]> git.neil.brown.name Git - history.git/commitdiff
Import 2.2.7pre4 2.2.7pre4
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:18:43 +0000 (15:18 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:18:43 +0000 (15:18 -0500)
197 files changed:
Documentation/scsi-generic.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/kernel/setup.c
arch/alpha/kernel/time.c
arch/alpha/lib/clear_user.S
arch/alpha/lib/copy_user.S
arch/alpha/lib/strlen_user.S
arch/alpha/lib/strncpy_from_user.S
arch/i386/config.in
arch/i386/kernel/bios32.c
arch/m68k/atari/atakeyb.c
arch/m68k/hp300/hil.c
arch/m68k/mac/mackeyb.c
drivers/Makefile
drivers/acorn/char/keyb_ps2.c
drivers/block/ide-cd.h
drivers/cdrom/optcd.c
drivers/char/Makefile
drivers/char/amikeyb.c
drivers/char/bttv.c
drivers/char/bttv.h
drivers/char/dn_keyb.c
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/n_tty.c
drivers/char/pc_keyb.c
drivers/char/radio-sf16fmi.c
drivers/char/radio-typhoon.c
drivers/char/softdog.c
drivers/macintosh/mac_keyb.c
drivers/net/3c523.c
drivers/net/ibmtr.c
drivers/net/irda/actisys.c
drivers/net/irda/esi.c
drivers/net/irda/girbil.c
drivers/net/irda/irport.c
drivers/net/irda/irtty.c
drivers/net/irda/pc87108.c
drivers/net/irda/tekram.c
drivers/net/irda/uircc.c
drivers/net/irda/w83977af_ir.c
drivers/net/net_init.c
drivers/net/pcnet32.c
drivers/net/rrunner.c
drivers/net/rrunner.h
drivers/net/z85230.c
drivers/sbus/char/pcikbd.c
drivers/usb/CREDITS [new file with mode: 0644]
drivers/usb/Config.in [new file with mode: 0644]
drivers/usb/Makefile [new file with mode: 0644]
drivers/usb/README.kbd [new file with mode: 0644]
drivers/usb/README.ohci [new file with mode: 0644]
drivers/usb/hub.c [new file with mode: 0644]
drivers/usb/hub.h [new file with mode: 0644]
drivers/usb/inits.h [new file with mode: 0644]
drivers/usb/keyboard.c [new file with mode: 0644]
drivers/usb/keymap.c [new file with mode: 0644]
drivers/usb/maps/fixup.map [new file with mode: 0644]
drivers/usb/maps/serial.map [new file with mode: 0644]
drivers/usb/maps/usb.map [new file with mode: 0644]
drivers/usb/mkmap [new file with mode: 0644]
drivers/usb/mouse.c [new file with mode: 0644]
drivers/usb/ohci-debug.c [new file with mode: 0644]
drivers/usb/ohci.c [new file with mode: 0644]
drivers/usb/ohci.h [new file with mode: 0644]
drivers/usb/restart [new file with mode: 0644]
drivers/usb/stopusb [new file with mode: 0644]
drivers/usb/uhci-debug.c [new file with mode: 0644]
drivers/usb/uhci.c [new file with mode: 0644]
drivers/usb/uhci.h [new file with mode: 0644]
drivers/usb/usb-debug.c [new file with mode: 0644]
drivers/usb/usb.c [new file with mode: 0644]
drivers/usb/usb.h [new file with mode: 0644]
fs/adfs/dir.c
fs/adfs/namei.c
fs/affs/dir.c
fs/affs/namei.c
fs/autofs/dir.c
fs/autofs/root.c
fs/buffer.c
fs/coda/dir.c
fs/dcache.c
fs/devpts/root.c
fs/ext2/dir.c
fs/ext2/namei.c
fs/fat/dir.c
fs/fat/inode.c
fs/hfs/dir_cap.c
fs/hfs/dir_dbl.c
fs/hfs/dir_nat.c
fs/hpfs/hpfs_fs.c
fs/inode.c
fs/isofs/dir.c
fs/isofs/namei.c
fs/minix/dir.c
fs/minix/inode.c
fs/minix/namei.c
fs/msdos/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/ntfs/fs.c
fs/ntfs/inode.c
fs/proc/fd.c
fs/proc/openpromfs.c
fs/proc/root.c
fs/qnx4/dir.c
fs/qnx4/namei.c
fs/romfs/inode.c
fs/smbfs/dir.c
fs/sysv/dir.c
fs/sysv/namei.c
fs/ufs/dir.c
fs/ufs/namei.c
fs/umsdos/dir.c
fs/umsdos/namei.c
fs/umsdos/rdir.c
fs/vfat/namei.c
include/asm-alpha/keyboard.h
include/asm-alpha/semaphore.h
include/asm-alpha/uaccess.h
include/asm-arm/arch-arc/keyboard.h
include/asm-arm/arch-ebsa285/keyboard.h
include/asm-arm/arch-rpc/keyboard.h
include/asm-arm/arch-vnc/keyboard.h
include/asm-i386/keyboard.h
include/asm-m68k/keyboard.h
include/asm-mips/keyboard.h
include/asm-ppc/keyboard.h
include/asm-sparc/keyboard.h
include/asm-sparc64/keyboard.h
include/linux/adfs_fs.h
include/linux/affs_fs.h
include/linux/ext2_fs.h
include/linux/fb.h
include/linux/fs.h
include/linux/irda.h [new file with mode: 0644]
include/linux/iso_fs.h
include/linux/kbd_ll.h
include/linux/minix_fs.h
include/linux/msdos_fs.h
include/linux/proc_fs.h
include/linux/qnx4_fs.h
include/linux/sysctl.h
include/linux/sysv_fs.h
include/linux/ufs_fs.h
include/linux/umsdos_fs.p
include/linux/wireless.h
include/net/irda/discovery.h
include/net/irda/ircomm_common.h
include/net/irda/irda.h
include/net/irda/irda_device.h
include/net/irda/iriap.h
include/net/irda/irkbd.h [deleted file]
include/net/irda/irlan_client.h
include/net/irda/irlan_common.h
include/net/irda/irlan_eth.h
include/net/irda/irlan_provider.h
include/net/irda/irlap.h
include/net/irda/irlap_frame.h
include/net/irda/irlmp.h
include/net/irda/irlpt_cli.h
include/net/irda/irmod.h
include/net/irda/irobex.h [deleted file]
include/net/irda/irttp.h
init/main.c
net/802/tr.c
net/irda/af_irda.c
net/irda/discovery.c
net/irda/ircomm/ircomm_common.c
net/irda/ircomm/irvtd_driver.c
net/irda/irda_device.c
net/irda/iriap.c
net/irda/irlan/irlan_client.c
net/irda/irlan/irlan_client_event.c
net/irda/irlan/irlan_common.c
net/irda/irlan/irlan_eth.c
net/irda/irlan/irlan_provider.c
net/irda/irlan/irlan_provider_event.c
net/irda/irlap.c
net/irda/irlap_event.c
net/irda/irlap_frame.c
net/irda/irlmp.c
net/irda/irlmp_event.c
net/irda/irlmp_frame.c
net/irda/irlpt/irlpt_cli.c
net/irda/irmod.c
net/irda/irsysctl.c
net/irda/irttp.c
net/irda/qos.c
net/irda/wrapper.c
net/netsyms.c
net/sched/sch_cbq.c
net/sched/sch_sfq.c

diff --git a/Documentation/scsi-generic.txt b/Documentation/scsi-generic.txt
new file mode 100644 (file)
index 0000000..17822c4
--- /dev/null
@@ -0,0 +1,636 @@
+            Notes on Linux's SG driver version 2.1.30
+            -----------------------------------------
+                                                        990328
+
+Introduction
+============
+These are notes on the Linux SCSI generic packet device driver (sg)
+describing version 2.1.30 . The original driver was written by Lawrence
+Foard and has remained in place with minimal changes since circa 1992.
+Version 2 of this driver remains backward compatible (binary and
+source **) with the original. It adds scatter gather, command queuing,
+per file descriptor sequencing, asynchronous notification and better
+error reporting.
+
+Sg is one of the four "high level" SCSI device drivers along with
+sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized
+(but lower level) than its sibling and tends to be used on SCSI devices
+that don't fit into the already serviced categories. Thus sg is used for
+scanners, cd writers and reading audio cds amongst other things.
+
+The interface and usage of the original sg driver has been documented
+by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
+of the document is version 1.5 dated 7th May 1996. It can found at
+ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO .
+Amongst other things it has a lot of tables from the SCSI-2 standard
+that are very useful for programming this interface.
+
+** It is possible to write applications that perform differently
+depending on whether they are using the original or this version of
+the sg device driver. The author is not aware of any useful applications
+that have problems with version 2 (yet).
+
+
+Architecture
+============
+The SCSI generic packet device driver (sg) is a character based device.
+It is one of the four high level device driver in the SCSI sub-system;
+the others are sd (for direct-access devices - disks), st (for tapes)
+and sr (for data cdroms). The other three devices are block devices.
+
+The unifying layer of the SCSI sub-system in the so-called mid-level.
+Below that are all the drivers for the various adapters supported by
+Linux.
+
+Since sg is a character device it supports the traditional Unix
+system calls of open(), close(), read(), write() and ioctl(). Two other
+related system calls: poll() and fcntl() are added to this list and
+how they interact with the sg device driver is documented later.
+An SG device is accessed by write()ing SCSI commands plus any associated 
+outgoing data to it; the resulting status codes and any incoming data are
+then obtained by a read() call. The device can be opened O_NONBLOCK
+(non-blocking) and poll() used to monitor its progress. The device may be
+opened O_EXCL which excludes other "sg" users from this device (but not 
+"sd", "st" or "sr" users). The buffer given to the write() call is made
+up as follows:
+        - struct sg_header image (see below)
+        - scsi command (6, 10 or 12 bytes long)
+        - data to be written to the device (if any)
+
+The buffer received from the corresponding read() call contains:
+        - struct sg_header image (check status/errors + sense_buffer)
+        - data read back from device (if any)
+
+The given SCSI command has its LUN field overwritten by the LUN value of
+the associated sg device that has been open()ed.
+
+
+sg_header
+=========
+This is the name of the control structure that conveys information
+about the length of data to be read/written by the associated SCSI
+command. It also conveys error and status information from the
+read() call. An instance of this structure is the first thing that
+is placed in the data buffers of both write() and read().
+
+In its original form it looked like this:
+struct sg_header {
+    int pack_len;
+    int reply_len;
+    int pack_id;
+    int result;
+    unsigned int twelve_byte:1;
+    unsigned int other_flags:31;
+    unsigned char sense_buffer[16];
+}; /* this structure is 36 bytes long */
+
+The 'pack_len' is bizzare and ends up having the 'reply_len' put in it
+(perhaps it had a use at some stage). 
+
+The 'reply_len' is the length of the data the corresponding read()
+will/should request (including the sg_header). 
+
+The 'pack_id' is not acted upon by the sg device driver but is conveyed
+back to the corresponding read() so it can be used for sequencing by an
+application. 
+
+The 'result' is also bizzare, turning certain types of host codes it 0 (no
+error), EBUSY or EIO. With better error reporting now available, the
+'result' is best ignored.
+
+The 'twelve_byte' field overrides the internal SCSI command length "guessing"
+algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
+a command lenth of 12 bytes.
+The command length "guessing" algorithm is as follows:
+Group:  0    1    2    3    4    5    6    7
+Length: 6   10   10   12   12   12   10   10
+
+'other_flags' was originally documented as "not used" but some current
+applications assume it has 0 placed in it.
+
+The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is
+returned when the target returns a SCSI status code of CHECK_CONDITION
+or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This
+buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
+this is unlikely to happen in the 2.2.x series of kernels.
+
+The new sg_header offered in this driver is:
+#define SG_MAX_SENSE 16
+struct sg_header
+{
+    int pack_len;    /* [o] reply_len (ie useless) ignored as input */
+    int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
+    int pack_id;     /* [io] id number of packet (use ints >= 0) */
+    int result;      /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */
+    unsigned int twelve_byte:1;
+        /* [i] Force 12 byte command length for group 6 & 7 commands  */
+    unsigned int target_status:5;   /* [o] scsi status from target */
+    unsigned int host_status:8;     /* [o] host status (see "DID" codes) */
+    unsigned int driver_status:8;   /* [o] driver status+suggestion */
+    unsigned int other_flags:10;    /* unused */
+    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is
+               CHECK_CONDITION or COMMAND_TERMINATED this is output. */
+};      /* This structure is 36 bytes long on i386 */
+
+Firstly the new header is binary compatible with the original. This is
+important for keeping existing apps working without recompilation.
+
+Only those elements (or fields) that are new or in some way different
+from the original are documented below.
+
+'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID,
+&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest
+waiting packet; any other value will cause the read() to wait (or yield
+EAGAIN) until a packet with that 'pack_id' becomes available. In all cases
+the value of 'pack_id' available after a read() is the value given to that
+variable in the prior, corresponding write().
+
+The 'target_status' field is always output and is the (masked and shifted
+1 bit right) SCSI status code from the target device. The allowable
+values are (found in <scsi/scsi.h>):
+/* N.B. 1 bit offset from usual SCSI status values */
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x01  
+#define CONDITION_GOOD       0x02
+#define BUSY                 0x04
+#define INTERMEDIATE_GOOD    0x08
+#define INTERMEDIATE_C_GOOD  0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define COMMAND_TERMINATED   0x11
+#define QUEUE_FULL           0x14
+When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
+'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
+is true then the 'sense_buffer' is also output (this seems to occur when
+the scsi ide emulation is used). When the 'sense_buffer' is output the 
+SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
+
+The 'host_status' field is always output and has the following values
+whose "defines" are not visible outside the kernel (unfortunately):
+#define DID_OK          0x00 /* NO error                                */
+#define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
+#define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
+#define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
+#define DID_BAD_TARGET  0x04 /* BAD target.                             */
+#define DID_ABORT       0x05 /* Told to abort for some other reason     */
+#define DID_PARITY      0x06 /* Parity error                            */
+#define DID_ERROR       0x07 /* Internal error                          */
+#define DID_RESET       0x08 /* Reset by somebody.                      */
+#define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */
+#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
+#define DID_SOFT_ERROR  0x0b /* The low level driver just wish a retry  */
+
+The 'driver_status' field is always output. When ('driver_status' &
+DRIVER_SENSE) is true the 'sense_buffer' is also output. The following
+values whose "defines" are not visible outside the kernel (unfortunately)
+can occur:
+#define DRIVER_OK           0x00 /* Typically no suggestion */
+#define DRIVER_BUSY         0x01
+#define DRIVER_SOFT         0x02
+#define DRIVER_MEDIA        0x03
+#define DRIVER_ERROR        0x04
+#define DRIVER_INVALID      0x05
+#define DRIVER_TIMEOUT      0x06
+#define DRIVER_HARD         0x07
+#define DRIVER_SENSE        0x08
+/* above status 'or'ed with one of the following suggestions */
+#define SUGGEST_RETRY       0x10
+#define SUGGEST_ABORT       0x20
+#define SUGGEST_REMAP       0x30
+#define SUGGEST_DIE         0x40
+#define SUGGEST_SENSE       0x80
+
+'other_flags' still remains as a 10 bit field, so code that places 0 in it
+will still be happy. It is not used.
+
+
+memory
+======
+Memory is a scarce resource in any computer. Sg needs to reserve memory
+suitable for DMA roughly equal in size to the maximum of the write and
+read data buffers for each packet. This DMA memory is obtained at the time
+of a write() and released when the corresponding read() is called (although
+if memory is tight it may be using the buffer reserved by the open() ).
+
+Linux obtaining memory a challenge for several reasons. The memory pool
+that sg uses is in common with all other device drivers and all user
+processes. In this environment the only way to 99.9% guarantee a driver
+will have memory in Linux is to build it into the kernel (ie not as a
+module) and then reserve it on initialization before user processes get
+a chance. [Of course, another driver initialized before sg could take
+all available memory ...] Another problem is the biggest contiguous
+chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE
+(which is 128KBytes on i386). As memory gets "splintered" there is a good
+chance that buffers won't be available (my machine has 64 MBytes of RAM
+and has 3 available at the moment).
+
+The original sg driver used the following technique: grab a SG_BIG_BUFF
+sized buffer at driver initialization and use it for all requests greater
+than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to
+32 KBytes in the origianl driver but many applications suggest that the
+user increases this number. Linux limits the biggest single buffer of
+this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the
+sg driver is a module then there is a high chance a contiguous block of
+that large size will not be available at module initialization.
+
+The author has found no "silver bullet" solution but uses multiple
+techniques hoping that at least one is able provide memory at the critical
+time. Listed below are some of these techniques:
+        - use scatter gather: then instead of one large buffer needing to
+          be found, multiple smaller buffer can be used
+        - use memory above the 16MByte level: the original driver limited
+          itself to obtaining memory below the 16MByte level (on the i386)
+          due to the shortcomings of DMA on ISA adapters. Yet more and more
+          people use PCI adapters that don't have this problem. So make
+          the decision based on the capabilities of the host adpater
+          associated with the current SCSI device
+        - reserve some memory at open() for emergencies but otherwise
+          fetch and release it on a per packet basis
+        - if the kernel is short of memory then dip into the SCSI DMA
+          pool (maintained by the mid-level driver) to a limited amount
+
+
+
+System Calls
+============
+What follows are descriptions of the characteristics of the standard
+Unix operating system calls when applied to a SCSI generic device
+using this version of the device driver.
+
+open
+----
+The filename should be an 'sg' device such as
+/dev/sg[a-z]
+/dev/sg[0,1,2,...]
+or a symbolic link to one of these. [Devfs has its own sub-directory for
+sg devices.] It seems as though SCSI devices are allocated to sg minor
+numbers in the same order as they appear in 'cat /proc/scsi/scsi'.
+Sg is a "character" based Linux device driver. This means it has an
+open/close/read/write/ioctl type interface.
+
+Flags can be either O_RDONLY or O_RDWR or-ed with either
+O_EXCL          waits for other opens on sg device to be closed before
+                proceeding. If O_NONBLOCK is set then yields EBUSY when
+                someone else has the sg device open. The combination of
+                O_RDONLY and O_EXCL is disallowed.
+O_NONBLOCK      Sets non-blocking mode. Calls that would otherwise block
+                yield EAGAIN (eg read() ) or EBUSY (eg open() ).
+
+The original version of sg did not allow the O_RDONLY (yielding a EACCES
+error). This version allows it for accessing ioctls (e.g. doing an sg
+device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
+allowed.
+
+By default, sequencing is per file descriptor in this version of sg. This
+means, for example that 2 processes can independently manipulate the same
+sg device at the same time. This may or may not make sense depending on
+the application: 2 processes (logically) reading from the same direct access
+device (ie a disk) is ok while running 2 instances of cd writing software
+on the same device at the same time probably wouldn't be a good idea. The
+previous version of sg supported only per device sequencing and this can
+still be selected with the SG_SET_MERGE_FD,1 ioctl().
+
+The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the
+current sg.h) on open() for "emergency" situations. If this is unavailable
+it will halve its request and try again. It gives up if PAGE_SIZE bytes
+(4096 bytes on i386) cannot be obtained so no memory is reserved. In this
+case open() will still return successfully. The actual amount of memory
+reserved can be found with the SG_GET_RESERVED_SIZE ioctl().
+
+Returns a file descriptor if >= 0 , otherwise -1 implies an error.
+
+Error codes (value in 'errno' after -1 returned):
+ENODEV          sg not compiled into kernel or the kernel cannot find the
+                sg module (or it can't initialize itself (low memory??))
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
+EBUSY           O_NONBLOCK set and some user of this sg device has O_EXCL
+                set while someone is already using this device
+EINTR           while waiting for an "exclusive" lock to clear, a signal
+                is received, just try again ...        
+ENOMEM          An attempt to get memory to store this open's context
+                failed (this was _not_ a request to reserve DMA memory)
+EACCES          An attempt to use both O_RDONLY and O_EXCL
+
+
+write
+-----
+Even though sg is a character-based device driver it sends and receives
+packets to/from the associated scsi device. Write() is used to send a
+packet containing 2 mandatory parts and 1 optional part. The mandatory
+parts are:
+  - a control block (an instance of struct sg_header)
+  - a SCSI command (6, 10 or 12 bytes long)
+The optional part is:
+  - outgoing data (eg if a SCSI write command is being sent)
+These should appear as one contiguous string in the buffer given to
+write() in the above order with no pad characters.
+
+If a write() accepts this packet then at some later time the user should
+call a read() to get the result of the SCSI command. The previous sg
+driver enforced a strict write()/read()/write()/read() regime so that a
+second write() would block until first read() was finished. This sg
+driver relaxes that condition and thereby allows command queuing
+(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor).
+However, for backward compatibility, command queuing is turned off
+by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed
+via the the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing
+the above define to 1].
+
+In this sg driver a write() should return more or less immediately.
+
+Returns number of bytes written if > 0 , otherwise -1 implies an error.
+
+Error codes (value in 'errno' after -1 returned):
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
+EACCES          opened with RD_ONLY flag
+EIO             incoming buffer too short. It should be at least (6 +
+                sizeof(struct sg_header))==42 bytes long
+EDOM            a) command queuing off: a packet is already queued
+                b) command queuing on: too many packets queued 
+                   (SG_MAX_QUEUE exceeded)
+EAGAIN          SCSI mid-level out of command blocks (rare), try again.
+                This is more likely to happen when queuing commands,
+                so wait a bit (eg usleep(10000) ) before trying again
+ENOMEM          can't get memory for DMA. Take evasive action ...
+                (see section on memory)
+
+
+read
+----
+Read() is used to receive a packet containing 1 mandatory part and 1 
+optional part. The mandatory part is:
+  - a control block (an instance of struct sg_header)
+The optional part is:
+  - incoming data (eg if a SCSI read command was sent by earlier write() )
+The buffer given to a read() and its corresponding count should be
+sufficient to accommodate this packet to avoid truncation. Truncation has
+occurred if count < sg_header::replylen .
+
+By default, read() will return the oldest packet queued up. If the 
+SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
+fetch the packet whose pack_id (given earlier to write()) matches the
+sg_header::pack_id given to this read(). If not available it will either
+wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
+to read() will match the oldest packet.
+
+
+Returns number of bytes read if > 0 , otherwise -1 implies an error.
+Unfortunately the return value in the non-error case is simply the
+same as the count argument. It is not the actual number of bytes
+DMA-ed by the SCSI device. This driver is currently unable to provide
+such an underrun indication.
+
+Error codes (value in 'errno' after -1 returned):
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
+EAGAIN          either no waiting packet or requested packet is not
+                available while O_NONBLOCK flag was set
+EINTR           while waiting for a packet, a signal is received, just
+                try again ...        
+EIO             if the 'count' given to read() is < sizeof(struct sg_header)
+                and the 'result' element in sg_header is non-zero. Not a
+                recommended error reporting technique
+
+
+close
+-----
+Preferably a close() should be done after all issued write()s have had
+their corresponding read() calls completed. Unfortunately this is not
+always possible. The semantics of close() in Unix are to return more
+or less immediately (ie not wait on any event) so the driver needs to
+arrange to an orderly cleanup of those packets that are still "in
+flight".
+
+A process that has an open file descriptor to an sg device may be aborted
+(eg by a kill signal). In this case, the kernel automatically calls close 
+(which is called 'sg_release()' in the version 2 driver) to facilitate
+the cleanup mentioned above.
+
+A problem persists in version 2.1.8 if the sg driver is a module and is
+removed while packets are still "in flight". Hopefully this will be soon
+fixed.
+
+Returns 0 if successful, otherwise -1 implies an error.
+
+Error codes (value in 'errno' after -1 returned):
+ENXIO           sg driver/module removed or corrupted
+
+ioctl (sg specific)
+-------------------
+Ken Thompson (or perhaps some other Unix luminary) described ioctl() as 
+the "garbage bin of Unix". This driver compounds the situation by adding
+around 18 more commands. These commands either yield state information (10
+of them), change the driver's characteristics (8 of them) or allow direct
+communication with the common SCSI mid-level driver.
+
+Those commands with an appended "+" are new in version 2.
+
+Those commands with an appended "W" are only accessible from file
+descriptors opened with O_RDWR. They will yield EACCES otherwise.
+
+SG_GET_TIMEOUT:
+Ignores its 3rd argument and _returns_ the timeout value (which will be
+>= 0 ). The unit of this timeout is "jiffies" which are currently 10
+millisecond intervals on i386 (less on an alpha). Linux supplies
+a manifest constant HZ which is the number of "jiffies" in 1 second.
+
+SG_SET_TIMEOUT:
+Assumes 3rd argument points to an int containing the new timeout value
+for this file descriptor. The unit is a "jiffy". Packets that are
+already "in flight" will not be effected. The default value is set
+on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h).
+
+SG_EMULATED_HOST:
+Assumes 3rd argument points to an int and outputs a flag indicating
+whether the host (adapter) is connected to a real SCSI bus or is
+emulated one (eg ide-scsi device driver). A value of 1 means emulated
+while 0 is not.
+
+SG_SET_FORCE_LOW_DMA +:
+Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
+means sg decides whether to use memory above 16 Mbyte level (on i386)
+based on the host adapter being used by this SCSI device. Typically
+PCI SCSI adapters will indicate they can DMA to the whole 32 bit address
+space. 
+If 1 is given then the host adapter is overridden and only memory below
+the 16MB level is used for DMA. A requirement for this should be
+extremely rare. If the "reserve" buffer allocated on open() is not in
+use then it will be de-allocated and re-allocated under the 16MB level
+(and the latter operation could fail yielding ENOMEM).
+Only the current file descriptor is effected.
+
+SG_GET_LOW_DMA +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0
+indicates the whole 32 bit address space is being used for DMA transfers
+on this file descriptor. 1 indicates the memory below the 16MB level
+(on i386) is being used (and this may be the case because the host
+adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
+
+SG_GET_SCSI_ID +:
+Assumes 3rd argument is pointing to an object of type Sg_scsi_id and
+populates it. That structure contains ints for host_no, channel,
+scsi_id, lun and scsi_type. Most of this information is available from
+other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER)
+but tends to be awkward to collect.
+
+SG_SET_FORCE_PACK_ID +:
+Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
+to return the oldest (written) packet if multiple packets are
+waiting to be read (when command queuing is being used). 
+1 instructs read() to view the sg_header::pack_id as input and return the
+oldest packet matching that pack_id or wait until it arrives (or yield
+EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
+given to read() in the mode will match the oldest packet.
+Only the current file descriptor is effected by this command.
+
+SG_GET_LOW_DMA +:
+Assumes 3rd argument points to an int and places the pack_id of the
+oldest (written) packet in it. If no packet is waiting to be read then
+yields -1.
+
+SG_GET_NUM_WAITING +:
+Assumes 3rd argument points to an int and places the number of packets
+waiting to be read in it.
+
+SG_GET_SG_TABLESIZE +:
+Assumes 3rd argument points to an int and places the maximum number of
+scatter gather elements supported by the host adapter. 0 indicates that
+the adapter does support scatter gather.
+
+SG_SET_RESERVED_SIZE +W:
+This is not currently implemented. It is intended for reserving either a
+large buffer or scatter gather list that will be available until the
+current file descriptor is closed. The requested amount of memory may
+not be available so SG_GET_RESERVED_SIZE should be used after this call
+to see how much was reserved. (EBUSY error possible)
+
+SG_GET_RESERVED_SIZE +:
+Assumes 3rd argument points to an int and places the size in bytes of
+the DMA buffer reserved on open() for emergencies. If this is 0 then it
+is probably not wise to attempt on operation like burning a CD on this
+file descriptor.
+
+SG_SET_MERGE_FD +W:
+Assumes 3rd argument is pointing to an int. 0 (the default) causes all
+subsequent sequencing to be per file descriptor. 1 causes all subsequent
+sequencing to be per device. If this command tries to change the current
+state and the is one or more _other_ file descriptors using this sg
+device then an EBUSY error occurs. Also if this file descriptor was not
+open()ed with the O_RDWR flag then an EACCES error occurs.
+Per device sequencing was the original semantics and allowed, for example
+different processes to "share" the device, one perhaps write()ing with
+the other one read()ing. This command is supplied if anyone needs those
+semantics. Per file descriptor sequencing, perhaps with the usage of
+the O_EXCL flag, seems more sensible.
+
+SG_GET_MERGE_FD +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+sequencing is per file descriptor. 1 implies sequencing is per device
+(original sg driver's semantics).
+
+SG_SET_COMMAND_Q +:
+Assumes 3rd argument is pointing to an int. 0 (current default, set by
+SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
+a packet while one is already queued will result in a EDOM error.
+1 turns command queuing on.
+Changing the queuing state only effects write()s done after the change.
+Only the current file descriptor is effected by this command.
+
+SG_GET_COMMAND_Q +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+that command queuing is off on this file descriptor. 1 implies command
+queuing is on.
+
+SG_SET_DEBUG +:
+Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
+off. Values > 0 cause the SCSI sense buffer to be decoded and output
+to the console/log when a SCSI device error occurs. Values > 8 cause
+the current sg device driver's state to be output to the console/log
+(this is a "one off" effect).
+If you need a _lot_ of the SCSI sub-system debug information (mainly from
+the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
+debug will appear in your console/log.
+
+ioctl (in common with sd, st + sr)
+----------------------------------
+The following ioctl()s can be called from any high-level scsi device
+driver (ie sd, st, sr + sg). Access permissions may differ a bit from
+one device to another, the access information given below is specific to
+the sg device driver.
+
+SCSI_IOCTL_GET_IDLUN:
+SCSI_IOCTL_GET_BUS_NUMBER:
+
+SCSI_IOCTL_SEND_COMMAND:  W
+If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
+the SCSI mid-level driver for processing.
+Don't know much about this one but it looks pretty powerful and
+dangerous. Some comments says it is also deprecated.
+
+<any_command_not matching_above>:  W
+If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
+the SCSI mid-level driver for processing.
+
+
+poll
+----
+This is a native call in Linux 2.2 but most of its capabilities are available
+through the older select() call. Given a choice poll() should probably be
+used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
+for polling; or alternatively with asynchronous notification using the
+fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
+Only if something drastically is wrong (eg file handle gone stale) will
+POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
+POLLIN is set when there is one or more packets waiting to be read.
+When POLLIN is set it implies that a read() will not block (or yield
+EAGAIN in non-blocking mode) but return a packet immediately.
+POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
+(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected
+by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
+set until the number of queued packets reaches SG_MAX_QUEUE, if the
+state is off then POLLOUT is only set when no packets are queued.
+Note that a packet can be queued after write()ing but not available to be
+read(); this typically happens when a SCSI read command is issued while
+the data is being retreaved.
+Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
+it is per device.
+
+
+fcntl
+-----
+There are several uses for this system call in association with a sg
+file descriptor. The first pseudo code shows code that is useful for
+scanning the sg devices, taking care not to be caught in a wait for
+an O_EXCL lock by another process, and when the appropriate device is
+found switching to normal blocked io. A working example of this logic
+is in the sg_scan.c utility program.
+
+open("/dev/sga", O_RDONLY | O_NONBLOCK)
+/* check device, EBUSY means some other process has O_EXCL lock on it */
+/* one the device you want is found then ... */
+flags = fcntl(sg_fd, F_GETFL)
+fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
+/* for simple apps is is easier to use normal blocked io */
+
+
+Some work has to be done in Linux to set up for asynchronous notification.
+This is a non-blocking mode of operation in which when the driver receives
+data back from a device so that a read() can be done, it sends a SIGPOLL
+(aka SIGIO) signal to the owning process. A working example of this logic
+is in the sg_poll.c test program.
+
+sigemptyset(&sig_set)
+sigaddset(&sig_set, SIGPOLL)
+sigaction(SIGPOLL, &s_action, 0)
+fcntl(sg_fd, F_SETOWN, getpid())
+flags = fcntl(sg_fd, F_GETFL);
+fcntl(sg_fd, F_SETFL, flags | O_ASYNC)
+
+
+Utility and Test Programs
+=========================
index bc38c72ff9067552412dc5199bc2b11f2dba9403..f852c910535c887839b325d84662975ce2281c70 100644 (file)
@@ -650,6 +650,11 @@ L: linux-scsi@vger.rutgers.edu
 W:     http://www.torque.net/sg
 S:     Maintained
 
+SCSI GENERIC
+L:     linux-scsi@vger.rutgers.edu
+M:     douglas.gilbert@rbcds.com
+S:     Maintained
+
 SCSI SUBSYSTEM
 L:     linux-scsi@vger.rutgers.edu
 S:     Unmaintained
@@ -771,7 +776,7 @@ M:  axboe@image.dk
 L:     linux-kernel@vger.rutgers.edu
 S:     Maintained
 
-USB HUB DRIVER
+USB HUB AND UHCI DRIVERS
 P:     Johannes Erdfelt
 M:     jerdfelt@sventech.com
 L:     linux-usb@peloncho.fis.ucm.es
@@ -798,9 +803,9 @@ M:  Alan.Cox@linux.org
 W:     http://roadrunner.swansea.linux.org.uk/v4l.shtml
 S:     Maintained
 
-WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP)
-P:     Gene Kozin
-M:     genek@compuserve.com
+WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
+P:     Jaspreet Singh
+M:     jaspreet@sangoma.com
 M:     dm@sangoma.com
 W:     http://www.sangoma.com
 S:     Supported
index 1a123ca5f2edbe4c181a8b7f01d794b0b1bb0116..47b243fffee138e9f430e54be36c30ddd962c25b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -175,7 +175,7 @@ DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.a
 endif
 
 ifeq ($(CONFIG_USB),y)
-DRIVERS := $(DRIVERS) drivers/uusbd/usb.a
+DRIVERS := $(DRIVERS) drivers/usb/usb.a
 endif
 
 ifeq ($(CONFIG_I2O),y)
index 42821d903ded22cb69f4ba3e50bc682acf2fffb9..80b4454e18206b91e51bab4002989d52236f8b0f 100644 (file)
@@ -183,6 +183,11 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p,
                        vec = get_sysvec_byname(p+9);
                        continue;
                }
+
+               if (strncmp(p, "cycle=", 6) == 0) {
+                       est_cycle_freq = simple_strtol(p+6, NULL, 0);
+                       continue;
+               }
        }
 
        /* Replace the command line, not that we've killed it with strtok.  */
@@ -721,8 +726,8 @@ int get_cpuinfo(char *buffer)
                       (char*)cpu->serial_no,
                       systype_name, sysvariation_name, hwrpb->sys_revision,
                       (char*)hwrpb->ssn,
-                      hwrpb->cycle_freq ? : est_cycle_freq,
-                      hwrpb->cycle_freq ? "" : "est.",
+                      est_cycle_freq ? : hwrpb->cycle_freq,
+                      est_cycle_freq ? "est." : "",
                       hwrpb->intr_freq / 4096,
                       (100 * hwrpb->intr_freq / 4096) % 100,
                       hwrpb->pagesize,
index 222b8f26fadd07fa1e6bfeee27b63a7e6cfd0cd9..a843789264726b6418efb08022c0410261581aa0 100644 (file)
@@ -226,7 +226,7 @@ time_init(void)
 {
        void (*irq_handler)(int, void *, struct pt_regs *);
        unsigned int year, mon, day, hour, min, sec, cc1, cc2;
-       unsigned long cycle_freq;
+       unsigned long cycle_freq, diff, one_percent;
 
        /*
         * The Linux interpretation of the CMOS clock register contents:
@@ -240,19 +240,30 @@ time_init(void)
        /* Read cycle counter exactly on falling edge of update flag */
        cc1 = rpcc();
 
-       /* If our cycle frequency isn't valid, go another round and give
-          a guess at what it should be.  */
-       cycle_freq = hwrpb->cycle_freq;
-       if (cycle_freq == 0) {
-               printk("HWRPB cycle frequency bogus.  Estimating... ");
-
+       if (!est_cycle_freq) {
+               /* Sometimes the hwrpb->cycle_freq value is bogus. 
+               Go another round to check up on it and see.  */
                do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
                do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
                cc2 = rpcc();
-               est_cycle_freq = cycle_freq = cc2 - cc1;
+               est_cycle_freq = cc2 - cc1;
                cc1 = cc2;
+       }
 
-               printk("%lu Hz\n", cycle_freq);
+       /* If the given value is within 1% of what we calculated, 
+          accept it.  Otherwise, use what we found.  */
+       cycle_freq = hwrpb->cycle_freq;
+       one_percent = cycle_freq / 100;
+       diff = cycle_freq - est_cycle_freq;
+       if (diff < 0)
+               diff = -diff;
+       if (diff > one_percent) {
+               cycle_freq = est_cycle_freq;
+               printk("HWRPB cycle frequency bogus.  Estimated %lu Hz\n",
+                      cycle_freq);
+       }
+       else {
+               est_cycle_freq = 0;
        }
 
        /* From John Bowman <bowman@math.ualberta.ca>: allow the values
index 65d7e2f282aaf842eeb3446a5b8b11a1e55be4f7..21d86eb78a112770bd2196b6828e522ed9675d88 100644 (file)
@@ -80,6 +80,7 @@ $tail:
        ret     $31, ($28), 1   # .. e1 :
 
 __do_clear_user:
+       ldgp    $29,0($27)      # we do exceptions -- we need the gp.
        and     $6, 7, $4       # e0    : find dest misalignment
        beq     $0, $zerolength # .. e1 :
        addq    $0, $4, $1      # e0    : bias counter
index aa309b9f5245e4b2524681f876f00696d7357018..da5d2795ad836c3c9a4b744f46b5ab703ebfc1f4 100644 (file)
@@ -46,6 +46,8 @@
        .globl __copy_user
        .ent __copy_user
 __copy_user:
+       ldgp $29,0($27)                 # we do exceptions -- we need the gp.
+       .prologue 1
        and $6,7,$3
        beq $0,$35
        beq $3,$36
index cdf71158f833dd04d3dbb262dc1ef61e788f73ad..1f4fb07f589a4fd906d9da611b12f32168b97173 100644 (file)
@@ -27,7 +27,8 @@
 
        .align 3
 __strlen_user:
-       .prologue 0
+       ldgp    $29,0($27)      # we do exceptions -- we need the gp.
+       .prologue 1
 
        EX( ldq_u t0, 0(a0) )   # load first quadword (a0 may be misaligned)
        lda     t1, -1(zero)
index aff7c1d2bf91db3c5855efc5f00c58498bacbdb3..998450196356169224085f67ad0ca219915ab2a1 100644 (file)
@@ -31,6 +31,7 @@
        .globl __strncpy_from_user
        .ent __strncpy_from_user
        .frame $30, 0, $26
+       .prologue 1
 
        .align 3
 $aligned:
@@ -99,6 +100,7 @@ $a_eoc:
        /*** The Function Entry Point ***/
        .align 3
 __strncpy_from_user:
+       ldgp    $29, 0($27)     # we do exceptions -- we need the gp.
 
        mov     a0, v0          # save the string start
        beq     a2, $zerolength
index 23a38e419efea4c972695c773ec43a7b2a5e93ca..65a3aee0a71c57c78ef3817536de7183145e5357 100644 (file)
@@ -168,6 +168,8 @@ endmenu
 
 source drivers/char/Config.in
 
+# source drivers/usb/Config.in
+
 source fs/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
index a7018a7e53359e48c580b8602d2ae14bc73ea692..91d338b2c2f4fe2143b65633f932347f67f47d95 100644 (file)
@@ -1095,6 +1095,8 @@ static void __init pcibios_scan_buglist(struct pci_bus *b)
  * for buggy PCI BIOS'es :-[).
  */
 
+extern int skip_ioapic_setup;
+
 static void __init pcibios_fixup_devices(void)
 {
        struct pci_dev *dev;
@@ -1147,6 +1149,7 @@ static void __init pcibios_fixup_devices(void)
                /*
                 * Recalculate IRQ numbers if we use the I/O APIC
                 */
+               if(!skip_ioapic_setup)
                {
                        int irq;
                        unsigned char pin;
index 79ef5f9fd4bf89fd501215e2512183c497f83971..6de1fd68662289d19692c6fa8116655d29f504aa 100644 (file)
@@ -291,7 +291,7 @@ static void atakeyb_rep( unsigned long ignore )
                atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
                add_timer( &atakeyb_rep_timer );
 
-               handle_scancode(rep_scancode);
+               handle_scancode(rep_scancode, 1);
        }
 
        atari_enable_irq( IRQ_MFP_ACIA );
@@ -448,7 +448,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
                    add_timer( &atakeyb_rep_timer );
                }
 
-               handle_scancode(break_flag | scancode);
+               handle_scancode(scancode, !break_flag);
                break;
            }
            break;
index 3be0d488a68bd0adf7067aab5abc6d0f230a994c..d7fe1867c04b358e22871c33310ca889a072e3ed 100644 (file)
@@ -223,12 +223,13 @@ static void poll_finished(void)
   {
   case 0x40:
     {
-      unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0);
+      int down = (poll.data[1] & 1) == 0;
+      unsigned char scode = poll.data[1] >> 1;
 #if 0
-      if (scode & 0x80)
-       printk("[%02x]", scode & 0x7f);
+      if (down)
+       printk("[%02x]", scode);
 #endif
-      handle_scancode(scode);
+      handle_scancode(scode, down);
     }
     break;
   }
index 5a6ae7c75af09ededcb4841fe175b1a0575d7c6d..a128a6314a99f9d3763b074de80623a59fdc8b72 100644 (file)
@@ -60,7 +60,7 @@ static void input_keycode(int, int);
 extern struct kbd_struct kbd_table[];
 
 extern void adb_bus_init(void);
-extern void handle_scancode(unsigned char);
+extern void handle_scancode(unsigned char, int);
 extern void put_queue(int);
 
 /* keyb */
@@ -387,7 +387,7 @@ input_keycode(int keycode, int repeat)
                 */
                switch (keycode) {
                case 0x39:
-                       handle_scancode(keycode);       /* down */
+                       handle_scancode(keycode, 1);    /* down */
                        up_flag = 0x80;                 /* see below ... */
                        mark_bh(KEYBOARD_BH);
                        break;
@@ -397,7 +397,7 @@ input_keycode(int keycode, int repeat)
                }
        }
 
-       handle_scancode(keycode + up_flag);
+       handle_scancode(keycode, !up_flag);
 }
 
 static void
index d83456c61aaa9b112da29058f0d7d10ff6facd1a..eef043f2855917b868f44fff0969f34910baf4c0 100644 (file)
@@ -10,7 +10,7 @@
 SUB_DIRS     := block char net misc sound
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \
-                                macintosh video dio zorro fc4
+                                macintosh video dio zorro fc4 usb
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -44,6 +44,11 @@ SUB_DIRS += macintosh
 MOD_SUB_DIRS += macintosh
 endif
 
+ifeq ($(CONFIG_USB),y)
+SUB_DIRS += usb
+MOD_SUB_DIRS += usb
+endif
+
 # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
 # but some of the low-level things may also be modules.
 ifeq ($(CONFIG_SCSI),y)
index c3ef33363a6bcd703234afb9bad043ee8fbc74db..4af051f444e5a86296f91ef02ee8afc4c1a8f0f3 100644 (file)
@@ -221,11 +221,6 @@ unsigned char ps2kbd_sysrq_xlate[] =
 };
 #endif
 
-int ps2kbd_pretranslate(unsigned char scancode)
-{
-       return 1;
-}
-
 int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p)
 {
        *uf_p = scancode & 0200;
@@ -235,7 +230,7 @@ int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_
 
 static void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
 {
-       handle_scancode(keycode + (up_flag ? 0x80 : 0));
+       handle_scancode(keycode, !up_flag);
 }
 
 static inline void ps2kbd_sendbyte(unsigned char val)
index 89fa51a83a6f95893c88c61659defc37d0782f23..28f4b9c74ba12bac3c931b31d19a4882693473e4 100644 (file)
@@ -334,13 +334,13 @@ struct atapi_capabilities_page {
 
 #if defined(__BIG_ENDIAN_BITFIELD)
        __u8 reserved3           : 2;
-       /* Drive can fake writes */
-       __u8 test_write          : 1;
-       __u8 reserved3a          : 1;
-       /* Drive can write DVD-R discs */
-       __u8 dvd_r_write         : 1;
        /* Drive can write DVD-RAM discs */
        __u8 dvd_ram_write       : 1;
+       /* Drive can write DVD-R discs */
+       __u8 dvd_r_write         : 1;
+       __u8 reserved3a          : 1;
+       /* Drive can fake writes */
+       __u8 test_write          : 1;
        /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
        __u8 cd_rw_write         : 1; /* reserved in 1.2 */
        /* Drive supports write to CD-R discs (orange book, part II) */
@@ -350,13 +350,13 @@ struct atapi_capabilities_page {
        __u8 cd_r_write          : 1; /* reserved in 1.2 */
        /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
        __u8 cd_rw_write         : 1; /* reserved in 1.2 */
-       /* Drive can write DVD-RAM discs */
-       __u8 dvd_ram_write       : 1;
-       /* Drive can write DVD-R discs */
-       __u8 dvd_r_write         : 1;
-       __u8 reserved3a          : 1;
        /* Drive can fake writes */
        __u8 test_write          : 1;
+       __u8 reserved3a          : 1;
+       /* Drive can write DVD-R discs */
+       __u8 dvd_r_write         : 1;
+       /* Drive can write DVD-RAM discs */
+       __u8 dvd_ram_write       : 1;
        __u8 reserved3           : 2;
 #else
 #error "Please fix <asm/byteorder.h>"
index 76103945be2e2ec047fa296a12507a2236837055..4406e17332766f8bbc17eb63ae393707c129c764 100644 (file)
@@ -100,6 +100,10 @@ static void debug(int debug_this, const char* fmt, ...)
 #else
 #define DEBUG(x)
 #endif
+
+static int blksize = 2048;
+static int hsecsize = 2048;
+
 \f
 /* Drive hardware/firmware characteristics
    Identifiers in accordance with Optics Storage documentation */
@@ -2061,6 +2065,8 @@ __initfunc(int optcd_init(void))
                return -EIO;
        }
 
+       hardsect_size[MAJOR_NR] = &hsecsize;
+       blksize_size[MAJOR_NR] = &blksize;
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
        read_ahead[MAJOR_NR] = 4;
        request_region(optcd_port, 4, "optcd");
index d623c4ec8c307b3784d76a139ce34be46c66b989..dfe297b6592ade7e1d0e008670605d591a3f65f9 100644 (file)
@@ -42,14 +42,15 @@ endif
 
 ifndef CONFIG_SUN_KEYBOARD
 ifdef CONFIG_VT
-L_OBJS += keyboard.o
+LX_OBJS += keyboard.o
 endif
  ifneq ($(ARCH),m68k)
    L_OBJS += pc_keyb.o defkeymap.o
  endif
 else
 ifdef CONFIG_PCI
-L_OBJS += defkeymap.o keyboard.o
+L_OBJS += defkeymap.o
+LX_OBJS += keyboard.o
 endif
 endif
 
index 164fc5df50174e11763493188a7cc49894856a68..8c8c58388d32dff81ccad71220109df87897f6b6 100644 (file)
@@ -188,7 +188,7 @@ static void amikeyb_rep(unsigned long ignore)
     amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
     amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
     add_timer(&amikeyb_rep_timer);
-    handle_scancode(rep_scancode);
+    handle_scancode(rep_scancode, 1);
 
     restore_flags(flags);
 }
@@ -243,8 +243,8 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
 
     if (keycode == AMIKEY_CAPS) {
        /* if the key is CAPS, fake a press/release. */
-       handle_scancode(AMIKEY_CAPS);
-       handle_scancode(BREAK_MASK | AMIKEY_CAPS);
+       handle_scancode(AMIKEY_CAPS, 1);
+       handle_scancode(AMIKEY_CAPS, 0);
     } else if (keycode < 0x78) {
        /* handle repeat */
        if (break_flag) {
@@ -257,7 +257,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
            amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
            add_timer(&amikeyb_rep_timer);
        }
-       handle_scancode(scancode);
+       handle_scancode(scancode, !break_flag);
     } else
        switch (keycode) {
            case 0x78:
index 5ce2fa70fb13573657a0538e89de8d93ad33ddd1..12ac86673fce14e62833f0bb75fc39c284f23601 100644 (file)
@@ -2853,6 +2853,16 @@ static void handle_chipset(void)
 }
 #endif
 
+static void init_tea6300(struct i2c_bus *bus) 
+{
+        I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB  */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB         */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB       */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off        */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */
+}
+
 static void init_tda8425(struct i2c_bus *bus) 
 {
         I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
@@ -2978,6 +2988,14 @@ static void idcard(int i)
                         break;
         }
         
+        if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
+        {
+               printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
+               btv->audio_chip = TEA6300;
+               init_tea6300(&(btv->i2c));
+        } else
+               printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr);
+
        printk(KERN_INFO "bttv%d: model: ",btv->nr);
 
        sprintf(btv->video_dev.name,"BT%d",btv->id);
index 59776cc20a80dc10693b55f70c4f8cac6ddf49f4..479384783b486cea00dd9891a68388614761ca70 100644 (file)
@@ -114,6 +114,7 @@ struct bttv
        int type;            /* card type  */
        int audio;           /* audio mode */
        int audio_chip;
+       int fader_chip;
        int radio;
 
        u32 *risc_jmp;
@@ -222,6 +223,7 @@ struct bttv
 #define TDA9850            0x01
 #define TDA8425            0x02
 #define TDA9840            0x03
+#define TEA6300            0x04
 
 #define I2C_TSA5522        0xc2
 #define I2C_TDA9840       0x84
@@ -230,6 +232,7 @@ struct bttv
 #define I2C_HAUPEE         0xa0
 #define I2C_STBEE          0xae
 #define I2C_VHX           0xc0
+#define I2C_TEA6300        0x80
 
 #define TDA9840_SW        0x00
 #define TDA9840_LVADJ     0x02
@@ -249,6 +252,12 @@ struct bttv
 #define TDA8425_BA         0x02
 #define TDA8425_TR         0x03
 #define TDA8425_S1         0x08
+
+#define TEA6300_VL         0x00                /* volume control left */
+#define TEA6300_VR         0x01                /* volume control right */
+#define TEA6300_BA         0x02                /* bass control */
+#define TEA6300_TR         0x03                /* treble control */
+#define TEA6300_FA         0x04                /* fader control */
+#define TEA6300_SW         0x05                /* mute and source switch */
 
 #endif
index 02436b8f2c5b44fe0cdbb66b492639f21cc0eb8e..304feb0e8cf740faecf249d2807c866e666415e1 100644 (file)
@@ -414,9 +414,9 @@ static void dn_keyb_process_key_event(unsigned char scancode) {
        }
        else if((scancode & (~BREAK_FLAG)) == DNKEY_CAPS) {
        /* printk("handle_scancode: %02x\n",DNKEY_CAPS); */
-               handle_scancode(DNKEY_CAPS);
+               handle_scancode(DNKEY_CAPS, 1);
                /*    printk("handle_scancode: %02x\n",BREAK_FLAG | DNKEY_CAPS); */
-               handle_scancode(BREAK_FLAG | DNKEY_CAPS);
+               handle_scancode(DNKEY_CAPS, 0);
        }
        else if( (scancode == DNKEY_REPEAT) && (prev_scancode < 0x7e) &&
                        !(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
@@ -424,13 +424,13 @@ static void dn_keyb_process_key_event(unsigned char scancode) {
                        prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
                        if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) {
                        /*      printk("handle_scancode: %02x\n",prev_scancode); */
-                               handle_scancode(prev_scancode);
+                               handle_scancode(prev_scancode, 1);
                                }
                                lastscancode=prev_scancode;
                        }
        else {
        /*      printk("handle_scancode: %02x\n",scancode);  */
-                       handle_scancode(scancode);
+                       handle_scancode(scancode & ~BREAK_FLAG, !(scancode & BREAK_FLAG));
                        lastkeypress=jiffies;
        }
 }
index fa7040e36b2d8c3eeed52f9f63869e3f6791154d..607f4b664f51622c033259482075f396d46598e8 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -59,6 +60,8 @@
 #define KBD_DEFLOCK 0
 #endif
 
+EXPORT_SYMBOL(handle_scancode);
+
 extern void ctrl_alt_del(void);
 
 struct wait_queue * keypress_wait = NULL;
@@ -190,15 +193,15 @@ int getkeycode(unsigned int scancode)
     return kbd_getkeycode(scancode);
 }
 
-void handle_scancode(unsigned char scancode)
+void handle_scancode(unsigned char scancode, int down)
 {
        unsigned char keycode;
-       char up_flag;                            /* 0 or 0200 */
+       char up_flag = down ? 0 : 0200;
        char raw_mode;
 
        do_poke_blanked_console = 1;
        mark_bh(CONSOLE_BH);
-       add_keyboard_randomness(scancode);
+       add_keyboard_randomness(scancode | up_flag);
 
        tty = ttytab? ttytab[fg_console]: NULL;
        if (tty && (!tty->driver_data)) {
@@ -213,20 +216,15 @@ void handle_scancode(unsigned char scancode)
        }
        kbd = kbd_table + fg_console;
        if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
-               put_queue(scancode);
+               put_queue(scancode | up_flag);
                /* we do not return yet, because we want to maintain
                   the key_down array, so that we have the correct
                   values when finishing RAW mode or when changing VT's */
-       }
+       }
 
-       if (!kbd_pretranslate(scancode, raw_mode))
-           return;
-       /*
+       /*
         *  Convert scancode to keycode
-        */
-       up_flag = (scancode & 0200);
-       scancode &= 0x7f;
-
+        */
        if (!kbd_translate(scancode, &keycode, raw_mode))
            return;
 
@@ -239,10 +237,10 @@ void handle_scancode(unsigned char scancode)
 
        if (up_flag) {
                rep = 0;
-               if(!test_and_clear_bit(keycode, key_down))
+               if(!test_and_clear_bit(keycode, key_down))
                    up_flag = kbd_unexpected_up(keycode);
        } else
-               rep = test_and_set_bit(keycode, key_down);
+               rep = test_and_set_bit(keycode, key_down);
 
 #ifdef CONFIG_MAGIC_SYSRQ              /* Handle the SysRq Hack */
        if (keycode == SYSRQ_KEY) {
@@ -257,11 +255,11 @@ void handle_scancode(unsigned char scancode)
 
        if (kbd->kbdmode == VC_MEDIUMRAW) {
                /* soon keycodes will require more than one byte */
-               put_queue(keycode + up_flag);
+               put_queue(keycode + up_flag);
                raw_mode = 1;   /* Most key classes will be ignored */
-       }
+       }
 
-       /*
+       /*
         * Small change in philosophy: earlier we defined repetition by
         *       rep = keycode == prev_keycode;
         *       prev_keycode = keycode;
@@ -270,9 +268,9 @@ void handle_scancode(unsigned char scancode)
         */
 
        /*
-        *  Repeat a key only if the input buffers are empty or the
-        *  characters get echoed locally. This makes key repeat usable
-        *  with slow applications and under heavy loads.
+        *  Repeat a key only if the input buffers are empty or the
+        *  characters get echoed locally. This makes key repeat usable
+        *  with slow applications and under heavy loads.
         */
        if (!rep ||
            (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
index 5f14bde50dd71e53c9a12f30e77a8b43009a2ff2..51ab86d8f00a9598dac244cd25c7b79e8024e0ae 100644 (file)
@@ -51,6 +51,12 @@ extern void mda_console_init(void);
 #if defined(CONFIG_PPC) || defined(CONFIG_MAC)
 extern void adbdev_init(void);
 #endif
+#ifdef CONFIG_USB_UHCI
+int uhci_init(void);
+#endif
+#ifdef CONFIG_USB_OHCI
+int ohci_init(void);
+#endif
 
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
                            const char * buf, size_t count, loff_t *ppos)
@@ -599,6 +605,12 @@ __initfunc(int chr_dev_init(void))
        if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
                printk("unable to get major %d for memory devs\n", MEM_MAJOR);
        rand_initialize();
+#ifdef CONFIG_USB_UHCI
+       uhci_init();
+#endif
+#ifdef CONFIG_USB_OHCI
+       ohci_init();
+#endif
 #if defined (CONFIG_FB)
        fbmem_init();
 #endif
index 4bf35716bf261026ee952199e32b32d6976bc911..1c6f93f44817388e81810aff89b3d564aea6dc76 100644 (file)
@@ -922,8 +922,14 @@ do_it_again:
                }
        }
 
-       if (down_interruptible(&tty->atomic_read))
-               return -ERESTARTSYS;
+       if (file->f_flags & O_NONBLOCK) {
+               if (down_trylock(&tty->atomic_read))
+                       return -EAGAIN;
+       }
+       else {
+               if (down_interruptible(&tty->atomic_read))
+                       return -ERESTARTSYS;
+       }
 
        add_wait_queue(&tty->read_wait, &wait);
        set_bit(TTY_DONT_FLIP, &tty->flags);
index b1793daf089034bdb2d89540f0c1a1cafda06e71..62f0c57bb99e86886a80b4ab4ffefef84ab43492 100644 (file)
@@ -240,8 +240,6 @@ static unsigned char e0_keys[128] = {
   0, 0, 0, 0, 0, 0, 0, 0                             /* 0x78-0x7f */
 };
 
-static unsigned int prev_scancode = 0;   /* remember E0, E1 */
-
 int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
        if (scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -284,41 +282,28 @@ static int do_acknowledge(unsigned char scancode)
                       scancode);
 #endif
        }
-       if (scancode == 0) {
-#ifdef KBD_REPORT_ERR
-               printk(KERN_INFO "Keyboard buffer overflow\n");
-#endif
-               prev_scancode = 0;
-               return 0;
-       }
        return 1;
 }
 
-int pckbd_pretranslate(unsigned char scancode, char raw_mode)
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+                   char raw_mode)
 {
-       if (scancode == 0xff) {
-               /* in scancode mode 1, my ESC key generates 0xff */
-               /* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
-               if (!raw_mode)
-                 printk(KERN_DEBUG "Keyboard error\n");
-#endif
-#endif
-               prev_scancode = 0;
-               return 0;
-       }
+       static int prev_scancode = 0;
 
+       /* special prefix scancodes.. */
        if (scancode == 0xe0 || scancode == 0xe1) {
                prev_scancode = scancode;
                return 0;
-       }
-       return 1;
-}
+       }
+
+       /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
+       if (scancode == 0x00 || scancode == 0xff) {
+               prev_scancode = 0;
+               return 0;
+       }
+
+       scancode &= 0x7f;
 
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-                   char raw_mode)
-{
        if (prev_scancode) {
          /*
           * usually it will be 0xe0, but a Pause key generates
@@ -452,7 +437,7 @@ static unsigned char handle_kbd_event(void)
                        handle_mouse_event(scancode);
                } else {
                        if (do_acknowledge(scancode))
-                               handle_scancode(scancode);
+                               handle_scancode(scancode, !(scancode & 0x80));
                        mark_bh(KEYBOARD_BH);
                }
 
index 58f9918d1c0a977fa90f06929112e62f60820857..53333f082de8457cfb8464ed86bf1e1d3746ff29 100644 (file)
@@ -4,6 +4,7 @@
  * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
  *
  * Fitted to new interface by Alan Cox <alan.cox@linux.org>
+ * Made working and cleaned up functions <mikael.hedin@irf.se>
  *
  * Notes on the hardware
  *
@@ -74,9 +75,10 @@ static inline void fmi_unmute(int port)
        outb(0x08, port);
 }
 
-static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
+static inline int fmi_setfreq(struct fmi_device *dev)
 {
         int myport = dev->port;
+       unsigned long freq = dev->curfreq;
        int i;
        
        outbits(16, RSF16_ENCODE(freq), myport);
@@ -158,7 +160,6 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.flags=fmi->flags;
                        v.mode=VIDEO_MODE_AUTO;
                        v.signal = fmi_getsigstr(fmi);
-                       strcpy(v.name, "FM");
                        if(copy_to_user(arg,&v, sizeof(v)))
                                return -EFAULT;
                        return 0;
@@ -192,8 +193,10 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                                tmp *= 1000;
                        if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
                          return -EINVAL;
-                       fmi->curfreq = tmp;
-                       fmi_setfreq(fmi, fmi->curfreq);
+                       /*rounding in steps of 800 to match th freq
+                         that will be used */
+                       fmi->curfreq = (tmp/800)*800; 
+                       fmi_setfreq(fmi);
                        return 0;
                }
                case VIDIOCGAUDIO:
@@ -205,7 +208,7 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.treble=0;
                        v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
                        strcpy(v.name, "Radio");
-                       v.mode=VIDEO_SOUND_MONO;
+                       v.mode=VIDEO_SOUND_STEREO;
                        v.balance=0;
                        v.step=0; /* No volume, just (un)mute */
                        if(copy_to_user(arg,&v, sizeof(v)))
index 3282ea67a8bac962481628e2623a41fefd5bd994..60e357a9b294f017b0aaac766e4f3eb24ddfa862 100644 (file)
@@ -196,7 +196,7 @@ static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.flags = VIDEO_TUNER_LOW;
                        v.mode = VIDEO_MODE_AUTO;
                        v.signal = 0xFFFF;      /* We can't get the signal strength */
-                       strcpy(v.tuner, "FM");
+                       strcpy(v.name, "FM");
                        if (copy_to_user(arg, &v, sizeof(v)))
                                return -EFAULT;
                        return 0;
index dc14c0e17a070fb5104028710cdd5db311689b75..9dc9cbfe4d60028e985962a34966b5e592e14e6f 100644 (file)
@@ -132,7 +132,6 @@ static ssize_t softdog_write(struct file *file, const char *data, size_t len, lo
 static int softdog_ioctl(struct inode *inode, struct file *file,
        unsigned int cmd, unsigned long arg)
 {
-       int i;
        static struct watchdog_info ident=
        {
                0,
index dbe7e4eb0fdf2551e4287e5821825b61800dc240..5d6ee7bbe8d7c3293f3042f079fcb1263c8ddc36 100644 (file)
@@ -194,7 +194,7 @@ extern int console_loglevel;
 extern struct kbd_struct kbd_table[];
 extern struct wait_queue * keypress_wait;
 
-extern void handle_scancode(unsigned char);
+extern void handle_scancode(unsigned char, int);
 
 static struct adb_ids keyboard_ids;
 static struct adb_ids mouse_ids;
@@ -234,11 +234,6 @@ int mackbd_getkeycode(unsigned int scancode)
        return -EINVAL;
 }
 
-int mackbd_pretranslate(unsigned char scancode, char raw_mode)
-{
-       return 1;
-}
-
 int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
                     char raw_mode)
 {
@@ -338,8 +333,8 @@ input_keycode(int keycode, int repeat)
                 switch (keycode) {
                 /*case 0xb9:*/
                 case 0x39:
-                       handle_scancode(0x39);
-                       handle_scancode(0xb9);
+                       handle_scancode(0x39, 1);
+                       handle_scancode(0x39, 0);
                        mark_bh(KEYBOARD_BH);
                        return;
                 case 0x47:
@@ -349,7 +344,7 @@ input_keycode(int keycode, int repeat)
                 }
        }
 
-       handle_scancode(keycode + up_flag);
+       handle_scancode(keycode, !up_flag);
 }
 
 static void
index d907fe7f3720422166144d3ecc4e23d85386bd1f..25daedb2dcbe83b30cfaa23a5f5db92542489100 100644 (file)
@@ -62,8 +62,8 @@
    search the MCA slots until it finds a 3c523 with the specified
    parameters.
 
-   This driver should support multiple ethernet cards, but I can't test
-   that.  If someone would I'd greatly appreciate it.
+   This driver does support multiple ethernet cards when used as a module
+   (up to MAX_3C523_CARDS, the default being 4)
 
    This has been tested with both BNC and TP versions, internal and
    external transceivers.  Haven't tested with the 64K version (that I
    update to 1.3.59, incorporated multicast diffs from ni52.c
    Feb 15th, 1996
    added shared irq support
-
+   Apr 1999
+   added support for multiple cards when used as a module
+   added option to disable multicast as is causes problems
+       Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
+       Stuart Adamson <stuart.adamson@compsoc.net>
+       
    $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
  */
 
 /*************************************************************************/
 #define DEBUG                  /* debug on */
 #define SYSBUSVAL 0            /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */
+#undef ELMC_MULTICAST          /* Disable multicast support as it is somewhat seriously broken at the moment */
 
 #define make32(ptr16) (p->memtop + (short) (ptr16) )
 #define make24(ptr32) ((char *) (ptr32) - p->base)
@@ -180,7 +186,9 @@ static int elmc_open(struct device *dev);
 static int elmc_close(struct device *dev);
 static int elmc_send_packet(struct sk_buff *, struct device *);
 static struct net_device_stats *elmc_get_stats(struct device *dev);
+#ifdef ELMC_MULTICAST
 static void set_multicast_list(struct device *dev);
+#endif
 
 /* helper-functions */
 static int init586(struct device *dev);
@@ -432,21 +440,19 @@ __initfunc(int elmc_probe(struct device *dev))
        while (slot != -1) {
                status = mca_read_stored_pos(slot, 2);
 
+               dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
+               dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
+               
                /*
                   If we're trying to match a specified irq or IO address,
                   we'll reject a match unless it's what we're looking for.
+                  Also reject it if the card is already in use.
                 */
-               if (base_addr || irq) {
-                       /* we're looking for a card at a particular place */
 
-                       if (irq && irq != irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]) {
-                               slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
-                               continue;
-                       }
-                       if (base_addr && base_addr != csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]) {
-                               slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
-                               continue;
-                       }
+               if((irq && irq != dev->irq) || (base_addr && base_addr != dev->base_addr)
+                  || check_region(dev->base_addr,ELMC_IO_EXTENT)) {
+                       slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+                       continue;
                }
                /* found what we're looking for... */
                break;
@@ -476,9 +482,6 @@ __initfunc(int elmc_probe(struct device *dev))
        /* revision is stored in the first 4 bits of the revision register */
        revision = inb(dev->base_addr + ELMC_REVISION) & 0xf;
 
-       /* figure out our irq */
-       dev->irq = irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
-
        /* according to docs, we read the interrupt and write it back to
           the IRQ select register, since the POST might not configure the IRQ
           properly. */
@@ -497,9 +500,6 @@ __initfunc(int elmc_probe(struct device *dev))
                break;
        }
 
-       /* Our IO address? */
-       dev->base_addr = csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
-
        request_region(dev->base_addr, ELMC_IO_EXTENT, "3c523");
 
        dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL);
@@ -565,7 +565,11 @@ __initfunc(int elmc_probe(struct device *dev))
        dev->stop = &elmc_close;
        dev->get_stats = &elmc_get_stats;
        dev->hard_start_xmit = &elmc_send_packet;
+#ifdef ELMC_MULTICAST
        dev->set_multicast_list = &set_multicast_list;
+#else
+       dev->set_multicast_list = NULL;
+#endif
 
        ether_setup(dev);
 
@@ -577,6 +581,10 @@ __initfunc(int elmc_probe(struct device *dev))
           That gets done in elmc_open().  I'm not sure that's such a good idea,
           but it works, so I'll go with it. */
 
+#ifndef ELMC_MULTICAST
+        dev->flags&=~IFF_MULTICAST;     /* Multicast doesn't work */
+#endif
+
        return 0;
 }
 
@@ -1210,6 +1218,7 @@ static struct net_device_stats *elmc_get_stats(struct device *dev)
  * Set MC list ..
  */
 
+#ifdef ELMC_MULTICAST
 static void set_multicast_list(struct device *dev)
 {
        if (!dev->start) {
@@ -1222,60 +1231,85 @@ static void set_multicast_list(struct device *dev)
        startrecv586(dev);
        dev->start = 1;
 }
+#endif
 
 /*************************************************************************/
 
 #ifdef MODULE
 
-static char devicename[9] = {0,};
+/* Increase if needed ;) */
+#define MAX_3C523_CARDS 4
+/* I'm not sure where this magic 9 comes from */
+#define NAMELEN 9
 
-static struct device dev_elmc =
-{
-       devicename /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, elmc_probe
+static char devicenames[NAMELEN * MAX_3C523_CARDS] = {0,};
+
+static struct device dev_elmc[MAX_3C523_CARDS] =
+{      
+       {
+       NULL /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL
+       },
 };
 
-static int irq = 0;
-static int io = 0;
-MODULE_PARM(irq, "i");
-MODULE_PARM(io, "i");
+static int irq[MAX_3C523_CARDS] = {0,};
+static int io[MAX_3C523_CARDS] = {0,};
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
 
 int init_module(void)
 {
-       struct device *dev = &dev_elmc;
-
-       dev->base_addr = io;
-       dev->irq = irq;
-       if (register_netdev(dev) != 0) {
-               return -EIO;
+       int this_dev,found = 0;
+
+       /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */        
+       for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) 
+               {
+               struct device *dev = &dev_elmc[this_dev];
+               dev->name=devicenames+(NAMELEN*this_dev);
+               dev->irq=irq[this_dev];
+               dev->base_addr=io[this_dev];
+               dev->init=elmc_probe;
+               if(register_netdev(dev)!=0) {
+                       if(io[this_dev]==0) break;
+                       printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
+               } else found++;
        }
-       return 0;
+
+       if(found==0) {
+               if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n");
+               return -ENXIO;
+       } else return 0;
 }
 
 void cleanup_module(void)
 {
-       struct device *dev = &dev_elmc;
-
-       /* shutdown interrupts on the card */
-       elmc_id_reset586();
-       if (dev->irq != 0) {
-               /* this should be done by close, but if we failed to
-                  initialize properly something may have gotten hosed. */
-               free_irq(dev->irq, dev);
-               dev->irq = 0;
-       }
-       if (dev->base_addr != 0) {
-               release_region(dev->base_addr, ELMC_IO_EXTENT);
-               dev->base_addr = 0;
-       }
-       irq = 0;
-       io = 0;
-       unregister_netdev(dev);
+       int this_dev;
+       for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
+
+               struct device *dev = &dev_elmc[this_dev];
+               if(dev->priv) {
+                       /* shutdown interrupts on the card */
+                       elmc_id_reset586();
+                       if (dev->irq != 0) {
+                               /* this should be done by close, but if we failed to
+                                  initialize properly something may have gotten hosed. */
+                               free_irq(dev->irq, dev);
+                               dev->irq = 0;
+                       }
+                       if (dev->base_addr != 0) {
+                               release_region(dev->base_addr, ELMC_IO_EXTENT);
+                               dev->base_addr = 0;
+                       }
+                       irq[this_dev] = 0;
+                       io[this_dev] = 0;
+                       unregister_netdev(dev);
 
-       mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot,
+                       mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot,
                               NULL, NULL);
 
-       kfree_s(dev->priv, sizeof(struct priv));
-       dev->priv = NULL;
+                       kfree_s(dev->priv, sizeof(struct priv));
+                       dev->priv = NULL;
+               }
+       }
 }
 
 #endif                         /* MODULE */
index 6df5b821aa331a4bfbc5738bbc4b8cbfac2256db..9d63a442d2d8c7e618e0c35bbe9a99c7556bc4cc 100644 (file)
  *      Changes by Joel Sloan (jjs@c-me.com) :
  *      + disable verbose debug messages by default - to enable verbose
  *       debugging, edit the IBMTR_DEBUG_MESSAGES define below 
+ *     
+ *     Changes by Mike Phillips <phillim@amtrak.com> :
+ *     + Added extra #ifdef's to work with new PCMCIA Token Ring Code.
+ *       The PCMCIA code now just sets up the card so it can be recognized
+ *        by ibmtr_probe. Also checks allocated memory vs. on-board memory
+ *       for correct figure to use.
  *
  *     Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) :
  *     + added spinlocks for SMP sanity (10 March 1999)
@@ -94,6 +100,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
 #undef NO_AUTODETECT
 #undef ENABLE_PAGING
 
+
 #define FALSE 0
 #define TRUE (!FALSE)
 
@@ -191,6 +198,9 @@ unsigned char ibmtr_debug_trace=0;
 int            ibmtr_probe(struct device *dev);
 static int     ibmtr_probe1(struct device *dev, int ioaddr);
 static unsigned char   get_sram_size(struct tok_info *adapt_info);
+#ifdef PCMCIA
+extern unsigned char   pcmcia_reality_check(unsigned char gss);
+#endif
 static int     tok_init_card(struct device *dev);
 void           tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int     trdev_init(struct device *dev);
@@ -256,7 +266,9 @@ __initfunc(int ibmtr_probe(struct device *dev))
                if (ibmtr_probe1(dev, base_addr)) 
                {
 #ifndef MODULE
+#ifndef PCMCIA
                       tr_freedev(dev);
+#endif
 #endif
                       return -ENODEV;
                } else
@@ -272,7 +284,9 @@ __initfunc(int ibmtr_probe(struct device *dev))
                        continue;
                 if (ibmtr_probe1(dev, ioaddr)) {
 #ifndef MODULE
+#ifndef PCMCIA
                        tr_freedev(dev);
+#endif
 #endif
                } else
                        return 0;
@@ -291,7 +305,9 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
        unsigned long timeout;
 
 #ifndef MODULE
+#ifndef PCMCIA
        dev = init_trdev(dev,0);
+#endif
 #endif
 
        /*      Query the adapter PIO base port which will return
@@ -300,7 +316,7 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
         */
 
                segment = inb(PIOaddr);
-       
+
        /*
         *      Out of range values so we'll assume non-existent IO device 
         */
@@ -373,12 +389,19 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
        }
 
        /* Now, allocate some of the pl0 buffers for this driver.. */
+
+       /* If called from PCMCIA, ti is already set up, so no need to 
+          waste the memory, just use the existing structure */
+
+#ifndef PCMCIA
        ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
        if (ti == NULL) 
                return -ENOMEM;
 
        memset(ti, 0, sizeof(struct tok_info));
-
+#else
+       ti = dev->priv ; 
+#endif
        ti->mmio= t_mmio;
        ti->readlog_pending = 0;
 
@@ -388,6 +411,10 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
                          should fit with out future hope of multiple
                          adapter support as well /dwm   */
 
+       /* if PCMCIA, then the card is recognized as TR_ISAPNP 
+        * and there is no need to set up the interrupt, it is already done. */
+        
+#ifndef PCMCIA
        switch (cardpresent) 
        {
                case TR_ISA:
@@ -428,7 +455,6 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
                                irq=10;
                        if (intr==3)
                                irq=11;
-
                        timeout = jiffies + TR_SPIN_INTERVAL;
                        while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN))
                                if (time_after(jiffies, timeout)) {
@@ -436,11 +462,13 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
                                        kfree_s(ti, sizeof(struct tok_info));
                                        return -ENODEV;
                                }
+
                        ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
                        ti->global_int_enable=PIOaddr+ADAPTINTREL;
                        ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
                        break;
        }
+#endif
 
        if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
                DPRINTK("irq=%d",irq);
@@ -483,8 +511,11 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
        ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
 
        /* How much shared RAM is on adapter ? */
+#ifdef PCMCIA
+       ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
+#else
        ti->avail_shared_ram = get_sram_size(ti);
-
+#endif
        /* We need to set or do a bunch of work here based on previous results.. */
        /* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
        ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
@@ -593,7 +624,6 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
                }
 #endif
        }
-
        /* finish figuring the shared RAM address */
        if (cardpresent==TR_ISA) {
                static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000};
@@ -619,15 +649,20 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr))
        DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2);
 #endif
 
+       /* The PCMCIA has already got the interrupt line and the io port, 
+          so no chance of anybody else getting it - MLP */
+
+#ifndef PCMCIA
        if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) {
                DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",irq);
                kfree_s(ti, sizeof(struct tok_info));
                return -ENODEV;
        }
+       /*?? Now, allocate some of the PIO PORTs for this driver.. */
+       request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range as busy */
+#endif
 
- /*?? Now, allocate some of the PIO PORTs for this driver.. */
-       request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range
-                                                                 as busy */
 #if !TR_NEWFORMAT
        DPRINTK("%s",version); /* As we have passed card identification,
                                   let the world know we're here! */
@@ -717,7 +752,6 @@ __initfunc(static unsigned char get_sram_size(struct tok_info *adapt_info))
 
        unsigned char avail_sram_code;
        static unsigned char size_code[]={ 0,16,32,64,127,128 };
-
        /* Adapter gives
           'F' -- use RRR bits 3,2
           'E' -- 8kb   'D' -- 16kb
@@ -747,7 +781,9 @@ __initfunc(static int trdev_init(struct device *dev))
        dev->change_mtu         = ibmtr_change_mtu;
 
 #ifndef MODULE
+#ifndef PCMCIA
        tr_setup(dev);
+#endif
 #endif
        return 0;
 }
@@ -842,7 +878,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs)
                          DPRINTK("PCMCIA card removed.\n");
                          spin_unlock(&(ti->lock));
                          dev->interrupt = 0;
-                         return;
+                         return;
                        }
 
                /* Check ISRP EVEN too. */
@@ -1186,7 +1222,6 @@ static void initial_tok_int(struct device *dev)
        __u32 encoded_addr;
        __u32 hw_encoded_addr;
        struct tok_info *ti;
-
        ti=(struct tok_info *) dev->priv;
 
        ti->do_tok_int=NOT_FIRST;
index 513b9ba30bd676593413e6b2cd98a8ee2e764f61..46ce2badfb85d66119ce98b04386141683913097 100644 (file)
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Tue Feb  9 15:38:16 1999
+ * Modified at:   Mon Apr 12 11:56:35 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -234,8 +234,8 @@ static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos)
        /* Remove support for 38400 if this is not a 220L+ dongle */
        if ( idev->io.dongle_id == ACTISYS_DONGLE)
                qos->baud_rate.bits &= ~IR_38400;
-               
-       qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */
+       
+       qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
 }
 
 #ifdef MODULE
index 8bdf796ef730ff9162400599ef13cb34196550cb..5395d2829688943e9797fe29c3092d69e83b8c85 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Tue Feb  9 15:36:47 1999
+ * Modified at:   Mon Apr 12 11:55:30 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:      esi.c
  *
@@ -56,9 +56,9 @@ static struct dongle dongle = {
        esi_qos_init,
 };
 
-__initfunc(void esi_init(void))
+__initfunc(int esi_init(void))
 {
-       irtty_register_dongle( &dongle);
+       return irtty_register_dongle(&dongle);
 }
 
 void esi_cleanup(void)
@@ -132,7 +132,7 @@ static void esi_change_speed( struct irda_device *idev, int baud)
        }
        /* Change speed of serial driver */
        tty->termios->c_cflag = cflag;
-       tty->driver.set_termios( tty, &old_termios);
+       tty->driver.set_termios(tty, &old_termios);
 
        irtty_set_dtr_rts(tty, dtr, rts);
 }
@@ -151,6 +151,7 @@ static void esi_reset( struct irda_device *idev, int unused)
 static void esi_qos_init( struct irda_device *idev, struct qos_info *qos)
 {
        qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
+       qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
 }
 
 #ifdef MODULE
@@ -163,8 +164,7 @@ static void esi_qos_init( struct irda_device *idev, struct qos_info *qos)
  */
 int init_module(void)
 {
-       esi_init();
-       return(0);
+       return esi_init();
 }
 
 /*
index f74186b6ae4c6ba4bfced87459e95d72f7d94365..128b32a23e22d209800394063c55cb60f9423fcb 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb  6 21:02:33 1999
- * Modified at:   Tue Feb  9 15:36:36 1999
+ * Modified at:   Sat Apr 10 19:53:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -195,7 +195,7 @@ void girbil_reset(struct irda_device *idev, int unused)
 {
        struct irtty_cb *self;
        struct tty_struct *tty;
-       __u8 control = GIRBIL_TXEN | GIRBIL_RXEN /* | GIRBIL_ECAN */;
+       __u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
index 6f23506528e58794390b6a924ab17fc9b2db6c64..5ea6dba738a0c0cdbef075191914c9cf5ad4d456 100644 (file)
@@ -1,7 +1,7 @@
 /*********************************************************************
  *               
  * Filename:     irport.c
- * Version:      0.8
+ * Version:      0.9
  * Description:   Serial driver for IrDA. 
  * Status:       Experimental.
  * Author:       Dag Brattli <dagb@cs.uit.no>
@@ -9,7 +9,6 @@
  * Modified at:   Sat May 23 23:15:20 1998
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:      serial.c by Linus Torvalds 
- *               serial_serial.c by Aage Kvalnes <aage@cs.uit.no>
  * 
  *     Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
  *
  *     NOTICE:
  *
- *     This driver is ment to be a small serial driver to be used for
- *     IR-chipsets that has a UART (16550) compatibility mode. If your
- *     chipset is is UART only, you should probably use IrTTY instead since
- *     the Linux serial driver is probably more robust and optimized.
+ *     This driver is ment to be a small half duplex serial driver to be
+ *     used for IR-chipsets that has a UART (16550) compatibility mode. If
+ *     your chipset is is UART only, you should probably use IrTTY instead
+ *     since the Linux serial driver is probably more robust and optimized.
  *
  *     The functions in this file may be used by FIR drivers, but this
  *     driver knows nothing about FIR drivers so don't ever insert such
@@ -64,7 +63,6 @@
 #include <net/irda/irport.h>
 
 #define IO_EXTENT 8
-#define CONFIG_HALF_DUPLEX
 
 /* static unsigned int io[]  = { 0x3e8, ~0, ~0, ~0 }; */
 /* static unsigned int irq[] = { 11, 0, 0, 0 }; */
@@ -114,7 +112,7 @@ static void irport_cleanup(void)
  *    Start IO port 
  *
  */
-int irport_open( int iobase)
+int irport_open(int iobase)
 {
        DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
 
@@ -134,7 +132,7 @@ int irport_open( int iobase)
  *    Stop IO port
  *
  */
-void irport_close( int iobase) 
+void irport_close(int iobase) 
 {
        DEBUG(4, __FUNCTION__ "()\n");
 
@@ -142,7 +140,7 @@ void irport_close( int iobase)
        outb(0, iobase+UART_MCR);
 
        /* Turn off interrupts */
-       outb(0, iobase+UART_IER); 
+       outb(0, iobase+UART_IER);
 }
 
 /*
@@ -186,16 +184,22 @@ void irport_change_speed( int iobase, int speed)
  *    more packets to send, we send them here.
  *
  */
-static void irport_write_wakeup( struct irda_device *idev)
+static void irport_write_wakeup(struct irda_device *idev)
 {
-       int actual = 0, count;
+       int actual = 0;
        int iobase;
 
        ASSERT(idev != NULL, return;);
        ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
        /* Finished with frame?  */
-       if (idev->tx_buff.offset == idev->tx_buff.len)  {
+       if (idev->tx_buff.len > 0)  {
+               /* Write data left in transmit buffer */
+               actual = irport_write(idev->io.iobase2, idev->io.fifo_size, 
+                                     idev->tx_buff.data, idev->tx_buff.len);
+               idev->tx_buff.data += actual;
+               idev->tx_buff.len  -= actual;
+       } else {
                iobase = idev->io.iobase2;
                /* 
                 *  Now serial buffer is almost free & we can start 
@@ -206,23 +210,14 @@ static void irport_write_wakeup( struct irda_device *idev)
 
                /* Schedule network layer, so we can get some more frames */
                mark_bh(NET_BH);
-#ifdef CONFIG_HALF_DUPLEX
+
                outb(UART_FCR_ENABLE_FIFO | 
                     UART_FCR_TRIGGER_14  |
                     UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */
 
                /* Turn on receive interrupts */
                outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); 
-#endif
-               return;
        }
-
-       /* Write data left in transmit buffer */
-       count = idev->tx_buff.len - idev->tx_buff.offset;
-       actual = irport_write(idev->io.iobase2, idev->io.fifo_size, 
-                             idev->tx_buff.head, count);
-       idev->tx_buff.offset += actual;
-       idev->tx_buff.head += actual;
 }
 
 /*
@@ -283,22 +278,19 @@ int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
        if (irda_lock((void *) &dev->tbusy) == FALSE)
                return -EBUSY;
        
-        /*  
-        *  Transfer skb to tx_buff while wrapping, stuffing and making CRC 
-        */
+       /* Init tx buffer */
+       idev->tx_buff.data = idev->tx_buff.head;
+
+        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
        idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
                                           idev->tx_buff.truesize);
        
-/*     actual = irport_write(idev->io.iobase2, idev->io.fifo_size,  */
-/*                           idev->tx_buff.data, idev->tx_buff.len); */
-       
-       idev->tx_buff.offset = actual;
-       idev->tx_buff.head = idev->tx_buff.data + actual;
+       idev->tx_buff.data += actual;
+       idev->tx_buff.len  -= actual;
 
-#ifdef CONFIG_HALF_DUPLEX
        /* Turn on transmit finished interrupt. Will fire immediately!  */
        outb(UART_IER_THRI, iobase+UART_IER); 
-#endif
+
        dev_kfree_skb(skb);
        
        return 0;
@@ -318,44 +310,37 @@ static void irport_receive(struct irda_device *idev)
        if (!idev)
                return;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        iobase = idev->io.iobase2;
 
-       if (idev->rx_buff.len == 0)
-               idev->rx_buff.head = idev->rx_buff.data;
-       
        /*  
         * Receive all characters in Rx FIFO, unwrap and unstuff them. 
          * async_unwrap_char will deliver all found frames  
         */
        do {
-               async_unwrap_char(idev, inb( iobase+UART_RX));
+               async_unwrap_char(idev, inb(iobase+UART_RX));
 
                /* Make sure we don't stay here to long */
                if (boguscount++ > 32) {
                        DEBUG(0,__FUNCTION__ "(), breaking!\n");
                        break;
                }
-
        } while (inb(iobase+UART_LSR) & UART_LSR_DR);   
 }
 
 /*
  * Function irport_interrupt (irq, dev_id, regs)
  *
- *    
+ *    Interrupt handler
  */
 void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
 {
        struct irda_device *idev = (struct irda_device *) dev_id;
-
        int iobase;
        int iir, lsr;
        int boguscount = 0;
 
-       DEBUG(5, __FUNCTION__ "(), irq %d\n", irq);
-       
        if (!idev) {
                printk(KERN_WARNING __FUNCTION__ 
                       "() irq %d for unknown device.\n", irq);
@@ -368,19 +353,13 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
        iir = inb(iobase + UART_IIR) & UART_IIR_ID;
        while (iir) {
-               DEBUG(4,__FUNCTION__ "(), iir=%#x\n", iir);
-
                /* Clear interrupt */
                lsr = inb(iobase+UART_LSR);
 
                if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) {
                        /* Transmitter ready for data */
                        irport_write_wakeup(idev);
-               }
-#ifdef CONFIG_HALF_DUPLEX
-               else 
-#endif
-               if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
+               } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
                        /* Receive interrupt */
                        irport_receive(idev);
                }
@@ -394,7 +373,6 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        idev->netdev.interrupt = 0;
 }
 
-
 #ifdef MODULE
 
 /*
index 8ea10d9a8f21b79085cbc9cdf351b5577b21f65d..cc7ab91a4c498c5016ac2accec3c6acd02774e3b 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Tue Apr  6 21:35:25 1999
+ * Modified at:   Thu Apr 22 09:20:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -45,22 +45,22 @@ static hashbin_t *dongles = NULL;
 
 static struct tty_ldisc irda_ldisc;
 
-static int irtty_hard_xmit( struct sk_buff *skb, struct device *dev);
-static void irtty_wait_until_sent( struct irda_device *driver);
-static int irtty_is_receiving( struct irda_device *idev);
-static int irtty_net_init( struct device *dev);
+static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev);
+static void irtty_wait_until_sent(struct irda_device *driver);
+static int irtty_is_receiving(struct irda_device *idev);
+static int irtty_net_init(struct device *dev);
 static int irtty_net_open(struct device *dev);
 static int irtty_net_close(struct device *dev);
 
-static int  irtty_open( struct tty_struct *tty);
-static void irtty_close( struct tty_struct *tty);
-static int  irtty_ioctl( struct tty_struct *, void *, int, void *);
-static int  irtty_receive_room( struct tty_struct *tty);
-static void irtty_change_speed( struct irda_device *dev, int baud);
-static void irtty_write_wakeup( struct tty_struct *tty);
+static int  irtty_open(struct tty_struct *tty);
+static void irtty_close(struct tty_struct *tty);
+static int  irtty_ioctl(struct tty_struct *, void *, int, void *);
+static int  irtty_receive_room(struct tty_struct *tty);
+static void irtty_change_speed(struct irda_device *dev, int baud);
+static void irtty_write_wakeup(struct tty_struct *tty);
 
-static void irtty_receive_buf( struct tty_struct *, const unsigned char *, 
-                              char *, int);
+static void irtty_receive_buf(struct tty_struct *, const unsigned char *, 
+                             char *, int);
 char *driver_name = "irtty";
 
 __initfunc(int irtty_init(void))
@@ -73,15 +73,15 @@ __initfunc(int irtty_init(void))
                return -ENOMEM;
        }
 
-       dongles = hashbin_new( HB_LOCAL);
-       if ( dongles == NULL) {
-               printk( KERN_WARNING 
-                       "IrDA: Can't allocate dongles hashbin!\n");
+       dongles = hashbin_new(HB_LOCAL);
+       if (dongles == NULL) {
+               printk(KERN_WARNING 
+                      "IrDA: Can't allocate dongles hashbin!\n");
                return -ENOMEM;
        }
 
        /* Fill in our line protocol discipline, and register it */
-       memset( &irda_ldisc, 0, sizeof( irda_ldisc));
+       memset(&irda_ldisc, 0, sizeof( irda_ldisc));
 
        irda_ldisc.magic = TTY_LDISC_MAGIC;
        irda_ldisc.name  = "irda";
@@ -97,10 +97,10 @@ __initfunc(int irtty_init(void))
        irda_ldisc.receive_room = irtty_receive_room;
        irda_ldisc.write_wakeup = irtty_write_wakeup;
        
-       if (( status = tty_register_ldisc( N_IRDA, &irda_ldisc)) != 0)  {
-               printk( KERN_ERR 
-                       "IrDA: can't register line discipline (err = %d)\n", 
-                       status);
+       if (( status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)  {
+               printk(KERN_ERR 
+                      "IrDA: can't register line discipline (err = %d)\n", 
+                      status);
        }
        
        return status;
@@ -120,10 +120,10 @@ static void irtty_cleanup(void)
        /*
         *  Unregister tty line-discipline
         */
-       if (( ret = tty_register_ldisc( N_IRDA, NULL))) {
-               printk( KERN_ERR 
-                       "IrTTY: can't unregister line discipline (err = %d)\n",
-                       ret);
+       if ((ret = tty_register_ldisc(N_IRDA, NULL))) {
+               ERROR(__FUNCTION__ 
+                     "(), can't unregister line discipline (err = %d)\n",
+                     ret);
        }
 
        /*
@@ -131,8 +131,8 @@ static void irtty_cleanup(void)
         *  callback to irtty_close(), therefore we do give any deallocation
         *  function to hashbin_destroy().
         */
-       hashbin_delete( irtty, NULL);
-       hashbin_delete( dongles, NULL);
+       hashbin_delete(irtty, NULL);
+       hashbin_delete(dongles, NULL);
 }
 #endif /* MODULE */
 
@@ -143,47 +143,45 @@ static void irtty_cleanup(void)
  *    discipline is called for.  Because we are sure the tty line exists,
  *    we only have to link it to a free IrDA channel.  
  */
-static int irtty_open( struct tty_struct *tty) 
+static int irtty_open(struct tty_struct *tty) 
 {
        struct irtty_cb *self;
        char name[16];
        
-       ASSERT( tty != NULL, return -EEXIST;);
+       ASSERT(tty != NULL, return -EEXIST;);
 
        /* First make sure we're not already connected. */
        self = (struct irtty_cb *) tty->disc_data;
-       if ( self != NULL && self->magic == IRTTY_MAGIC)
+       if (self != NULL && self->magic == IRTTY_MAGIC)
                return -EEXIST;
        
        /*
         *  Allocate new instance of the driver
         */
-       self = kmalloc( sizeof(struct irtty_cb), GFP_KERNEL);
-       if ( self == NULL) {
-               printk( KERN_ERR "IrDA: Can't allocate memory for "
-                       "IrDA control block!\n");
+       self = kmalloc(sizeof(struct irtty_cb), GFP_KERNEL);
+       if (self == NULL) {
+               printk(KERN_ERR "IrDA: Can't allocate memory for "
+                      "IrDA control block!\n");
                return -ENOMEM;
        }
-       memset( self, 0, sizeof(struct irtty_cb));
+       memset(self, 0, sizeof(struct irtty_cb));
        
        self->tty = tty;
        tty->disc_data = self;
 
        /* Give self a name */
-       sprintf( name, "%s%d", tty->driver.name,
-                MINOR(tty->device) - tty->driver.minor_start +
-                tty->driver.name_base);
-
+       sprintf(name, "%s%d", tty->driver.name,
+               MINOR(tty->device) - tty->driver.minor_start +
+               tty->driver.name_base);
+       
        /* hashbin_insert( irtty, (QUEUE*) self, 0, self->name); */
-       hashbin_insert( irtty, (QUEUE*) self, (int) self, NULL);
+       hashbin_insert(irtty, (QUEUE*) self, (int) self, NULL);
 
-       if (tty->driver.flush_buffer) {
+       if (tty->driver.flush_buffer)
                tty->driver.flush_buffer(tty);
-       }
-
-       if (tty->ldisc.flush_buffer) {
+       
+       if (tty->ldisc.flush_buffer)
                tty->ldisc.flush_buffer(tty);
-       }
        
        self->magic = IRTTY_MAGIC;
 
@@ -198,12 +196,12 @@ static int irtty_open( struct tty_struct *tty)
         *  that are not device dependent (such as link disconnect time) so
         *  this parameter can be set by IrLAP (or the user) instead. DB
         */
-       irda_init_max_qos_capabilies( &self->idev.qos);
+       irda_init_max_qos_capabilies(&self->idev.qos);
 
        /* The only value we must override it the baudrate */
        self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
                IR_115200;
-       self->idev.qos.min_turn_time.bits = 0x03;
+       self->idev.qos.min_turn_time.bits = 0x0f;
        self->idev.flags = IFF_SIR | IFF_PIO;
        irda_qos_bits_to_value(&self->idev.qos);
 
@@ -236,7 +234,7 @@ static int irtty_open( struct tty_struct *tty)
 }
 
 /* 
- *  Function irtty_close ( tty)
+ *  Function irtty_close (tty)
  *
  *    Close down a IrDA channel. This means flushing out any pending queues,
  *    and then restoring the TTY line discipline to what it was before it got
@@ -272,14 +270,40 @@ static void irtty_close(struct tty_struct *tty)
        MOD_DEC_USE_COUNT;
 }
 
+/*
+ * Function irtty_stop_receiver (irda_device, stop)
+ *
+ *    
+ *
+ */
+static void irtty_stop_receiver(struct irda_device *idev, int stop)
+{
+       struct termios old_termios;
+       struct irtty_cb *self;
+       int cflag;
+
+       self = (struct irtty_cb *) idev->priv;
+
+       old_termios = *(self->tty->termios);
+       cflag = self->tty->termios->c_cflag;
+       
+       if (stop)
+               cflag &= ~CREAD;
+       else
+               cflag |= CREAD;
+
+       self->tty->termios->c_cflag = cflag;
+       self->tty->driver.set_termios(self->tty, &old_termios);
+}
+
 /* 
- *  Function irtty_change_speed ( self, baud)
+ *  Function irtty_change_speed (self, baud)
  *
  *    Change the speed of the serial port. The driver layer must check that
  *    all transmission has finished using the irtty_wait_until_sent() 
  *    function.
  */
-static void irtty_change_speed( struct irda_device *idev, int baud) 
+static void irtty_change_speed(struct irda_device *idev, int baud) 
 {
         struct termios old_termios;
        struct irtty_cb *self;
@@ -287,22 +311,22 @@ static void irtty_change_speed( struct irda_device *idev, int baud)
 
        DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); 
 
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
        self = (struct irtty_cb *) idev->priv;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
 
        old_termios = *(self->tty->termios);
        cflag = self->tty->termios->c_cflag;
 
        cflag &= ~CBAUD;
 
-       DEBUG( 4, __FUNCTION__ "(), Setting speed to %d\n", baud);
+       DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", baud);
 
-       switchbaud) {
+       switch (baud) {
        case 1200:
                cflag |= B1200;
                break;
@@ -331,7 +355,7 @@ static void irtty_change_speed( struct irda_device *idev, int baud)
        }       
 
        self->tty->termios->c_cflag = cflag;
-       self->tty->driver.set_termios( self->tty, &old_termios);
+       self->tty->driver.set_termios(self->tty, &old_termios);
 }
 
 /*
@@ -340,43 +364,42 @@ static void irtty_change_speed( struct irda_device *idev, int baud)
  *    Initialize attached dongle. Warning, must be called with a process
  *    context!
  */
-static void irtty_init_dongle( struct irtty_cb *self, int type)
+static void irtty_init_dongle(struct irtty_cb *self, int type)
 {
        struct dongle_q *node;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
 
 #ifdef CONFIG_KMOD
        /* Try to load the module needed */
        switch( type) {
        case ESI_DONGLE:
-               DEBUG( 0, __FUNCTION__ "(), ESI dongle!\n");
-               request_module( "esi");
+               MESSAGE("IrDA: Trying to initialize ESI dongle!\n");
+               request_module("esi");
                break;
        case TEKRAM_DONGLE:
-               DEBUG( 0, __FUNCTION__ "(), Tekram dongle!\n");
-               request_module( "tekram");
+               MESSAGE("IrDA: Trying to initialize Tekram dongle!\n");
+               request_module("tekram");
                break;
        case ACTISYS_DONGLE:     /* FALLTHROUGH */
        case ACTISYS_PLUS_DONGLE:
-               DEBUG( 0, __FUNCTION__ "(), ACTiSYS dongle!\n");
-               request_module( "actisys");
+               MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n");
+               request_module("actisys");
                break;
        case GIRBIL_DONGLE:
-               DEBUG( 0, __FUNCTION__ "(), GIrBIL dongle!\n");
-               request_module( "girbil");
+               MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n");
+               request_module("girbil");
                break;
        default:
-               DEBUG( 0, __FUNCTION__ "(), Unknown dongle type!\n");
+               ERROR("Unknown dongle type!\n");
                return;
-               break;
        }
 #endif /* CONFIG_KMOD */
 
-       node = hashbin_find( dongles, type, NULL);
+       node = hashbin_find(dongles, type, NULL);
        if ( !node) {
-               DEBUG(0, __FUNCTION__ "(), Unable to find requested dongle\n");
+               ERROR("Unable to find requested dongle\n");
                return;
        }
        self->dongle_q = node;
@@ -387,14 +410,14 @@ static void irtty_init_dongle( struct irtty_cb *self, int type)
        /*
         * Now initialize the dongle!
         */
-       node->dongle->open( &self->idev, type);
-       node->dongle->qos_init( &self->idev, &self->idev.qos);
+       node->dongle->open(&self->idev, type);
+       node->dongle->qos_init(&self->idev, &self->idev.qos);
        
        /* Reset dongle */
-       node->dongle->reset( &self->idev, 0);
+       node->dongle->reset(&self->idev, 0);
 
        /* Set to default baudrate */
-       node->dongle->change_speed( &self->idev, 9600);
+       node->dongle->change_speed(&self->idev, 9600);
 }
 
 /*
@@ -411,25 +434,25 @@ static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
 
        self = (struct irtty_cb *) tty->disc_data;
 
-       ASSERT( self != NULL, return -ENODEV;);
-       ASSERT( self->magic == IRTTY_MAGIC, return -EBADR;);
+       ASSERT(self != NULL, return -ENODEV;);
+       ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;);
 
-       if ( _IOC_DIR(cmd) & _IOC_READ)
+       if (_IOC_DIR(cmd) & _IOC_READ)
                err = verify_area( VERIFY_WRITE, (void *) arg, size);
-       else if ( _IOC_DIR(cmd) & _IOC_WRITE)
+       else if (_IOC_DIR(cmd) & _IOC_WRITE)
                err = verify_area( VERIFY_READ, (void *) arg, size);
-       if ( err)
+       if (err)
                return err;
        
        switch(cmd) {
        case TCGETS:
        case TCGETA:
-               return n_tty_ioctl( tty, (struct file *) file, cmd, 
-                                   (unsigned long) arg);
+               return n_tty_ioctl(tty, (struct file *) file, cmd, 
+                                  (unsigned long) arg);
                break;
        case IRTTY_IOCTDONGLE:
                /* Initialize dongle */
-               irtty_init_dongle( self, (int) arg);
+               irtty_init_dongle(self, (int) arg);
                break;
        default:
                return -ENOIOCTLCMD;
@@ -450,8 +473,8 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 {
        struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
        
        /* Read the characters out of the buffer */
        while (count--) {
@@ -461,19 +484,19 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                if (fp && *fp++) { 
                        DEBUG( 0, "Framing or parity error!\n");
                        irda_device_set_media_busy( &self->idev, TRUE);
-                       /* sl->rx_errors++; */
+
                        cp++;
                        continue;
                }
                /* Unwrap and destuff one byte */
-               async_unwrap_char( &self->idev, *cp++);
+               async_unwrap_char(&self->idev, *cp++);
        }
 }
 
 /*
  * Function irtty_hard_xmit (skb, dev)
  *
- *    Transmit skb
+ *    Transmit frame
  *
  */
 static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
@@ -482,9 +505,6 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
        struct irda_device *idev;
        int actual = 0;
 
-       ASSERT( dev != NULL, return 0;);
-       ASSERT( skb != NULL, return 0;);
-
        idev = (struct irda_device *) dev->priv;
 
        ASSERT(idev != NULL, return 0;);
@@ -498,10 +518,11 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
        /* Lock transmit buffer */
        if (irda_lock((void *) &dev->tbusy) == FALSE)
                return -EBUSY;
-
-        /*  
-        *  Transfer skb to tx_buff while wrapping, stuffing and making CRC 
-        */
+       
+       /* Init tx buffer*/
+       idev->tx_buff.data = idev->tx_buff.head;
+       
+        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
         idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
                                           idev->tx_buff.truesize); 
 
@@ -509,13 +530,14 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
 
        dev->trans_start = jiffies;
 
-       if ( self->tty->driver.write)
+       if (self->tty->driver.write)
                actual = self->tty->driver.write(self->tty, 0, 
                                                 idev->tx_buff.data, 
                                                 idev->tx_buff.len);
 
-       idev->tx_buff.offset = actual;
-       idev->tx_buff.head = idev->tx_buff.data + actual;
+       /* Hide the part we just transmitted */
+       idev->tx_buff.data += actual;
+       idev->tx_buff.len -= actual;
 
        idev->stats.tx_packets++;
        idev->stats.tx_bytes += idev->tx_buff.len;
@@ -524,7 +546,7 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
         *  Did we transmit the whole frame? Commented out for now since
         *  I must check if this optimalization really works. DB.
         */
-       if (( idev->tx.count - idev->tx.ptr) <= 0) {
+       if ((idev->tx_buff.len) == 0) {
                DEBUG( 4, "irtty_xmit_buf: finished with frame!\n");
                self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
                irda_unlock( &self->tbusy);
@@ -541,8 +563,9 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
  *    Used by the TTY to find out how much data we can receive at a time
  * 
 */
-static int irtty_receive_room( struct tty_struct *tty) 
+static int irtty_receive_room(struct tty_struct *tty) 
 {
+       DEBUG(0, __FUNCTION__ "()\n");
        return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
@@ -553,47 +576,42 @@ static int irtty_receive_room( struct tty_struct *tty)
  *    more packets to send, we send them here.
  *
  */
-static void irtty_write_wakeup( struct tty_struct *tty) 
+static void irtty_write_wakeup(struct tty_struct *tty) 
 {
-       int actual = 0, count;
        struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
        struct irda_device *idev;
+       int actual = 0;
        
        /* 
         *  First make sure we're connected. 
         */
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
 
        idev = &self->idev;
 
-       /*
-        *  Finished with frame?
-        */
-       if ( idev->tx_buff.offset == idev->tx_buff.len)  {
+       /* Finished with frame?  */
+       if (idev->tx_buff.len > 0)  {
+               /* Write data left in transmit buffer */
+               actual = tty->driver.write(tty, 0, idev->tx_buff.data, 
+                                          idev->tx_buff.len);
 
+               idev->tx_buff.data += actual;
+               idev->tx_buff.len  -= actual;
+       } else {                
                /* 
                 *  Now serial buffer is almost free & we can start 
                 *  transmission of another packet 
                 */
                DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
-
+               
                tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
                idev->netdev.tbusy = 0; /* Unlock */
-
+                       
                /* Tell network layer that we want more frames */
-               mark_bh( NET_BH);
-
-               return;
+               mark_bh(NET_BH);
        }
-       /*
-        *  Write data left in transmit buffer
-        */
-       count = idev->tx_buff.len - idev->tx_buff.offset;
-       actual = tty->driver.write( tty, 0, idev->tx_buff.head, count);
-       idev->tx_buff.offset += actual;
-       idev->tx_buff.head += actual;
 }
 
 /*
@@ -602,9 +620,9 @@ static void irtty_write_wakeup( struct tty_struct *tty)
  *    Return TRUE is we are currently receiving a frame
  *
  */
-static int irtty_is_receiving( struct irda_device *idev)
+static int irtty_is_receiving(struct irda_device *idev)
 {
-       return ( idev->rx_buff.state != OUTSIDE_FRAME);
+       return (idev->rx_buff.state != OUTSIDE_FRAME);
 }
 
 /*
@@ -614,20 +632,20 @@ static int irtty_is_receiving( struct irda_device *idev)
  *    to change the speed of the serial port. Warning this function must
  *    be called with a process context!
  */
-static void irtty_wait_until_sent( struct irda_device *idev)
+static void irtty_wait_until_sent(struct irda_device *idev)
 {
        struct irtty_cb *self = (struct irtty_cb *) idev->priv;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
        
-       DEBUG( 4, "Chars in buffer %d\n", 
-              self->tty->driver.chars_in_buffer( self->tty));
+       DEBUG(4, "Chars in buffer %d\n", 
+             self->tty->driver.chars_in_buffer(self->tty));
        
-       tty_wait_until_sent( self->tty, 0);
+       tty_wait_until_sent(self->tty, 0);
 }
 
-int irtty_register_dongle( struct dongle *dongle)
+int irtty_register_dongle(struct dongle *dongle)
 {
        struct dongle_q *new;
        
@@ -638,12 +656,11 @@ int irtty_register_dongle( struct dongle *dongle)
         }
        
        /* Make new IrDA dongle */
-        new = (struct dongle_q *)kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
-        if (new == NULL) {
-                return 1;
+        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
+        if (new == NULL)
+                return -1;
                
-        }
-       memset( new, 0, sizeof( struct dongle_q));
+       memset(new, 0, sizeof( struct dongle_q));
         new->dongle = dongle;
 
        /* Insert IrDA dongle into hashbin */
@@ -652,16 +669,16 @@ int irtty_register_dongle( struct dongle *dongle)
         return 0;
 }
 
-void irtty_unregister_dongle( struct dongle *dongle)
+void irtty_unregister_dongle(struct dongle *dongle)
 {
        struct dongle_q *node;
 
-       node = hashbin_remove( dongles, dongle->type, NULL);
-       if ( !node) {
-               DEBUG( 0, __FUNCTION__ "(), dongle not found!\n");
+       node = hashbin_remove(dongles, dongle->type, NULL);
+       if (!node) {
+               ERROR(__FUNCTION__ "(), dongle not found!\n");
                return;
        }
-       kfree( node);
+       kfree(node);
 }
 
 
@@ -696,26 +713,24 @@ void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts)
        set_fs(get_ds());
        
        if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
-               DEBUG(0, __FUNCTION__ "(), error!\n");
+               ERROR(__FUNCTION__ "(), error doing ioctl!\n");
        }
        set_fs(fs);
 }
 
-
-static int irtty_net_init( struct device *dev)
+static int irtty_net_init(struct device *dev)
 {
        /* Set up to be a normal IrDA network device driver */
-       irda_device_setup( dev);
+       irda_device_setup(dev);
 
        /* Insert overrides below this line! */
 
        return 0;
 }
 
-
-static int irtty_net_open( struct device *dev)
+static int irtty_net_open(struct device *dev)
 {
-       ASSERT( dev != NULL, return -1;);
+       ASSERT(dev != NULL, return -1;);
 
        /* Ready to play! */
        dev->tbusy = 0;
@@ -729,7 +744,7 @@ static int irtty_net_open( struct device *dev)
 
 static int irtty_net_close(struct device *dev)
 {
-       ASSERT( dev != NULL, return -1;);
+       ASSERT(dev != NULL, return -1;);
        
        /* Stop device */
        dev->tbusy = 1;
index 385a1eb5f2a219c45d4c4e5b81b24f2c68b2e97b..878b2e33a84654498563b2fddba46e3acf0e8443 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Sat Apr  3 15:54:47 1999
+ * Modified at:   Tue Apr 20 11:11:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
@@ -734,10 +734,9 @@ static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev)
 
        /* Decide if we should use PIO or DMA transfer */
        if ( idev->io.baudrate > 115200) {
-               memcpy( idev->tx_buff.data, skb->data, skb->len);
+               idev->tx_buff.data = idev->tx_buff.head;
+               memcpy(idev->tx_buff.data, skb->data, skb->len);
                idev->tx_buff.len = skb->len;
-               idev->tx_buff.head = idev->tx_buff.data;
-               idev->tx_buff.offset = 0;
 
                mtt = irda_get_mtt( skb);
                if ( mtt > 50) {
@@ -767,11 +766,10 @@ static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev)
                        pc87108_dma_write( idev, iobase);
                }
         } else {
-               idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, 
-                                                   idev->tx_buff.truesize);
+               idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
+                                                  idev->tx_buff.truesize);
                
-               idev->tx_buff.offset = 0;
-               idev->tx_buff.head = idev->tx_buff.data;
+               idev->tx_buff.data = idev->tx_buff.head;
                
                /* Add interrupt on tx low level (will fire immediately) */
                switch_bank( iobase, BANK0);
@@ -945,8 +943,7 @@ static int pc87108_dma_receive(struct irda_device *idev)
        
        /* driver->media_busy = FALSE; */
        idev->io.direction = IO_RECV;
-       idev->rx_buff.head = idev->rx_buff.data;
-       idev->rx_buff.offset = 0;
+       idev->rx_buff.data = idev->rx_buff.head;
 
        /* Reset Rx FIFO. This will also flush the ST_FIFO */
        outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
@@ -1024,42 +1021,41 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
                                /* Skip frame */
                                idev->stats.rx_errors++;
                                
-                               idev->rx_buff.offset  += len;
-                               idev->rx_buff.head += len;
+                               idev->rx_buff.data += len;
                        
-                               if ( status & FRM_ST_MAX_LEN)
+                               if (status & FRM_ST_MAX_LEN)
                                        idev->stats.rx_length_errors++;
                                
-                               if ( status & FRM_ST_PHY_ERR) 
+                               if (status & FRM_ST_PHY_ERR) 
                                        idev->stats.rx_frame_errors++;
                                
-                               if ( status & FRM_ST_BAD_CRC) 
+                               if (status & FRM_ST_BAD_CRC) 
                                        idev->stats.rx_crc_errors++;
                        }
                        /* The errors below can be reported in both cases */
-                       if ( status & FRM_ST_OVR1)
+                       if (status & FRM_ST_OVR1)
                                idev->stats.rx_fifo_errors++;
                        
-                       if ( status & FRM_ST_OVR2)
+                       if (status & FRM_ST_OVR2)
                                idev->stats.rx_fifo_errors++;
                        
                } else {
                        /* Check if we have transfered all data to memory */
-                       if ( inb( iobase+LSR) & LSR_RXDA) {
+                       if (inb(iobase+LSR) & LSR_RXDA) {
                                /* Put this entry back in fifo */
                                st_fifo->head--;
                                st_fifo->len++;
                                st_fifo->entries[st_fifo->head].status = status;
-                               st_fifo->entries[ st_fifo->head].len = len;
+                               st_fifo->entries[st_fifo->head].len = len;
 
                                /* Restore bank register */
-                               outb( bank, iobase+BSR);
+                               outb(bank, iobase+BSR);
                        
                                return FALSE;   /* I'll be back! */
                        }
 
                        /* Should be OK then */                 
-                       skb = dev_alloc_skb( len+1);
+                       skb = dev_alloc_skb(len+1);
                        if (skb == NULL)  {
                                printk( KERN_INFO __FUNCTION__ 
                                        "(), memory squeeze, dropping frame.\n");
@@ -1070,20 +1066,19 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
                        }
                        
                        /* Make sure IP header gets aligned */
-                       skb_reserve( skb, 1); 
+                       skb_reserve(skb, 1); 
 
                        /* Copy frame without CRC */
-                       if ( idev->io.baudrate < 4000000) {
-                               skb_put( skb, len-2);
-                               memcpy( skb->data, idev->rx_buff.head, len-2);
+                       if (idev->io.baudrate < 4000000) {
+                               skb_put(skb, len-2);
+                               memcpy(skb->data, idev->rx_buff.data, len-2);
                        } else {
-                               skb_put( skb, len-4);
-                               memcpy( skb->data, idev->rx_buff.head, len-4);
+                               skb_put(skb, len-4);
+                               memcpy(skb->data, idev->rx_buff.data, len-4);
                        }
 
                        /* Move to next frame */
-                       idev->rx_buff.offset += len;
-                       idev->rx_buff.head += len;
+                       idev->rx_buff.data += len;
                        idev->stats.rx_packets++;
 
                        skb->dev = &idev->netdev;
@@ -1093,7 +1088,7 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase)
                }
        }
        /* Restore bank register */
-       outb( bank, iobase+BSR);
+       outb(bank, iobase+BSR);
 
        return TRUE;
 }
@@ -1109,23 +1104,19 @@ static void pc87108_pio_receive( struct irda_device *idev)
        __u8 byte = 0x00;
        int iobase;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
        iobase = idev->io.iobase;
        
-       if ( idev->rx_buff.len == 0) {
-               idev->rx_buff.head = idev->rx_buff.data;
-       }
-
        /*  Receive all characters in Rx FIFO */
        do {
-               byte = inb( iobase+RXD);
-               async_unwrap_char( idev, byte);
+               byte = inb(iobase+RXD);
+               async_unwrap_char(idev, byte);
 
-       } while ( inb( iobase+LSR) & LSR_RXDA); /* Data available */    
+       } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */      
 }
 
 /*
@@ -1134,38 +1125,35 @@ static void pc87108_pio_receive( struct irda_device *idev)
  *    Handle SIR interrupt
  *
  */
-static __u8 pc87108_sir_interrupt( struct irda_device *idev, int eir)
+static __u8 pc87108_sir_interrupt(struct irda_device *idev, int eir)
 {
-       int len;
        int actual;
        __u8 new_ier = 0;
 
        /* Transmit FIFO low on data */
        if ( eir & EIR_TXLDL_EV) {
                /* Write data left in transmit buffer */
-               len = idev->tx_buff.len - idev->tx_buff.offset;
-
-               ASSERT( len > 0, return 0;);
-               actual = pc87108_pio_write( idev->io.iobase, 
-                                           idev->tx_buff.head, 
-                                           len, idev->io.fifo_size);
-               idev->tx_buff.offset += actual;
-               idev->tx_buff.head += actual;
+               actual = pc87108_pio_write(idev->io.iobase, 
+                                          idev->tx_buff.data, 
+                                          idev->tx_buff.len, 
+                                          idev->io.fifo_size);
+               idev->tx_buff.data += actual;
+               idev->tx_buff.len  -= actual;
                
                idev->io.direction = IO_XMIT;
-               ASSERT( actual <= len, return 0;);
 
                /* Check if finished */
-               if ( actual == len) { 
-                       DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
+               if (idev->tx_buff.len > 0)
+                       new_ier |= IER_TXLDL_IE;
+               else { 
                        idev->netdev.tbusy = 0; /* Unlock */
                        idev->stats.tx_packets++;
-
+                       
                        mark_bh(NET_BH);        
 
                        new_ier |= IER_TXEMP_IE;
-               } else
-                       new_ier |= IER_TXLDL_IE;
+               }
+                       
        }
        /* Check if transmission has completed */
        if ( eir & EIR_TXEMP_EV) {
index eb8e2a0c41ceb327e947d4bc22340f75eef3cab4..de1a553a4aaf1605a2e3caab085840627839f298 100644 (file)
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      tekram.c
- * Version:       0.5
+ * Version:       1.0
  * Description:   Implementation of the Tekram IrMate IR-210B dongle
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon Feb 15 14:13:17 1999
+ * Modified at:   Tue Apr 13 16:33:54 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
 #include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
-#include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/irtty.h>
 #include <net/irda/dongle.h>
 
-static void tekram_reset( struct irda_device *dev, int unused);
-static void tekram_open( struct irda_device *dev, int type);
-static void tekram_close( struct irda_device *dev);
-static void tekram_change_speed( struct irda_device *dev, int baud);
-static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos);
+static void tekram_reset(struct irda_device *dev, int unused);
+static void tekram_open(struct irda_device *dev, int type);
+static void tekram_close(struct irda_device *dev);
+static void tekram_change_speed(struct irda_device *dev, int baud);
+static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos);
+
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600  0x01
+#define TEKRAM_38400  0x02
+#define TEKRAM_19200  0x03
+#define TEKRAM_9600   0x04
+
+#define TEKRAM_PW 0x10 /* Pulse select bit */
 
 static struct dongle dongle = {
        TEKRAM_DONGLE,
@@ -53,9 +60,9 @@ static struct dongle dongle = {
        tekram_init_qos,
 };
 
-__initfunc(void tekram_init(void))
+__initfunc(int tekram_init(void))
 {
-       irtty_register_dongle( &dongle);
+       return irtty_register_dongle(&dongle);
 }
 
 void tekram_cleanup(void)
@@ -102,17 +109,17 @@ static void tekram_change_speed( struct irda_device *dev, int baud)
        int cflag;
        __u8 byte;
        
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( dev != NULL, return;);
-       ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;);
+       ASSERT(dev != NULL, return;);
+       ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
        
        self = (struct irtty_cb *) dev->priv;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
        
-       if ( !self->tty)
+       if (!self->tty)
                return;
 
        tty = self->tty;
@@ -123,26 +130,27 @@ static void tekram_change_speed( struct irda_device *dev, int baud)
        cflag &= ~CBAUD;
 
        switch (baud) {
-       case 9600:
        default:
+               /* FALLTHROUGH */
+       case 9600:
                cflag |= B9600;
-               byte = 4;
+               byte = TEKRAM_PW|TEKRAM_9600;
                break;
        case 19200:
                cflag |= B19200;
-               byte = 3;
+               byte = TEKRAM_PW|TEKRAM_19200;
                break;
        case 34800:
                cflag |= B38400;
-               byte = 2;
+               byte = TEKRAM_PW|TEKRAM_38400;
                break;
        case 57600:
                cflag |= B57600;
-               byte = 1;
+               byte = TEKRAM_PW|TEKRAM_57600;
                break;
        case 115200:
                cflag |= B115200;
-               byte = 0;
+               byte = TEKRAM_PW|TEKRAM_115200;
                break;
        }
 
@@ -150,22 +158,22 @@ static void tekram_change_speed( struct irda_device *dev, int baud)
        irtty_set_dtr_rts(tty, TRUE, FALSE);
        
        /* Wait at least 7us */
-       udelay( 7);
+       udelay(7);
 
        /* Write control byte */
-       if ( tty->driver.write)
-               tty->driver.write( self->tty, 0, &byte, 1);
+       if (tty->driver.write)
+               tty->driver.write(self->tty, 0, &byte, 1);
        
        /* Wait at least 100 ms */
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout( 10);
+       schedule_timeout(MSECS_TO_JIFFIES(100));
         
        /* Set DTR, Set RTS */
        irtty_set_dtr_rts(tty, TRUE, TRUE);
 
        /* Now change the speed of the serial port */
        tty->termios->c_cflag = cflag;
-       tty->driver.set_termios( tty, &old_termios);    
+       tty->driver.set_termios(tty, &old_termios);     
 }
 
 /*
@@ -175,30 +183,29 @@ static void tekram_change_speed( struct irda_device *dev, int baud)
  *      must be called with a process context!! 
  *
  *      Algorithm:
- *       0. set RTS and DTR, and wait 50 ms 
- *           ( power off the IR-210 )
+ *       0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
  *        1. clear RTS 
  *        2. set DTR, and wait at least 1 ms 
  *        3. clear DTR to SPACE state, wait at least 50 us for further 
  *         operation
  */
-void tekram_reset( struct irda_device *dev, int unused)
+void tekram_reset(struct irda_device *dev, int unused)
 {
        struct irtty_cb *self;
        struct tty_struct *tty;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( dev != NULL, return;);
-       ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;);
+       ASSERT(dev != NULL, return;);
+       ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
        
        self = (struct irtty_cb *) dev->priv;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRTTY_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IRTTY_MAGIC, return;);
 
        tty = self->tty;
-       if ( !tty)
+       if (!tty)
                return;
 
        /* Power off dongle */
@@ -206,18 +213,20 @@ void tekram_reset( struct irda_device *dev, int unused)
 
        /* Sleep 50 ms */
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(5);
+       schedule_timeout(MSECS_TO_JIFFIES(50));
 
        /* Clear DTR, Set RTS */
        irtty_set_dtr_rts(tty, FALSE, TRUE); 
 
        /* Should sleep 1 ms, but 10-20 should not do any harm */
        current->state = TASK_INTERRUPTIBLE;
-       schedule_timeout(2);
+       schedule_timeout(MSECS_TO_JIFFIES(20));
 
        /* Set DTR, Set RTS */
        irtty_set_dtr_rts(tty, TRUE, TRUE);
        
+       udelay(50);
+
        /* Finished! */
 }
 
@@ -227,10 +236,11 @@ void tekram_reset( struct irda_device *dev, int unused)
  *    Initialize QoS capabilities
  *
  */
-static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos)
 {
        qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-       qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */
+       qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
+       irda_qos_bits_to_value(qos);
 }
 
 #ifdef MODULE
@@ -246,8 +256,7 @@ MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
  */
 int init_module(void)
 {
-       tekram_init();
-       return(0);
+       return tekram_init();
 }
 
 /*
index c4915c7556b7d9af04b22ba3d80a34fc59ec89e2..60c8e024a0d1fec5c56b44e05c48cf494d69c972 100644 (file)
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Sat Apr  3 15:54:41 1999
+ * Modified at:   Tue Apr 20 11:15:52 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -190,7 +190,7 @@ static int uircc_open(int i, unsigned int iobase, unsigned int iobase2,
        
        /* The only value we must override it the baudrate */
        idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
-               IR_115200|/*IR_576000|IR_1152000| */(IR_4000000 << 8);
+               IR_115200/*IR_576000|IR_1152000 |(IR_4000000 << 8)*/;
 
        idev->qos.min_turn_time.bits = 0x0f;
        irda_qos_bits_to_value(&idev->qos);
@@ -372,7 +372,7 @@ static void uircc_change_speed(struct irda_device *idev, int speed)
                DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
 
                /* Set self pole address */
-               outb(0x10, iobase+UIRCC_CR8);
+               //outb(0xfe, iobase+UIRCC_CR8);
 
                /* outb(0x10, iobase+UIRCC_CR11); */
                break;
@@ -443,8 +443,7 @@ static int uircc_hard_xmit(struct sk_buff *skb, struct device *dev)
                skb->len++;
 
        idev->tx_buff.len = skb->len;
-       idev->tx_buff.head = idev->tx_buff.data;
-       idev->tx_buff.offset = 0;
+       idev->tx_buff.data = idev->tx_buff.head;
        
        mtt = irda_get_mtt(skb);
        
@@ -586,11 +585,15 @@ static int uircc_dma_receive(struct irda_device *idev)
        outb(self->cr3, iobase+UIRCC_CR3);
 
        /* Transmit reset (just in case) */
-       outb(UIRCC_CR0_XMIT_RST, iobase+UIRCC_CR0);
+       outb(UIRCC_CR0_XMIT_RST|0x17, iobase+UIRCC_CR0);
 
        /* Set modem */
        outb(0x08, iobase+UIRCC_CR10);
 
+       /* Enable receiving with CRC */
+       self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN);
+       outb(self->cr3, iobase+UIRCC_CR3);
+
        /* Make sure Rx DMA is set */
        outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1);
 
@@ -602,13 +605,13 @@ static int uircc_dma_receive(struct irda_device *idev)
        
        /* driver->media_busy = FALSE; */
        idev->io.direction = IO_RECV;
-       idev->rx_buff.head = idev->rx_buff.data;
-       idev->rx_buff.offset = 0;
+       idev->rx_buff.data = idev->rx_buff.head;
 
+#if 0
        /* Enable receiving with CRC */
        self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN);
        outb(self->cr3, iobase+UIRCC_CR3);
-
+#endif
        DEBUG(4, __FUNCTION__ "(), cr3=%#x\n", self->cr3);
        
        /* Address check? */
@@ -673,7 +676,7 @@ static int uircc_dma_receive_complete(struct irda_device *idev, int iobase)
 /*     } */
 
        skb_put(skb, len);
-       memcpy(skb->data, idev->rx_buff.head, len);
+       memcpy(skb->data, idev->rx_buff.data, len);
        idev->stats.rx_packets++;
 
        skb->dev = &idev->netdev;
@@ -737,7 +740,7 @@ static void uircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                uircc_dma_xmit_complete(idev, FALSE);
                uircc_dma_receive(idev);
 
-               /* outb(0, iobase+UIRCC_CR2);  */
+               outb(0x0d, iobase+UIRCC_CR2);
                break;
        case UIRCC_SR3_TMR_OUT:
                /* Disable timer */
index 5d92f5a198204a3a1e2406415dcb49d1dce1e761..9234c4a82022b5f2d96d60916379aba661f05114 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Wed Apr  7 17:35:59 1999
+ * Modified at:   Tue Apr 20 11:15:00 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Corel Computer Corp.
@@ -482,8 +482,7 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
        if (idev->io.baudrate > 115200) {
                memcpy(idev->tx_buff.data, skb->data, skb->len);
                idev->tx_buff.len = skb->len;
-               idev->tx_buff.head = idev->tx_buff.data;
-               idev->tx_buff.offset = 0;
+               idev->tx_buff.data = idev->tx_buff.head;
                
                mtt = irda_get_mtt(skb);
                if (mtt > 50) {
@@ -512,20 +511,18 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev)
                        w83977af_dma_write(idev, iobase);
                }
        } else {
+               idev->tx_buff.data = idev->tx_buff.head;
                idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
                                                   idev->tx_buff.truesize);
                
-               idev->tx_buff.offset = 0;
-               idev->tx_buff.head = idev->tx_buff.data;
-               
                /* Add interrupt on tx low level (will fire immediately) */
-               switch_bank( iobase, SET0);
+               switch_bank(iobase, SET0);
                outb(ICR_ETXTHI, iobase+ICR);
        }
        dev_kfree_skb(skb);
 
        /* Restore set register */
-       outb( set, iobase+SSR);
+       outb(set, iobase+SSR);
 
        return 0;
 }
@@ -594,9 +591,9 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
        }
 
        /* Fill FIFO with current frame */
-       while (( fifo_size-- > 0) && (actual < len)) {
+       while ((fifo_size-- > 0) && (actual < len)) {
                /* Transmit next byte */
-               outb( buf[actual++], iobase+TBR);
+               outb(buf[actual++], iobase+TBR);
        }
         
        DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
@@ -702,8 +699,7 @@ int w83977af_dma_receive(struct irda_device *idev)
 #endif
        /* driver->media_busy = FALSE; */
        idev->io.direction = IO_RECV;
-       idev->rx_buff.head = idev->rx_buff.data;
-       idev->rx_buff.offset = 0;
+       idev->rx_buff.data = idev->rx_buff.head;
 
        /* 
         * Reset Rx FIFO. This will also flush the ST_FIFO, it's very 
@@ -751,30 +747,30 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
        __u8 set;
        __u8 status;
 
-       DEBUG( 0, __FUNCTION__ "\n");
+       DEBUG(0, __FUNCTION__ "\n");
 
        iobase = idev->io.iobase;
 
        /* Save current set */
-       set = inb( iobase+SSR);
+       set = inb(iobase+SSR);
        
        iobase = idev->io.iobase;
 
        switch_bank(iobase, SET5);
-       if ( prev.status & FS_FO_FSFDR) {
+       if (prev.status & FS_FO_FSFDR) {
                status = prev.status;
                len = prev.len;
-
+               
                prev.status = 0;
        } else {
-               status = inb( iobase+FS_FO);
-               len = inb( iobase+RFLFL);
-               len |= inb( iobase+RFLFH) << 8;
+               status = inb(iobase+FS_FO);
+               len = inb(iobase+RFLFL);
+               len |= inb(iobase+RFLFH) << 8;
        }
 
-       while ( status & FS_FO_FSFDR) {
+       while (status & FS_FO_FSFDR) {
                /* Check for errors */
-               if ( status & FS_FO_ERR_MSK) {
+               if (status & FS_FO_ERR_MSK) {
                        if ( status & FS_FO_LST_FR) {
                                /* Add number of lost frames to stats */
                                idev->stats.rx_errors += len;   
@@ -782,29 +778,28 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
                                /* Skip frame */
                                idev->stats.rx_errors++;
                                
-                               idev->rx_buff.offset += len;
-                               idev->rx_buff.head   += len;
+                               idev->rx_buff.data += len;
                                
-                               if ( status & FS_FO_MX_LEX)
+                               if (status & FS_FO_MX_LEX)
                                        idev->stats.rx_length_errors++;
                                
-                               if ( status & FS_FO_PHY_ERR) 
+                               if (status & FS_FO_PHY_ERR) 
                                        idev->stats.rx_frame_errors++;
                                
-                               if ( status & FS_FO_CRC_ERR) 
+                               if (status & FS_FO_CRC_ERR) 
                                        idev->stats.rx_crc_errors++;
                        }
                        /* The errors below can be reported in both cases */
-                       if ( status & FS_FO_RX_OV)
+                       if (status & FS_FO_RX_OV)
                                idev->stats.rx_fifo_errors++;
                        
-                       if ( status & FS_FO_FSF_OV)
+                       if (status & FS_FO_FSF_OV)
                                idev->stats.rx_fifo_errors++;
                        
                } else {
                        /* Check if we have transfered all data to memory */
                        switch_bank(iobase, SET0);
-                       if ( inb( iobase+USR) & USR_RDR) {
+                       if (inb(iobase+USR) & USR_RDR) {
                                /* Put this entry back in fifo */
                                prev.status = status;
                                prev.len = len;
@@ -815,31 +810,30 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
                                return FALSE;   /* I'll be back! */
                        }
                                                
-                       skb = dev_alloc_skb( len+1);
+                       skb = dev_alloc_skb(len+1);
                        if (skb == NULL)  {
-                               printk( KERN_INFO __FUNCTION__ 
-                                       "(), memory squeeze, dropping frame.\n");
+                               printk(KERN_INFO __FUNCTION__ 
+                                      "(), memory squeeze, dropping frame.\n");
                                /* Restore set register */
-                               outb( set, iobase+SSR);
+                               outb(set, iobase+SSR);
 
                                return FALSE;
                        }
                        
                        /*  Align to 20 bytes */
-                       skb_reserve( skb, 1); 
+                       skb_reserve(skb, 1); 
                        
                        /* Copy frame without CRC */
                        if ( idev->io.baudrate < 4000000) {
                                skb_put( skb, len-2);
-                               memcpy( skb->data, idev->rx_buff.head, len-2);
+                               memcpy( skb->data, idev->rx_buff.data, len-2);
                        } else {
                                skb_put( skb, len-4);
-                               memcpy( skb->data, idev->rx_buff.head, len-4);
+                               memcpy( skb->data, idev->rx_buff.data, len-4);
                        }
 
                        /* Move to next frame */
-                       idev->rx_buff.offset += len;
-                       idev->rx_buff.head += len;
+                       idev->rx_buff.data += len;
                        
                        skb->dev = &idev->netdev;
                        skb->mac.raw  = skb->data;
@@ -854,7 +848,7 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
                len |= inb( iobase+RFLFH) << 8;
        }
        /* Restore set register */
-       outb( set, iobase+SSR);
+       outb(set, iobase+SSR);
 
        return TRUE;
 }
@@ -865,28 +859,24 @@ int w83977af_dma_receive_complete(struct irda_device *idev)
  *    Receive all data in receiver FIFO
  *
  */
-static void w83977af_pio_receive( struct irda_device *idev) 
+static void w83977af_pio_receive(struct irda_device *idev) 
 {
        __u8 byte = 0x00;
        int iobase;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( idev != NULL, return;);
-       ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+       ASSERT(idev != NULL, return;);
+       ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
        
        iobase = idev->io.iobase;
        
-       if ( idev->rx_buff.len == 0) {
-               idev->rx_buff.head = idev->rx_buff.data;
-       }
-
        /*  Receive all characters in Rx FIFO */
        do {
-               byte = inb( iobase+RBR);
-               async_unwrap_char( idev, byte);
+               byte = inb(iobase+RBR);
+               async_unwrap_char(idev, byte);
 
-       } while ( inb( iobase+USR) & USR_RDR); /* Data available */     
+       } while (inb(iobase+USR) & USR_RDR); /* Data available */       
 }
 
 /*
@@ -897,7 +887,6 @@ static void w83977af_pio_receive( struct irda_device *idev)
  */
 static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
 {
-       int len;
        int actual;
        __u8 new_icr = 0;
 
@@ -906,19 +895,19 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
        /* Transmit FIFO low on data */
        if (isr & ISR_TXTH_I) {
                /* Write data left in transmit buffer */
-               len = idev->tx_buff.len - idev->tx_buff.offset;
-
-               ASSERT(len > 0, return 0;);
                actual = w83977af_pio_write(idev->io.iobase, 
-                                           idev->tx_buff.head, 
-                                           len, idev->io.fifo_size);
-               idev->tx_buff.offset += actual;
-               idev->tx_buff.head += actual;
+                                           idev->tx_buff.data, 
+                                           idev->tx_buff.len, 
+                                           idev->io.fifo_size);
+               idev->tx_buff.data += actual;
+               idev->tx_buff.len  -= actual;
                
                idev->io.direction = IO_XMIT;
-               ASSERT( actual <= len, return 0;);
+
                /* Check if finished */
-               if ( actual == len) { 
+               if (idev->tx_buff.len > 0)
+                       new_icr |= ICR_ETXTHI;
+               else { 
                        DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
                        idev->netdev.tbusy = 0; /* Unlock */
                        idev->stats.tx_packets++;
@@ -927,8 +916,8 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
                        mark_bh(NET_BH);        
 
                        new_icr |= ICR_ETBREI;
-               } else
-                       new_icr |= ICR_ETXTHI;
+               }
+               
        }
        /* Check if transmission has completed */
        if (isr & ISR_TXEMP_I) {
index edb41febb4d433b79edbc39a6e576022a268d80c..4391bb68fe3ab226dbf1014dabfeb6cc35ab1f94 100644 (file)
@@ -252,6 +252,22 @@ hipfound:                          /* From the double loop above. */
        return dev;
 }
 
+
+void unregister_hipdev(struct device *dev)
+{
+       int i;
+       rtnl_lock();
+       unregister_netdevice(dev);
+       for (i = 0; i < MAX_HIP_CARDS; ++i) {
+               if (hipdev_index[i] == dev) {
+                       hipdev_index[i] = NULL;
+                       break;
+               }
+       }
+       rtnl_unlock();
+}
+
+
 static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
 {
        /* Never send broadcast/multicast ARP messages */
index d56f772061cb40d055e5e84a3745f3df30fac16e..f2ce89efa73ed700e867ac9037ba84741482d557 100644 (file)
@@ -13,7 +13,7 @@
  *     This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.11 17.1.99 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -58,9 +58,36 @@ static const int rx_copybreak = 200;
 
 #define PORT_PORTSEL  0x03
 #define PORT_ASEL     0x04
+#define PORT_100      0x40
 #define PORT_FD       0x80
 
-static int options = PORT_ASEL;  /* port selection */
+
+/*
+ * table to translate option values from tulip
+ * to internal options
+ */
+static unsigned char options_mapping[] = {
+    PORT_ASEL,                    /*  0 Auto-select      */
+    PORT_AUI,                     /*  1 BNC/AUI          */
+    PORT_AUI,                     /*  2 AUI/BNC          */ 
+    PORT_ASEL,                    /*  3 not supported    */
+    PORT_10BT | PORT_FD,          /*  4 10baseT-FD       */
+    PORT_ASEL,                    /*  5 not supported    */
+    PORT_ASEL,                    /*  6 not supported    */
+    PORT_ASEL,                    /*  7 not supported    */
+    PORT_ASEL,                    /*  8 not supported    */
+    PORT_MII,                     /*  9 MII 10baseT      */
+    PORT_MII | PORT_FD,            /* 10 MII 10baseT-FD   */
+    PORT_MII,                     /* 11 MII (autosel)    */
+    PORT_10BT,                    /* 12 10BaseT          */
+    PORT_MII | PORT_100,          /* 13 MII 100BaseTx    */
+    PORT_MII | PORT_100 | PORT_FD, /* 14 MII 100BaseTx-FD */
+    PORT_ASEL                     /* 15 not supported    */
+};
+
+#define MAX_UNITS 8
+static int options[MAX_UNITS] = {0, };
+static int full_duplex[MAX_UNITS] = {0, };
 
 /*
  *                             Theory of Operation
@@ -116,6 +143,12 @@ static int options = PORT_ASEL;  /* port selection */
  *         added port selection for modules
  *         detect special T1/E1 WAN card and setup port selection
  * v1.11:  fixed wrong checking of Tx errors
+ * v1.20:  added check of return value kmalloc (cpeterso@cs.washington.edu)
+ *         added save original kmalloc addr for freeing (mcr@solidum.com)
+ *         added support for PCnetHome chip (joe@MIT.EDU)
+ *         rewritten PCI card detection
+ *         added dwio mode to get driver working on some PPC machines
+ * v1.21:  added mii selection and mii ioctl
  */
 
 
@@ -140,202 +173,402 @@ static int options = PORT_ASEL;  /* port selection */
 #define PKT_BUF_SZ             1544
 
 /* Offsets from base I/O address. */
-#define PCNET32_DATA 0x10
-#define PCNET32_ADDR 0x12
-#define PCNET32_RESET 0x14
-#define PCNET32_BUS_IF 0x16
-#define PCNET32_TOTAL_SIZE 0x18
+#define PCNET32_WIO_RDP                0x10
+#define PCNET32_WIO_RAP                0x12
+#define PCNET32_WIO_RESET      0x14
+#define PCNET32_WIO_BDP                0x16
+
+#define PCNET32_DWIO_RDP       0x10
+#define PCNET32_DWIO_RAP       0x14
+#define PCNET32_DWIO_RESET     0x18
+#define PCNET32_DWIO_BDP       0x1C
+
+#define PCNET32_TOTAL_SIZE 0x20
 
 #define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
-       u32 base;
-       s16 buf_length;
-        s16 status;    
-       u32 msg_length;
-       u32 reserved;
+    u32 base;
+    s16 buf_length;
+    s16 status;    
+    u32 msg_length;
+    u32 reserved;
 };
        
 struct pcnet32_tx_head {
-       u32 base;
-       s16 length;
-        s16 status;
-       u32 misc;
-       u32 reserved;
+    u32 base;
+    s16 length;
+    s16 status;
+    u32 misc;
+    u32 reserved;
 };
 
-
 /* The PCNET32 32-Bit initialization block, described in databook. */
 struct pcnet32_init_block {
-       u16 mode;
-       u16 tlen_rlen;
-       u8  phys_addr[6];
-       u16 reserved;
-       u32 filter[2];
-       /* Receive and transmit ring base, along with extra bits. */    
-       u32 rx_ring;
-       u32 tx_ring;
+    u16 mode;
+    u16 tlen_rlen;
+    u8  phys_addr[6];
+    u16 reserved;
+    u32 filter[2];
+    /* Receive and transmit ring base, along with extra bits. */    
+    u32 rx_ring;
+    u32 tx_ring;
+};
+
+/* PCnet32 access functions */
+struct pcnet32_access {
+    u16 (*read_csr)(unsigned long, int);
+    void (*write_csr)(unsigned long, int, u16);
+    u16 (*read_bcr)(unsigned long, int);
+    void (*write_bcr)(unsigned long, int, u16);
+    u16 (*read_rap)(unsigned long);
+    void (*write_rap)(unsigned long, u16);
+    void (*reset)(unsigned long);
 };
 
 struct pcnet32_private {
-       /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
-       struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
-       struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
-       struct pcnet32_init_block       init_block;
-       const char *name;
-       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
-       struct sk_buff *tx_skbuff[TX_RING_SIZE];
-        struct sk_buff *rx_skbuff[RX_RING_SIZE];
-       int cur_rx, cur_tx;                     /* The next free ring entry */
-       int dirty_rx, dirty_tx;                 /* The ring entries to be free()ed. */
-       struct net_device_stats stats;
-       char tx_full;
-        int  options;
-        int  shared_irq:1,                      /* shared irq possible */
-             full_duplex:1;                     /* full duplex possible */
+    /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
+    struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
+    struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
+    struct pcnet32_init_block  init_block;
+    const char *name;
+    /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+    struct sk_buff *tx_skbuff[TX_RING_SIZE];
+    struct sk_buff *rx_skbuff[RX_RING_SIZE];
+    struct pcnet32_access a;
+    void *origmem;
+    int cur_rx, cur_tx;                        /* The next free ring entry */
+    int dirty_rx, dirty_tx;                    /* The ring entries to be free()ed. */
+    struct net_device_stats stats;
+    char tx_full;
+    int  options;
+    int  shared_irq:1,                      /* shared irq possible */
+         full_duplex:1,                     /* full duplex possible */
+         mii:1;                             /* mii port available */
 #ifdef MODULE
-        struct device *next;
+    struct device *next;
 #endif    
 };
 
-int  pcnet32_probe(struct device *dev);
-static int  pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared);
-static int  pcnet32_open(struct device *dev);
-static int  pcnet32_init_ring(struct device *dev);
-static int  pcnet32_start_xmit(struct sk_buff *skb, struct device *dev);
-static int  pcnet32_rx(struct device *dev);
-static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int  pcnet32_close(struct device *dev);
-static struct net_device_stats *pcnet32_get_stats(struct device *dev);
-static void pcnet32_set_multicast_list(struct device *dev);
+int  pcnet32_probe(struct device *);
+static int  pcnet32_probe1(struct device *, unsigned long, unsigned char, int, int);
+static int  pcnet32_open(struct device *);
+static int  pcnet32_init_ring(struct device *);
+static int  pcnet32_start_xmit(struct sk_buff *, struct device *);
+static int  pcnet32_rx(struct device *);
+static void pcnet32_interrupt(int, void *, struct pt_regs *);
+static int  pcnet32_close(struct device *);
+static struct net_device_stats *pcnet32_get_stats(struct device *);
+static void pcnet32_set_multicast_list(struct device *);
+#ifdef HAVE_PRIVATE_IOCTL
+static int  pcnet32_mii_ioctl(struct device *, struct ifreq *, int);
+#endif
+
+enum pci_flags_bit {
+    PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+    PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+
+struct pcnet32_pci_id_info {
+    const char *name;
+    u16 vendor_id, device_id, device_id_mask, flags;
+    int io_size;
+    int (*probe1) (struct device *, unsigned long, unsigned char, int, int);
+};
+
+static struct pcnet32_pci_id_info pcnet32_tbl[] = {
+    { "AMD PCnetPCI series",
+       0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+       pcnet32_probe1},
+    {0,}
+};
+
+static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    return inw (addr+PCNET32_WIO_RDP);
+}
+
+static void pcnet32_wio_write_csr (unsigned long addr, int index, u16 val)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    outw (val, addr+PCNET32_WIO_RDP);
+}
+
+static u16 pcnet32_wio_read_bcr (unsigned long addr, int index)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    return inw (addr+PCNET32_WIO_BDP);
+}
+
+static void pcnet32_wio_write_bcr (unsigned long addr, int index, u16 val)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    outw (val, addr+PCNET32_WIO_BDP);
+}
+
+static u16 pcnet32_wio_read_rap (unsigned long addr)
+{
+    return inw (addr+PCNET32_WIO_RAP);
+}
+
+static void pcnet32_wio_write_rap (unsigned long addr, u16 val)
+{
+    outw (val, addr+PCNET32_WIO_RAP);
+}
+
+static void pcnet32_wio_reset (unsigned long addr)
+{
+    inw (addr+PCNET32_WIO_RESET);
+}
+
+static int pcnet32_wio_check (unsigned long addr)
+{
+    outw (88, addr+PCNET32_WIO_RAP);
+    return (inw (addr+PCNET32_WIO_RAP) == 88);
+}
+
+static struct pcnet32_access pcnet32_wio = {
+    pcnet32_wio_read_csr,
+    pcnet32_wio_write_csr,
+    pcnet32_wio_read_bcr,
+    pcnet32_wio_write_bcr,
+    pcnet32_wio_read_rap,
+    pcnet32_wio_write_rap,
+    pcnet32_wio_reset
+};
+
+static u16 pcnet32_dwio_read_csr (unsigned long addr, int index)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    return (inl (addr+PCNET32_DWIO_RDP) & 0xffff);
+}
+
+static void pcnet32_dwio_write_csr (unsigned long addr, int index, u16 val)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    outl (val, addr+PCNET32_DWIO_RDP);
+}
+
+static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    return (inl (addr+PCNET32_DWIO_BDP) & 0xffff);
+}
+
+static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    outl (val, addr+PCNET32_DWIO_BDP);
+}
+
+static u16 pcnet32_dwio_read_rap (unsigned long addr)
+{
+    return (inl (addr+PCNET32_DWIO_RAP) & 0xffff);
+}
+
+static void pcnet32_dwio_write_rap (unsigned long addr, u16 val)
+{
+    outl (val, addr+PCNET32_DWIO_RAP);
+}
+
+static void pcnet32_dwio_reset (unsigned long addr)
+{
+    inl (addr+PCNET32_DWIO_RESET);
+}
+
+static int pcnet32_dwio_check (unsigned long addr)
+{
+    outl (88, addr+PCNET32_DWIO_RAP);
+    return (inl (addr+PCNET32_DWIO_RAP) == 88);
+}
+
+static struct pcnet32_access pcnet32_dwio = {
+    pcnet32_dwio_read_csr,
+    pcnet32_dwio_write_csr,
+    pcnet32_dwio_read_bcr,
+    pcnet32_dwio_write_bcr,
+    pcnet32_dwio_read_rap,
+    pcnet32_dwio_write_rap,
+    pcnet32_dwio_reset
+
+};
 
 \f
 
-__initfunc(int pcnet32_probe (struct device *dev))
+int __init pcnet32_probe (struct device *dev)
 {
-    unsigned int  ioaddr = dev ? dev->base_addr: 0;
+    unsigned long ioaddr = dev ? dev->base_addr: 0;
     unsigned int  irq_line = dev ? dev->irq : 0;
     int *port;
+    int cards_found = 0;
     
-    if (ioaddr > 0x1ff)
-      return pcnet32_probe1(dev, ioaddr, irq_line, 0);
-    else if(ioaddr != 0)
-      return ENXIO;
+    
+#ifndef __powerpc__
+    if (ioaddr > 0x1ff) {
+       if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0)
+           return pcnet32_probe1(dev, ioaddr, irq_line, 0, 0);
+       else
+           return ENODEV;
+    } else
+#endif
+       if(ioaddr != 0)
+           return ENXIO;
     
 #if defined(CONFIG_PCI)
     if (pci_present()) {
-       struct pci_dev *pdev = NULL;
+       struct pci_dev *pdev;
+       unsigned char pci_bus, pci_device_fn;
+       int pci_index;
        
        printk("pcnet32.c: PCI bios is present, checking for devices...\n");
-       while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
-           unsigned short pci_command;
+       for (pci_index = 0; pci_index < 0xff; pci_index++) {
+           u16 vendor, device, pci_command;
+           int chip_idx;
 
-           irq_line = pdev->irq;
+           if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+                                   pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+               break;
+           
+           pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor);
+           pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device);
+
+           for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
+               if (vendor == pcnet32_tbl[chip_idx].vendor_id &&
+                   (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id)
+                   break;
+           if (pcnet32_tbl[chip_idx].vendor_id == 0)
+               continue;
+           
+           pdev = pci_find_slot(pci_bus, pci_device_fn);
            ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+#if defined(ADDR_64BITS) && defined(__alpha__)
+           ioaddr |= ((long)pdev->base_address[1]) << 32;
+#endif
+           irq_line = pdev->irq;
+           
+           /* Avoid already found cards from previous pcnet32_probe() calls */
+           if ((pcnet32_tbl[chip_idx].flags & PCI_USES_IO) &&
+               check_region(ioaddr, pcnet32_tbl[chip_idx].io_size))
+               continue;
+
            /* PCI Spec 2.1 states that it is either the driver or PCI card's
             * responsibility to set the PCI Master Enable Bit if needed.
             *  (From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
             */
            pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-           
-           /* Avoid already found cards from previous pcnet32_probe() calls */
-           if (check_region(ioaddr, PCNET32_TOTAL_SIZE))
-             continue;
-
            if ( ! (pci_command & PCI_COMMAND_MASTER)) {
                printk("PCI Master Bit has not been set. Setting...\n");
                pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
                pci_write_config_word(pdev, PCI_COMMAND, pci_command);
            }
+           printk("Found PCnet/PCI at %#lx, irq %d.\n", ioaddr, irq_line);
            
-           printk("Found PCnet/PCI at %#x, irq %d.\n",
-                  ioaddr, irq_line);
-           
-           if (pcnet32_probe1(dev, ioaddr, irq_line, 1) != 0) {        /* Shouldn't happen. */
-               printk(KERN_ERR "pcnet32.c: Probe of PCI card at %#x failed.\n", ioaddr);
-               break;
+           if (pcnet32_tbl[chip_idx].probe1(dev, ioaddr, irq_line, 1, cards_found) == 0) {
+               cards_found++;
+               dev = NULL;
            }
-           return 0;
        }
     } else 
 #endif  /* defined(CONFIG_PCI) */
     
     /* now look for PCnet32 VLB cards */
     for (port = pcnet32_portlist; *port; port++) {
-       unsigned int ioaddr = *port;
+       unsigned long ioaddr = *port;
        
        if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
            /* check if there is really a pcnet chip on that ioaddr */
            if ((inb(ioaddr + 14) == 0x57) &&
                (inb(ioaddr + 15) == 0x57) &&
-               (pcnet32_probe1(dev, ioaddr, 0, 0) == 0))
-             return 0;
+               (pcnet32_probe1(dev, ioaddr, 0, 0, 0) == 0))
+               cards_found++;
        }
     }
-    return ENODEV;
+    return cards_found ? 0: ENODEV;
 }
 
 
 /* pcnet32_probe1 */
-__initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared))
+static int __init
+pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx)
 {
     struct pcnet32_private *lp;
-    int i,full_duplex = 0;
+    int i,media,fdx = 0, mii = 0;
+    int chip_version;
     char *chipname;
+    char *priv;
+    struct pcnet32_access *a;
+
+    /* reset the chip */
+    pcnet32_dwio_reset(ioaddr);
+    pcnet32_wio_reset(ioaddr);
+
+    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
+       a = &pcnet32_wio;
+    } else {
+       if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+           a = &pcnet32_dwio;
+       } else
+           return ENODEV;
+    }
 
-    inw(ioaddr+PCNET32_RESET); /* Reset the PCNET32 */
-
-    outw(0x0000, ioaddr+PCNET32_ADDR); /* Switch to window 0 */
-    if (inw(ioaddr+PCNET32_DATA) != 0x0004)
-      return ENODEV;
-
-    /* Get the version of the chip. */
-    outw(88, ioaddr+PCNET32_ADDR);
-    if (inw(ioaddr+PCNET32_ADDR) != 88) {
-       /* should never happen */
+    chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
+    if (pcnet32_debug > 2)
+       printk("  PCnet chip version is %#x.\n", chip_version);
+    if ((chip_version & 0xfff) != 0x003)
        return ENODEV;
-    } else {                   /* Good, it's a newer chip. */
-       int chip_version = inw(ioaddr+PCNET32_DATA);
-       outw(89, ioaddr+PCNET32_ADDR);
-       chip_version |= inw(ioaddr+PCNET32_DATA) << 16;
+    chip_version = (chip_version >> 12) & 0xffff;
+    switch (chip_version) {
+     case 0x2420:
+       chipname = "PCnet/PCI 79C970";
+       break;
+     case 0x2430:
+       if (shared)
+           chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
+       else
+           chipname = "PCnet/32 79C965";
+       break;
+     case 0x2621:
+       chipname = "PCnet/PCI II 79C970A";
+       fdx = 1;
+       break;
+     case 0x2623:
+       chipname = "PCnet/FAST 79C971";
+       fdx = 1; mii = 1;
+       break;
+     case 0x2624:
+       chipname = "PCnet/FAST+ 79C972";
+       fdx = 1; mii = 1;
+       break;
+     case 0x2626:
+       chipname = "PCnet/Home 79C978";
+       fdx = 1;
+       /* 
+        * This is based on specs published at www.amd.com.  This section
+        * assumes that a card with a 79C978 wants to go into 1Mb HomePNA
+        * mode.  The 79C978 can also go into standard ethernet, and there
+        * probably should be some sort of module option to select the
+        * mode by which the card should operate
+        */
+       /* switch to home wiring mode */
+       media = a->read_bcr (ioaddr, 49);
        if (pcnet32_debug > 2)
-         printk("  PCnet chip version is %#x.\n", chip_version);
-       if ((chip_version & 0xfff) != 0x003)
-         return ENODEV;
-       chip_version = (chip_version >> 12) & 0xffff;
-       switch (chip_version) {
-        case 0x2420:
-           chipname = "PCnet/PCI 79C970";
-           break;
-        case 0x2430:
-           if (shared)
-               chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
-           else
-               chipname = "PCnet/32 79C965";
-           break;
-        case 0x2621:
-           chipname = "PCnet/PCI II 79C970A";
-           full_duplex = 1;
-           break;
-        case 0x2623:
-           chipname = "PCnet/FAST 79C971";
-           full_duplex = 1;
-           break;
-        case 0x2624:
-           chipname = "PCnet/FAST+ 79C972";
-           full_duplex = 1;
-           break;
-        default:
-           printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
-           return ENODEV;
-       }
+           printk("pcnet32: pcnet32 media value %#x.\n",  media);
+       media &= ~3;
+       media |= 1;
+       if (pcnet32_debug > 2)
+           printk("pcnet32: pcnet32 media reset to %#x.\n",  media);
+       a->write_bcr (ioaddr, 49, media);
+       break;
+     default:
+       printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+       return ENODEV;
     }
     
-    if (dev == NULL)
-       dev = init_etherdev(0, 0);
+    dev = init_etherdev(dev, 0);
 
-    printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+    printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
 
     /* There is a 16 byte station address PROM at the base address.
      The first six bytes are the station address. */
@@ -345,15 +578,31 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
-    /* Make certain the data structures used by the PCnet32 are 16byte aligned and DMAble. */
-    lp = (struct pcnet32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
+    if ((priv = kmalloc(sizeof(*lp)+15,GFP_KERNEL)) == NULL)
+       return ENOMEM;
+
+    /*
+     * Make certain the data structures used by
+     * the PCnet32 are 16byte aligned
+      */
+    lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
       
     memset(lp, 0, sizeof(*lp));
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
-    lp->full_duplex = full_duplex;
-    lp->options = options;
+    lp->full_duplex = fdx;
+    lp->mii = mii;
+    if (options[card_idx] > sizeof (options_mapping))
+       lp->options = PORT_ASEL;
+    else
+       lp->options = options_mapping[options[card_idx]];
+    
+    if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx])
+       lp->options |= PORT_FD;
+    
+    lp->origmem = priv;
+    lp->a = *a;
     
     /* detect special T1/E1 WAN card by checking for MAC address */
     if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75)
@@ -369,24 +618,17 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
     lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
     
     /* switch pcnet32 to 32bit mode */
-    outw(0x0014, ioaddr+PCNET32_ADDR);
-    outw(0x0002, ioaddr+PCNET32_BUS_IF);
-
-    outw(0x0001, ioaddr+PCNET32_ADDR);
-    inw(ioaddr+PCNET32_ADDR);
-    outw(virt_to_bus(&lp->init_block) & 0xffff, ioaddr+PCNET32_DATA);
-    outw(0x0002, ioaddr+PCNET32_ADDR);
-    inw(ioaddr+PCNET32_ADDR);
-    outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
-    outw(0x0000, ioaddr+PCNET32_ADDR);
-    inw(ioaddr+PCNET32_ADDR);
+    a->write_bcr (ioaddr, 20, 2);
+
+    a->write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) & 0xffff);
+    a->write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
     
     if (irq_line) {
        dev->irq = irq_line;
     }
     
     if (dev->irq >= 2)
-      printk(" assigned IRQ %d.\n", dev->irq);
+       printk(" assigned IRQ %d.\n", dev->irq);
     else {
        unsigned long irq_mask = probe_irq_on();
        
@@ -396,7 +638,7 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
         * boards will work.
         */
        /* Trigger an initialization just for the interrupt. */
-       outw(0x0041, ioaddr+PCNET32_DATA);
+       a->write_csr (ioaddr, 0, 0x41);
        mdelay (1);
        
        dev->irq = probe_irq_off (irq_mask);
@@ -409,7 +651,7 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
     }
 
     if (pcnet32_debug > 0)
-      printk(version);
+       printk(version);
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -417,6 +659,10 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
     dev->stop = &pcnet32_close;
     dev->get_stats = &pcnet32_get_stats;
     dev->set_multicast_list = &pcnet32_set_multicast_list;
+#ifdef HAVE_PRIVATE_IOCTL
+    dev->do_ioctl = &pcnet32_mii_ioctl;
+#endif
+
     
 #ifdef MODULE
     lp->next = pcnet32_dev;
@@ -432,95 +678,96 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un
 static int
 pcnet32_open(struct device *dev)
 {
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-       unsigned int ioaddr = dev->base_addr;
-        unsigned short val;
-       int i;
-
-       if (dev->irq == 0 ||
-               request_irq(dev->irq, &pcnet32_interrupt,
-                           lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
-               return -EAGAIN;
-       }
-
-       /* Reset the PCNET32 */
-       inw(ioaddr+PCNET32_RESET);
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    u16 val;
+    int i;
+
+    if (dev->irq == 0 ||
+       request_irq(dev->irq, &pcnet32_interrupt,
+                   lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
+       return -EAGAIN;
+    }
 
-       /* switch pcnet32 to 32bit mode */
-       outw(0x0014, ioaddr+PCNET32_ADDR);
-       outw(0x0002, ioaddr+PCNET32_BUS_IF);
+    /* Reset the PCNET32 */
+    lp->a.reset (ioaddr);
 
-       if (pcnet32_debug > 1)
-               printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
-                          dev->name, dev->irq,
-                          (u32) virt_to_bus(lp->tx_ring),
-                          (u32) virt_to_bus(lp->rx_ring),
-                          (u32) virt_to_bus(&lp->init_block));
+    /* switch pcnet32 to 32bit mode */
+    lp->a.write_csr (ioaddr, 20, 2);
+
+    if (pcnet32_debug > 1)
+       printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
+              dev->name, dev->irq,
+              (u32) virt_to_bus(lp->tx_ring),
+              (u32) virt_to_bus(lp->rx_ring),
+              (u32) virt_to_bus(&lp->init_block));
     
-        /* set/reset autoselect bit */
-       outw(0x0002, ioaddr+PCNET32_ADDR);
-        val = inw(ioaddr+PCNET32_BUS_IF) & ~2;
-        if (lp->options & PORT_ASEL)
-               val |= 2;
-        outw(val, ioaddr+PCNET32_BUS_IF);
-
-        /* handle full duplex setting */
-        if (lp->full_duplex) {
-           outw (0x0009, ioaddr+PCNET32_ADDR);
-           val = inw(ioaddr+PCNET32_BUS_IF) & ~3;
-           if (lp->options & PORT_FD) {
-               val |= 1;
-               if (lp->options == (PORT_FD | PORT_AUI))
-                   val |= 2;
-           }
-           outw(val, ioaddr+PCNET32_BUS_IF);
+    /* set/reset autoselect bit */
+    val = lp->a.read_bcr (ioaddr, 2) & ~2;
+    if (lp->options & PORT_ASEL)
+       val |= 2;
+    lp->a.write_bcr (ioaddr, 2, val);
+    
+    /* handle full duplex setting */
+    if (lp->full_duplex) {
+       val = lp->a.read_bcr (ioaddr, 9) & ~3;
+       if (lp->options & PORT_FD) {
+           val |= 1;
+           if (lp->options == (PORT_FD | PORT_AUI))
+               val |= 2;
        }
+       lp->a.write_bcr (ioaddr, 9, val);
+    }
     
-        /* set/reset GPSI bit in test register */
-        outw (0x007c, ioaddr+PCNET32_ADDR);
-        val = inw(ioaddr+PCNET32_DATA) & ~0x10;
-        if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
-               val |= 0x10;
-       outw(val, ioaddr+PCNET32_DATA);
-           
-       lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
-       lp->init_block.filter[0] = 0x00000000;
-       lp->init_block.filter[1] = 0x00000000;
-       if (pcnet32_init_ring(dev))
-               return -ENOMEM;
+    /* set/reset GPSI bit in test register */
+    val = lp->a.read_csr (ioaddr, 124) & ~0x10;
+    if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
+       val |= 0x10;
+    lp->a.write_csr (ioaddr, 124, val);
     
-       /* Re-initialize the PCNET32, and start it when done. */
-       outw(0x0001, ioaddr+PCNET32_ADDR);
-       outw(virt_to_bus(&lp->init_block) &0xffff, ioaddr+PCNET32_DATA);
-       outw(0x0002, ioaddr+PCNET32_ADDR);
-       outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
-
-       outw(0x0004, ioaddr+PCNET32_ADDR);
-       outw(0x0915, ioaddr+PCNET32_DATA);
-
-       outw(0x0000, ioaddr+PCNET32_ADDR);
-       outw(0x0001, ioaddr+PCNET32_DATA);
-
-       dev->tbusy = 0;
-       dev->interrupt = 0;
-       dev->start = 1;
-       i = 0;
-       while (i++ < 100)
-               if (inw(ioaddr+PCNET32_DATA) & 0x0100)
-                       break;
-       /* 
-        * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
-        * reports that doing so triggers a bug in the '974.
-        */
-       outw(0x0042, ioaddr+PCNET32_DATA);
-
-       if (pcnet32_debug > 2)
-               printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-                          dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA));
-
-        MOD_INC_USE_COUNT;
+    if (lp->mii & (lp->options & PORT_ASEL)) {
+       val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */
+       if (lp->options & PORT_FD)
+           val |= 0x10;
+       if (lp->options & PORT_100)
+           val |= 0x08;
+       lp->a.write_bcr (ioaddr, 32, val);
+    }
+    
+    lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
+    lp->init_block.filter[0] = 0x00000000;
+    lp->init_block.filter[1] = 0x00000000;
+    if (pcnet32_init_ring(dev))
+       return -ENOMEM;
+    
+    /* Re-initialize the PCNET32, and start it when done. */
+    lp->a.write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) &0xffff);
+    lp->a.write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
+
+    lp->a.write_csr (ioaddr, 4, 0x0915);
+    lp->a.write_csr (ioaddr, 0, 0x0001);
+
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    dev->start = 1;
+    i = 0;
+    while (i++ < 100)
+       if (lp->a.read_csr (ioaddr, 0) & 0x0100)
+           break;
+    /* 
+     * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+     * reports that doing so triggers a bug in the '974.
+     */
+    lp->a.write_csr (ioaddr, 0, 0x0042);
+
+    if (pcnet32_debug > 2)
+       printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+              dev->name, i, (u32) virt_to_bus(&lp->init_block),
+              lp->a.read_csr (ioaddr, 0));
+
+    MOD_INC_USE_COUNT;
     
-       return 0;                                       /* Always succeed */
+    return 0;  /* Always succeed */
 }
 
 /*
@@ -539,15 +786,15 @@ pcnet32_open(struct device *dev)
 static void 
 pcnet32_purge_tx_ring(struct device *dev)
 {
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-       int i;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int i;
 
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               if (lp->tx_skbuff[i]) {
-                       dev_kfree_skb(lp->tx_skbuff[i]);
-                       lp->tx_skbuff[i] = NULL;
-               }
+    for (i = 0; i < TX_RING_SIZE; i++) {
+       if (lp->tx_skbuff[i]) {
+           dev_kfree_skb(lp->tx_skbuff[i]);
+           lp->tx_skbuff[i] = NULL;
        }
+    }
 }
 
 
@@ -555,445 +802,437 @@ pcnet32_purge_tx_ring(struct device *dev)
 static int
 pcnet32_init_ring(struct device *dev)
 {
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-       int i;
-
-       lp->tx_full = 0;
-       lp->cur_rx = lp->cur_tx = 0;
-       lp->dirty_rx = lp->dirty_tx = 0;
-
-       for (i = 0; i < RX_RING_SIZE; i++) {
-           if (lp->rx_skbuff[i] == NULL) {
-               if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
-                   /* there is not much, we can do at this point */
-                   printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
-                   return -1;
-               }
-               skb_reserve (lp->rx_skbuff[i], 2);
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int i;
+
+    lp->tx_full = 0;
+    lp->cur_rx = lp->cur_tx = 0;
+    lp->dirty_rx = lp->dirty_tx = 0;
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+       if (lp->rx_skbuff[i] == NULL) {
+           if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
+               /* there is not much, we can do at this point */
+               printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
+               return -1;
            }
-           lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
-           lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
-           lp->rx_ring[i].status = le16_to_cpu(0x8000);
-       }
-       /* The Tx buffer address is filled in as needed, but we do need to clear
-          the upper ownership bit. */
-       for (i = 0; i < TX_RING_SIZE; i++) {
-               lp->tx_ring[i].base = 0;
-               lp->tx_ring[i].status = 0;
+           skb_reserve (lp->rx_skbuff[i], 2);
        }
+       lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
+       lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+       lp->rx_ring[i].status = le16_to_cpu(0x8000);
+    }
+    /* The Tx buffer address is filled in as needed, but we do need to clear
+     the upper ownership bit. */
+    for (i = 0; i < TX_RING_SIZE; i++) {
+       lp->tx_ring[i].base = 0;
+       lp->tx_ring[i].status = 0;
+    }
 
-        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
-       for (i = 0; i < 6; i++)
-               lp->init_block.phys_addr[i] = dev->dev_addr[i];
-       lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
-       lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
-       return 0;
+    lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
+    for (i = 0; i < 6; i++)
+       lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    return 0;
 }
 
 static void
 pcnet32_restart(struct device *dev, unsigned int csr0_bits)
 {
-        int i;
-       unsigned int ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    int i;
     
-       pcnet32_purge_tx_ring(dev);
-       if (pcnet32_init_ring(dev))
-               return;
+    pcnet32_purge_tx_ring(dev);
+    if (pcnet32_init_ring(dev))
+       return;
     
-       outw(0x0000, ioaddr + PCNET32_ADDR);
-        /* ReInit Ring */
-        outw(0x0001, ioaddr + PCNET32_DATA);
-       i = 0;
-       while (i++ < 100)
-               if (inw(ioaddr+PCNET32_DATA) & 0x0100)
-                       break;
-
-       outw(csr0_bits, ioaddr + PCNET32_DATA);
+    /* ReInit Ring */
+    lp->a.write_csr (ioaddr, 0, 1);
+    i = 0;
+    while (i++ < 100)
+       if (lp->a.read_csr (ioaddr, 0) & 0x0100)
+           break;
+
+    lp->a.write_csr (ioaddr, 0, csr0_bits);
 }
 
 static int
 pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
 {
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-       unsigned int ioaddr = dev->base_addr;
-       int entry;
-       unsigned long flags;
-
-       /* Transmitter timeout, serious problems. */
-       if (dev->tbusy) {
-               int tickssofar = jiffies - dev->trans_start;
-               if (tickssofar < HZ/2)
-                       return 1;
-               outw(0, ioaddr+PCNET32_ADDR);
-               printk("%s: transmit timed out, status %4.4x, resetting.\n",
-                          dev->name, inw(ioaddr+PCNET32_DATA));
-               outw(0x0004, ioaddr+PCNET32_DATA);
-               lp->stats.tx_errors++;
-               if (pcnet32_debug > 2) {
-                       int i;
-                       printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-                                  lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-                                  lp->cur_rx);
-                       for (i = 0 ; i < RX_RING_SIZE; i++)
-                               printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-                                          lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-                                          lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
-                       for (i = 0 ; i < TX_RING_SIZE; i++)
-                               printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-                                          lp->tx_ring[i].base, -lp->tx_ring[i].length,
-                                          lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
-                       printk("\n");
-               }
-               pcnet32_restart(dev, 0x0042);
-
-               dev->tbusy = 0;
-               dev->trans_start = jiffies;
-               dev_kfree_skb(skb);
-               return 0;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned int ioaddr = dev->base_addr;
+    int entry;
+    unsigned long flags;
+
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+       int tickssofar = jiffies - dev->trans_start;
+       if (tickssofar < HZ/2)
+           return 1;
+       printk("%s: transmit timed out, status %4.4x, resetting.\n",
+              dev->name, lp->a.read_csr (ioaddr, 0));
+       lp->a.write_csr (ioaddr, 0, 0x0004);
+       lp->stats.tx_errors++;
+       if (pcnet32_debug > 2) {
+           int i;
+           printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+                  lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+                  lp->cur_rx);
+           for (i = 0 ; i < RX_RING_SIZE; i++)
+               printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+                      lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+                      lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+           for (i = 0 ; i < TX_RING_SIZE; i++)
+               printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+                      lp->tx_ring[i].base, -lp->tx_ring[i].length,
+                      lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+           printk("\n");
        }
+       pcnet32_restart(dev, 0x0042);
 
-       if (pcnet32_debug > 3) {
-               outw(0x0000, ioaddr+PCNET32_ADDR);
-               printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name,
-                          inw(ioaddr+PCNET32_DATA));
-       }
+       dev->tbusy = 0;
+       dev->trans_start = jiffies;
+       dev_kfree_skb(skb);
+       return 0;
+    }
 
-       /* Block a timer-based transmit from overlapping.  This could better be
-          done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-       if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-               printk("%s: Transmitter access conflict.\n", dev->name);
-               return 1;
-       }
+    if (pcnet32_debug > 3) {
+       printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
+              dev->name, lp->a.read_csr (ioaddr, 0));
+    }
 
-       save_flags (flags);
-       cli ();
+    /* Block a timer-based transmit from overlapping.  This could better be
+       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+       printk("%s: Transmitter access conflict.\n", dev->name);
+       return 1;
+    }
 
-       /* Fill in a Tx ring entry */
+    save_flags (flags);
+    cli ();
 
-       /* Mask to ring buffer boundary. */
-       entry = lp->cur_tx & TX_RING_MOD_MASK;
+    /* Fill in a Tx ring entry */
 
-       /* Caution: the write order is important here, set the base address
-          with the "ownership" bits last. */
+    /* Mask to ring buffer boundary. */
+    entry = lp->cur_tx & TX_RING_MOD_MASK;
 
-       lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+    /* Caution: the write order is important here, set the base address
+       with the "ownership" bits last. */
 
-       lp->tx_ring[entry].misc = 0x00000000;
+    lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
 
-       lp->tx_skbuff[entry] = skb;
-       lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
-        lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+    lp->tx_ring[entry].misc = 0x00000000;
 
-       lp->cur_tx++;
-        lp->stats.tx_bytes += skb->len;
+    lp->tx_skbuff[entry] = skb;
+    lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
+    lp->tx_ring[entry].status = le16_to_cpu(0x8300);
 
-       /* Trigger an immediate send poll. */
-       outw(0x0000, ioaddr+PCNET32_ADDR);
-       outw(0x0048, ioaddr+PCNET32_DATA);
+    lp->cur_tx++;
+    lp->stats.tx_bytes += skb->len;
 
-       dev->trans_start = jiffies;
+    /* Trigger an immediate send poll. */
+    lp->a.write_csr (ioaddr, 0, 0x0048);
 
-       if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
-               clear_bit (0, (void *)&dev->tbusy);
-       else
-               lp->tx_full = 1;
-       restore_flags(flags);
-       return 0;
+    dev->trans_start = jiffies;
+
+    if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
+       clear_bit (0, (void *)&dev->tbusy);
+    else
+       lp->tx_full = 1;
+    restore_flags(flags);
+    return 0;
 }
 
 /* The PCNET32 interrupt handler. */
 static void
 pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-       struct device *dev = (struct device *)dev_id;
-       struct pcnet32_private *lp;
-       unsigned int csr0, ioaddr;
-       int boguscnt =  max_interrupt_work;
-       int must_restart;
-
-       if (dev == NULL) {
-               printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
-               return;
-       }
+    struct device *dev = (struct device *)dev_id;
+    struct pcnet32_private *lp;
+    unsigned long ioaddr;
+    u16 csr0;
+    int boguscnt =  max_interrupt_work;
+    int must_restart;
 
-       ioaddr = dev->base_addr;
-       lp = (struct pcnet32_private *)dev->priv;
-       if (dev->interrupt)
-               printk("%s: Re-entering the interrupt handler.\n", dev->name);
+    if (dev == NULL) {
+       printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+       return;
+    }
 
-       dev->interrupt = 1;
+    ioaddr = dev->base_addr;
+    lp = (struct pcnet32_private *)dev->priv;
+    if (dev->interrupt)
+       printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
-       outw(0x00, dev->base_addr + PCNET32_ADDR);
-       while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600 && --boguscnt >= 0) {
-               /* Acknowledge all of the current interrupt sources ASAP. */
-               outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA);
+    dev->interrupt = 1;
 
-               must_restart = 0;
+    while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
+       /* Acknowledge all of the current interrupt sources ASAP. */
+       lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
 
-               if (pcnet32_debug > 5)
-                       printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
-                                  dev->name, csr0, inw(dev->base_addr + PCNET32_DATA));
+       must_restart = 0;
 
-               if (csr0 & 0x0400)                      /* Rx interrupt */
-                       pcnet32_rx(dev);
+       if (pcnet32_debug > 5)
+           printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+                  dev->name, csr0, lp->a.read_csr (ioaddr, 0));
 
-               if (csr0 & 0x0200) {            /* Tx-done interrupt */
-                       int dirty_tx = lp->dirty_tx;
+       if (csr0 & 0x0400)              /* Rx interrupt */
+           pcnet32_rx(dev);
 
-                       while (dirty_tx < lp->cur_tx) {
-                               int entry = dirty_tx & TX_RING_MOD_MASK;
-                               int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+       if (csr0 & 0x0200) {            /* Tx-done interrupt */
+           int dirty_tx = lp->dirty_tx;
+
+           while (dirty_tx < lp->cur_tx) {
+               int entry = dirty_tx & TX_RING_MOD_MASK;
+               int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
                        
-                               if (status < 0)
-                                       break;                  /* It still hasn't been Txed */
-
-                               lp->tx_ring[entry].base = 0;
-
-                               if (status & 0x4000) {
-                                       /* There was an major error, log it. */
-                                       int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
-                                       lp->stats.tx_errors++;
-                                       if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
-                                       if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
-                                       if (err_status & 0x10000000) lp->stats.tx_window_errors++;
-                                       if (err_status & 0x40000000) {
-                                               /* Ackk!  On FIFO errors the Tx unit is turned off! */
-                                               lp->stats.tx_fifo_errors++;
-                                               /* Remove this verbosity later! */
-                                               printk("%s: Tx FIFO error! Status %4.4x.\n",
-                                                          dev->name, csr0);
-                                               must_restart = 1;
+               if (status < 0)
+                   break;              /* It still hasn't been Txed */
+
+               lp->tx_ring[entry].base = 0;
+
+               if (status & 0x4000) {
+                   /* There was an major error, log it. */
+                   int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
+                   lp->stats.tx_errors++;
+                   if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
+                   if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
+                   if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+                   if (err_status & 0x40000000) {
+                       /* Ackk!  On FIFO errors the Tx unit is turned off! */
+                       lp->stats.tx_fifo_errors++;
+                       /* Remove this verbosity later! */
+                       printk("%s: Tx FIFO error! Status %4.4x.\n",
+                              dev->name, csr0);
+                       must_restart = 1;
                                        }
-                               } else {
-                                       if (status & 0x1800)
-                                               lp->stats.collisions++;
-                                       lp->stats.tx_packets++;
-                               }
-
-                               /* We must free the original skb */
-                               if (lp->tx_skbuff[entry]) {
-                                       dev_kfree_skb(lp->tx_skbuff[entry]);
-                                       lp->tx_skbuff[entry] = 0;
-                               }
-                               dirty_tx++;
-                       }
+               } else {
+                   if (status & 0x1800)
+                       lp->stats.collisions++;
+                   lp->stats.tx_packets++;
+               }
+
+               /* We must free the original skb */
+               if (lp->tx_skbuff[entry]) {
+                   dev_kfree_skb(lp->tx_skbuff[entry]);
+                   lp->tx_skbuff[entry] = 0;
+               }
+               dirty_tx++;
+           }
 
 #ifndef final_version
-                       if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-                               printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-                                          dirty_tx, lp->cur_tx, lp->tx_full);
-                               dirty_tx += TX_RING_SIZE;
-                       }
+           if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+               printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+                      dirty_tx, lp->cur_tx, lp->tx_full);
+               dirty_tx += TX_RING_SIZE;
+           }
 #endif
+           if (lp->tx_full && dev->tbusy
+               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+               /* The ring is no longer full, clear tbusy. */
+               lp->tx_full = 0;
+               clear_bit(0, (void *)&dev->tbusy);
+               mark_bh(NET_BH);
+           }
+           lp->dirty_tx = dirty_tx;
+       }
 
-                       if (lp->tx_full && dev->tbusy
-                               && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
-                               /* The ring is no longer full, clear tbusy. */
-                               lp->tx_full = 0;
-                               clear_bit(0, (void *)&dev->tbusy);
-                               mark_bh(NET_BH);
-                       }
-                       lp->dirty_tx = dirty_tx;
-               }
-
-               /* Log misc errors. */
-               if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
-               if (csr0 & 0x1000) {
-                   /*
-                    * this happens when our receive ring is full. This shouldn't
-                    * be a problem as we will see normal rx interrupts for the frames
-                    * in the receive ring. But there are some PCI chipsets (I can reproduce
-                    * this on SP3G with Intel saturn chipset) which have sometimes problems
-                    * and will fill up the receive ring with error descriptors. In this
-                    * situation we don't get a rx interrupt, but a missed frame interrupt sooner
-                    * or later. So we try to clean up our receive ring here.
-                    */
-                   pcnet32_rx(dev);
-                   lp->stats.rx_errors++; /* Missed a Rx frame. */
-               }
-               if (csr0 & 0x0800) {
-                       printk("%s: Bus master arbitration failure, status %4.4x.\n",
-                                  dev->name, csr0);
-                       /* unlike for the lance, there is no restart needed */
-               }
+       /* Log misc errors. */
+       if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
+       if (csr0 & 0x1000) {
+           /*
+            * this happens when our receive ring is full. This shouldn't
+            * be a problem as we will see normal rx interrupts for the frames
+            * in the receive ring. But there are some PCI chipsets (I can reproduce
+            * this on SP3G with Intel saturn chipset) which have sometimes problems
+            * and will fill up the receive ring with error descriptors. In this
+            * situation we don't get a rx interrupt, but a missed frame interrupt sooner
+            * or later. So we try to clean up our receive ring here.
+            */
+           pcnet32_rx(dev);
+           lp->stats.rx_errors++; /* Missed a Rx frame. */
+       }
+       if (csr0 & 0x0800) {
+           printk("%s: Bus master arbitration failure, status %4.4x.\n",
+                  dev->name, csr0);
+           /* unlike for the lance, there is no restart needed */
+       }
 
-               if (must_restart) {
-                       /* stop the chip to clear the error condition, then restart */
-                       outw(0x0000, dev->base_addr + PCNET32_ADDR);
-                       outw(0x0004, dev->base_addr + PCNET32_DATA);
-                       pcnet32_restart(dev, 0x0002);
-               }
+       if (must_restart) {
+           /* stop the chip to clear the error condition, then restart */
+           lp->a.write_csr (ioaddr, 0, 0x0004);
+           pcnet32_restart(dev, 0x0002);
        }
+    }
 
     /* Clear any other interrupt, and set interrupt enable. */
-    outw(0x0000, dev->base_addr + PCNET32_ADDR);
-    outw(0x7940, dev->base_addr + PCNET32_DATA);
+    lp->a.write_csr (ioaddr, 0, 0x7940);
 
-       if (pcnet32_debug > 4)
-               printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
-                          dev->name, inw(ioaddr + PCNET32_ADDR),
-                          inw(dev->base_addr + PCNET32_DATA));
+    if (pcnet32_debug > 4)
+       printk("%s: exiting interrupt, csr0=%#4.4x.\n",
+              dev->name, lp->a.read_csr (ioaddr, 0));
 
-       dev->interrupt = 0;
-       return;
+    dev->interrupt = 0;
+    return;
 }
 
 static int
 pcnet32_rx(struct device *dev)
 {
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-       int entry = lp->cur_rx & RX_RING_MOD_MASK;
-       int i;
-
-       /* If we own the next entry, it's a new packet. Send it up. */
-       while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
-               int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
-
-               if (status != 0x03) {                   /* There was an error. */
-                       /* There is a tricky error noted by John Murphy,
-                          <murf@perftech.com> to Russ Nelson: Even with full-sized
-                          buffers it's possible for a jabber packet to use two
-                          buffers, with only the last correctly noting the error. */
-                       if (status & 0x01)      /* Only count a general error at the */
-                               lp->stats.rx_errors++; /* end of a packet.*/
-                       if (status & 0x20) lp->stats.rx_frame_errors++;
-                       if (status & 0x10) lp->stats.rx_over_errors++;
-                       if (status & 0x08) lp->stats.rx_crc_errors++;
-                       if (status & 0x04) lp->stats.rx_fifo_errors++;
-                       lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
-               }
-               else 
-               {
-                       /* Malloc up new buffer, compatible with net-2e. */
-                       short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
-                       struct sk_buff *skb;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int entry = lp->cur_rx & RX_RING_MOD_MASK;
+    int i;
+
+    /* If we own the next entry, it's a new packet. Send it up. */
+    while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+       int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+
+       if (status != 0x03) {                   /* There was an error. */
+           /* 
+            * There is a tricky error noted by John Murphy,
+            * <murf@perftech.com> to Russ Nelson: Even with full-sized
+            * buffers it's possible for a jabber packet to use two
+            * buffers, with only the last correctly noting the error.
+            */
+           if (status & 0x01)  /* Only count a general error at the */
+               lp->stats.rx_errors++; /* end of a packet.*/
+           if (status & 0x20) lp->stats.rx_frame_errors++;
+           if (status & 0x10) lp->stats.rx_over_errors++;
+           if (status & 0x08) lp->stats.rx_crc_errors++;
+           if (status & 0x04) lp->stats.rx_fifo_errors++;
+           lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+       } else {
+           /* Malloc up new buffer, compatible with net-2e. */
+           short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
+           struct sk_buff *skb;
                        
-                       if(pkt_len < 60) {
-                               printk("%s: Runt packet!\n",dev->name);
-                               lp->stats.rx_errors++;
-                       } else {
-                           int rx_in_place = 0;
+           if(pkt_len < 60) {
+               printk("%s: Runt packet!\n",dev->name);
+               lp->stats.rx_errors++;
+           } else {
+               int rx_in_place = 0;
                            
-                           if (pkt_len > rx_copybreak) {
-                               struct sk_buff *newskb;
+               if (pkt_len > rx_copybreak) {
+                   struct sk_buff *newskb;
                                
-                               if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
-                                   skb_reserve (newskb, 2);
-                                   skb = lp->rx_skbuff[entry];
-                                   skb_put (skb, pkt_len);
-                                   lp->rx_skbuff[entry] = newskb;
-                                   newskb->dev = dev;
-                                   lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
-                                   rx_in_place = 1;
-                               } else
-                                   skb = NULL;
-                           } else
-                               skb = dev_alloc_skb(pkt_len+2);
+                   if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
+                       skb_reserve (newskb, 2);
+                       skb = lp->rx_skbuff[entry];
+                       skb_put (skb, pkt_len);
+                       lp->rx_skbuff[entry] = newskb;
+                       newskb->dev = dev;
+                       lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
+                       rx_in_place = 1;
+                   } else
+                       skb = NULL;
+               } else
+                   skb = dev_alloc_skb(pkt_len+2);
                            
-                           if (skb == NULL) {
-                               printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-                               for (i=0; i < RX_RING_SIZE; i++)
-                                   if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
-                                       break;
-
-                               if (i > RX_RING_SIZE -2) {
-                                   lp->stats.rx_dropped++;
-                                   lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
-                                   lp->cur_rx++;
-                               }
-                               break;
-                           }
-                           skb->dev = dev;
-                           if (!rx_in_place) {
-                               skb_reserve(skb,2);     /* 16 byte align */
-                               skb_put(skb,pkt_len);   /* Make room */
-                               eth_copy_and_sum(skb,
-                                       (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
-                                       pkt_len,0);
-                           }
-                           lp->stats.rx_bytes += skb->len;
-                           skb->protocol=eth_type_trans(skb,dev);
-                           netif_rx(skb);
-                           lp->stats.rx_packets++;
-                       }
+               if (skb == NULL) {
+                   printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+                   for (i=0; i < RX_RING_SIZE; i++)
+                       if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
+                           break;
+
+                   if (i > RX_RING_SIZE -2) {
+                       lp->stats.rx_dropped++;
+                       lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+                       lp->cur_rx++;
+                   }
+                   break;
+               }
+               skb->dev = dev;
+               if (!rx_in_place) {
+                   skb_reserve(skb,2); /* 16 byte align */
+                   skb_put(skb,pkt_len);       /* Make room */
+                   eth_copy_and_sum(skb,
+                                    (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
+                                    pkt_len,0);
                }
-               /* The docs say that the buffer length isn't touched, but Andrew Boyd
-                  of QNX reports that some revs of the 79C965 clear it. */
-               lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
-               lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
-               entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+               lp->stats.rx_bytes += skb->len;
+               skb->protocol=eth_type_trans(skb,dev);
+               netif_rx(skb);
+               lp->stats.rx_packets++;
+           }
        }
+       /*
+        * The docs say that the buffer length isn't touched, but Andrew Boyd
+        * of QNX reports that some revs of the 79C965 clear it.
+        */
+       lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+       lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+       entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+    }
 
-       /* We should check that at least two ring entries are free.      If not,
-          we should free one and mark stats->rx_dropped++. */
-
-       return 0;
+    return 0;
 }
 
 static int
 pcnet32_close(struct device *dev)
 {
-       unsigned int ioaddr = dev->base_addr;
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-        int i;
+    unsigned long ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int i;
 
-       dev->start = 0;
-       set_bit (0, (void *)&dev->tbusy);
+    dev->start = 0;
+    set_bit (0, (void *)&dev->tbusy);
 
-       outw(112, ioaddr+PCNET32_ADDR);
-       lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
+    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
 
-       outw(0, ioaddr+PCNET32_ADDR);
+    if (pcnet32_debug > 1)
+       printk("%s: Shutting down ethercard, status was %2.2x.\n",
+              dev->name, lp->a.read_csr (ioaddr, 0));
 
-       if (pcnet32_debug > 1)
-               printk("%s: Shutting down ethercard, status was %2.2x.\n",
-                          dev->name, inw(ioaddr+PCNET32_DATA));
+    /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
+    lp->a.write_csr (ioaddr, 0, 0x0004);
 
-       /* We stop the PCNET32 here -- it occasionally polls
-          memory if we don't. */
-       outw(0x0004, ioaddr+PCNET32_DATA);
+    /*
+     * Switch back to 16bit mode to avoid problems with dumb 
+     * DOS packet driver after a warm reboot
+     */
+    lp->a.write_bcr (ioaddr, 20, 4);
 
-       free_irq(dev->irq, dev);
+    free_irq(dev->irq, dev);
     
-        /* free all allocated skbuffs */
-        for (i = 0; i < RX_RING_SIZE; i++) {
-           lp->rx_ring[i].status = 0;                      
-           if (lp->rx_skbuff[i])
-               dev_kfree_skb(lp->rx_skbuff[i]);
-           lp->rx_skbuff[i] = NULL;
-       }
+    /* free all allocated skbuffs */
+    for (i = 0; i < RX_RING_SIZE; i++) {
+       lp->rx_ring[i].status = 0;                          
+       if (lp->rx_skbuff[i])
+           dev_kfree_skb(lp->rx_skbuff[i]);
+       lp->rx_skbuff[i] = NULL;
+    }
     
-        for (i = 0; i < TX_RING_SIZE; i++) {
-           if (lp->tx_skbuff[i])
-               dev_kfree_skb(lp->tx_skbuff[i]);
-           lp->rx_skbuff[i] = NULL;
-       }
+    for (i = 0; i < TX_RING_SIZE; i++) {
+       if (lp->tx_skbuff[i])
+           dev_kfree_skb(lp->tx_skbuff[i]);
+       lp->rx_skbuff[i] = NULL;
+    }
     
-        MOD_DEC_USE_COUNT;
+    MOD_DEC_USE_COUNT;
 
-       return 0;
+    return 0;
 }
 
 static struct net_device_stats *
 pcnet32_get_stats(struct device *dev)
 {
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-       unsigned int ioaddr = dev->base_addr;
-       unsigned short saved_addr;
-       unsigned long flags;
-
-       save_flags(flags);
-       cli();
-       saved_addr = inw(ioaddr+PCNET32_ADDR);
-       outw(112, ioaddr+PCNET32_ADDR);
-       lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
-       outw(saved_addr, ioaddr+PCNET32_ADDR);
-       restore_flags(flags);
-
-       return &lp->stats;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    u16 saved_addr;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    saved_addr = lp->a.read_rap(ioaddr);
+    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
+    lp->a.write_rap(ioaddr, saved_addr);
+    restore_flags(flags);
+
+    return &lp->stats;
 }
 
-
 /* taken from the sunlance driver, which it took from the depca driver */
 static void pcnet32_load_multicast (struct device *dev)
 {
@@ -1044,34 +1283,68 @@ static void pcnet32_load_multicast (struct device *dev)
 }
 
 
-/* Set or clear the multicast filter for this adaptor.
+/*
+ * Set or clear the multicast filter for this adaptor.
  */
-
 static void pcnet32_set_multicast_list(struct device *dev)
 {
-       unsigned int ioaddr = dev->base_addr;
-       struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
-
-       if (dev->flags&IFF_PROMISC) {
-               /* Log any net taps. */
-               printk("%s: Promiscuous mode enabled.\n", dev->name);
-               lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
-       } else {
-               lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
-               pcnet32_load_multicast (dev);
-       }
+    unsigned long ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+
+    if (dev->flags&IFF_PROMISC) {
+       /* Log any net taps. */
+       printk("%s: Promiscuous mode enabled.\n", dev->name);
+       lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
+    } else {
+       lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
+       pcnet32_load_multicast (dev);
+    }
     
-       outw(0, ioaddr+PCNET32_ADDR);
-       outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance.        */
+    lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
 
-       pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
+    pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
+static int pcnet32_mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+    unsigned long ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    u16 *data = (u16 *)&rq->ifr_data;
+    int phyaddr = lp->a.read_bcr (ioaddr, 33);
+
+    if (lp->mii) {
+       switch(cmd) {
+        case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
+           data[0] = (phyaddr >> 5) & 0x1f;
+           /* Fall Through */
+        case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+           lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
+           data[3] = lp->a.read_bcr (ioaddr, 34);
+           lp->a.write_bcr (ioaddr, 33, phyaddr);
+           return 0;
+        case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+           if (!suser())
+               return -EPERM;
+           lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
+           lp->a.write_bcr (ioaddr, 34, data[2]);
+           lp->a.write_bcr (ioaddr, 33, phyaddr);
+           return 0;
+        default:
+           return -EOPNOTSUPP;
+       }
+    }
+    return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+                                           
 #ifdef MODULE
 MODULE_PARM(debug, "i");
-MODULE_PARM(options, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+                                            
 
 /* An additional parameter that may be passed in... */
 static int debug = -1;
@@ -1079,27 +1352,27 @@ static int debug = -1;
 int
 init_module(void)
 {
-        if (debug > 0)
-               pcnet32_debug = debug;
+    if (debug > 0)
+       pcnet32_debug = debug;
     
-       pcnet32_dev = NULL;
-       return pcnet32_probe(NULL);
+    pcnet32_dev = NULL;
+    return pcnet32_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-       struct device *next_dev;
-
-       /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-       while (pcnet32_dev) {
-               next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
-               unregister_netdev(pcnet32_dev);
-               release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-               kfree(pcnet32_dev->priv);
-               kfree(pcnet32_dev);
-               pcnet32_dev = next_dev;
-       }
+    struct device *next_dev;
+
+    /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+    while (pcnet32_dev) {
+       next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
+       unregister_netdev(pcnet32_dev);
+       release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
+       kfree(((struct pcnet32_private *)pcnet32_dev->priv)->origmem);
+       kfree(pcnet32_dev);
+       pcnet32_dev = next_dev;
+    }
 }
 #endif /* MODULE */
 
index 9b175bffaa062a2a078e26ea6453dc19bb68640a..4016cf60fdd56b2602ec593534bdcba8957cf429 100644 (file)
  * stack will need to know about I/O vectors or something similar.
  */
 
-static const char *version = "rrunner.c: v0.09 12/14/98  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
-
-static unsigned int read_eeprom(struct rr_private *rrpriv,
-                               unsigned long offset,
-                               unsigned char *buf,
-                               unsigned long length);
-static u32 read_eeprom_word(struct rr_private *rrpriv,
-                           void * offset);
-static int rr_load_firmware(struct device *dev);
+static const char __initdata *version = "rrunner.c: v0.17 03/09/99  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
 
 
 /*
@@ -78,44 +70,32 @@ static int rr_load_firmware(struct device *dev);
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
 
+static int probed __initdata = 0;
+
 __initfunc(int rr_hippi_probe (struct device *dev))
 {
-       static int i = 0;
        int boards_found = 0;
        int version_disp;       /* was version info already displayed? */
-       u8 pci_bus;             /* PCI bus number (0-255) */
-       u8 pci_dev_fun;         /* PCI device and function numbers (0-255) */
+       struct pci_dev *pdev = NULL;
+       struct pci_dev *opdev = NULL;
        u8 pci_latency;
-       u16 command;            /* PCI Configuration space Command register */
-       unsigned int tmp;
-       u8 irq;
        struct rr_private *rrpriv;
 
+       if (probed)
+               return -ENODEV;
+       probed++;
+
        if (!pci_present())             /* is PCI BIOS even present? */
                return -ENODEV;
 
        version_disp = 0;
 
-       for (; i < 255; i++)
+       while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL,
+                                     PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
+                                     pdev)))
        {
-               if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL,
-                                       PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
-                                       i, &pci_bus, &pci_dev_fun) != 0)
-                       break;
-
-               pcibios_read_config_word(pci_bus, pci_dev_fun,
-                                        PCI_COMMAND, &command);
-
-               /* Enable mastering */
-
-               command |= PCI_COMMAND_MASTER;
-               pcibios_write_config_word(pci_bus, pci_dev_fun,
-                                         PCI_COMMAND, command);
-
-               if (!(command & PCI_COMMAND_MEMORY)){
-                       printk("shared mem not enabled - unable to configure RoadRunner\n");
-                       break;
-               }
+               if (pdev == opdev)
+                       return 0;
 
                /*
                 * So we found our HIPPI ... time to tell the system.
@@ -123,31 +103,24 @@ __initfunc(int rr_hippi_probe (struct device *dev))
 
                dev = init_hippi_dev(dev, sizeof(struct rr_private));
 
-               if (dev == NULL)
+               if (!dev)
                        break;
 
                if (!dev->priv)
                        dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL);
 
-               rrpriv = (struct rr_private *)dev->priv;
-
-               /* Read register base address from
-                  PCI Configuration Space */
-
-               pcibios_read_config_dword(pci_bus, pci_dev_fun,
-                                         PCI_BASE_ADDRESS_0, &tmp);
+               if (!dev->priv)
+                       return -ENOMEM;
 
-               pcibios_read_config_byte(pci_bus, pci_dev_fun,
-                                        PCI_INTERRUPT_LINE, &irq);
+               rrpriv = (struct rr_private *)dev->priv;
+               memset(rrpriv, 0, sizeof(*rrpriv));
 
-               dev->irq = irq;
-               rrpriv->pci_bus = pci_bus;
-               rrpriv->pci_dev_fun = pci_dev_fun;
-               sprintf(rrpriv->name, "RoadRunner serial HIPPI");
 #ifdef __SMP__
                spin_lock_init(&rrpriv->lock);
 #endif
+               sprintf(rrpriv->name, "RoadRunner serial HIPPI");
 
+               dev->irq = pdev->irq;
                dev->open = &rr_open;
                dev->hard_start_xmit = &rr_start_xmit;
                dev->stop = &rr_close;
@@ -168,29 +141,30 @@ __initfunc(int rr_hippi_probe (struct device *dev))
                        printk(version);
                }
 
-               printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n",
-                      dev->name, tmp, dev->irq);
-
-               pcibios_read_config_byte(pci_bus, pci_dev_fun,
-                                        PCI_LATENCY_TIMER, &pci_latency);
-#if 0
-               if (pci_latency <= 48){
-                       printk("  PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency);
-                       pcibios_write_config_byte(pci_bus, pci_dev_fun,
-                                                 PCI_LATENCY_TIMER, 48);
+               pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+               if (pci_latency <= 0x58){
+                       pci_latency = 0x58;
+                       pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+                                             pci_latency);
                }
-#else
-               if (pci_latency <= 0x58)
-                       pcibios_write_config_byte(pci_bus, pci_dev_fun,
-                                                 PCI_LATENCY_TIMER, 0x58);
-#endif
+
+               pci_set_master(pdev);
+
+               printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "
+                      "at 0x%08lx, irq %i, PCI latency %i\n", dev->name,
+                      pdev->base_address[0], dev->irq, pci_latency);
+
                /*
                 * Remap the regs into kernel space.
                 */
 
-               rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000);
+               rrpriv->regs = (struct rr_regs *)
+                       ioremap(pdev->base_address[0], 0x1000);
+
                if (!rrpriv->regs){
-                       printk(KERN_ERR "%s:  Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i);
+                       printk(KERN_ERR "%s:  Unable to map I/O register, "
+                              "RoadRunner %i will be disabled.\n",
+                              dev->name, boards_found);
                        break;
                }
 
@@ -198,7 +172,7 @@ __initfunc(int rr_hippi_probe (struct device *dev))
                 * Don't access any registes before this point!
                 */
 #ifdef __BIG_ENDIAN
-               regs->HostCtrl |= NO_SWAP;
+               writel(readl(&regs->HostCtrl) | NO_SWAP, &regs->HostCtrl);
 #endif
                /*
                 * Need to add a case for little-endian 64-bit hosts here.
@@ -209,6 +183,7 @@ __initfunc(int rr_hippi_probe (struct device *dev))
                boards_found++;
                dev->base_addr = 0;
                dev = NULL;
+               opdev = pdev;
        }
 
        /*
@@ -217,12 +192,59 @@ __initfunc(int rr_hippi_probe (struct device *dev))
         * 1 or more boards. Otherwise, return failure (-ENODEV).
         */
 
+#ifdef MODULE
+       return boards_found;
+#else
        if (boards_found > 0)
                return 0;
        else
                return -ENODEV;
+#endif
 }
 
+static struct device *root_dev = NULL;
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
+MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver");
+#endif
+
+
+int init_module(void)
+{
+       int cards;
+
+       root_dev = NULL;
+
+       cards = rr_hippi_probe(NULL);
+       return cards ? 0 : -ENODEV;
+}
+
+void cleanup_module(void)
+{
+       struct rr_private *rr;
+       struct device *next;
+
+       while (root_dev) {
+               next = ((struct rr_private *)root_dev->priv)->next;
+               rr = (struct rr_private *)root_dev->priv;
+
+               if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){
+                       printk(KERN_ERR "%s: trying to unload running NIC\n",
+                              root_dev->name);
+                       writel(HALT_NIC, &rr->regs->HostCtrl);
+               }
+
+               iounmap(rr->regs);
+               unregister_hipdev(root_dev);
+               kfree(root_dev);
+
+               root_dev = next;
+       }
+}
+#endif
+
 
 /*
  * Commands are considered to be slow, thus there is no reason to
@@ -238,21 +260,25 @@ static void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd)
         * This is temporary - it will go away in the final version.
         * We probably also want to make this function inline.
         */
-       if (regs->HostCtrl & NIC_HALTED){
-               printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl);
-               if (regs->Mode & FATAL_ERR)
-                       printk("error code %02x\n", regs->Fail1);
+       if (readl(&regs->HostCtrl) & NIC_HALTED){
+               printk("issuing command for halted NIC, code 0x%x, "
+                      "HostCtrl %08x\n", cmd->code, readl(&regs->HostCtrl));
+               if (readl(&regs->Mode) & FATAL_ERR)
+                       printk("error codes Fail1 %02x, Fail2 %02x\n",
+                              readl(&regs->Fail1), readl(&regs->Fail2));
        }
 
        idx = rrpriv->info->cmd_ctrl.pi;
 
-       regs->CmdRing[idx] = *(u32*)(cmd);
+       writel(*(u32*)(cmd), &regs->CmdRing[idx]);
+       mb();
 
        idx = (idx - 1) % CMD_RING_ENTRIES;
        rrpriv->info->cmd_ctrl.pi = idx;
+       mb();
 
-       if (regs->Mode & FATAL_ERR)
-               printk("error code %02x\n", regs->Fail1);
+       if (readl(&regs->Mode) & FATAL_ERR)
+               printk("error code %02x\n", readl(&regs->Fail1));
 }
 
 
@@ -273,85 +299,97 @@ static int rr_reset(struct device *dev)
 
        rr_load_firmware(dev);
 
-       regs->TX_state = 0x01000000;
-       regs->RX_state = 0xff800000;
-       regs->AssistState = 0;
-       regs->LocalCtrl = CLEAR_INTA;
-       regs->BrkPt = 0x01;
-       regs->Timer = 0;
-       regs->TimerRef = 0;
-       regs->DmaReadState = RESET_DMA;
-       regs->DmaWriteState = RESET_DMA;
-       regs->DmaWriteHostHi = 0;
-       regs->DmaWriteHostLo = 0;
-       regs->DmaReadHostHi = 0;
-       regs->DmaReadHostLo = 0;
-       regs->DmaReadLen = 0;
-       regs->DmaWriteLen = 0;
-       regs->DmaWriteLcl = 0;
-       regs->DmaWriteIPchecksum = 0;
-       regs->DmaReadLcl = 0;
-       regs->DmaReadIPchecksum = 0;
-       regs->PciState = 0; /* 0x90 for GE? */
-       regs->Mode = SWAP_DATA;
+       writel(0x01000000, &regs->TX_state);
+       writel(0xff800000, &regs->RX_state);
+       writel(0, &regs->AssistState);
+       writel(CLEAR_INTA, &regs->LocalCtrl);
+       writel(0x01, &regs->BrkPt);
+       writel(0, &regs->Timer);
+       writel(0, &regs->TimerRef);
+       writel(RESET_DMA, &regs->DmaReadState);
+       writel(RESET_DMA, &regs->DmaWriteState);
+       writel(0, &regs->DmaWriteHostHi);
+       writel(0, &regs->DmaWriteHostLo);
+       writel(0, &regs->DmaReadHostHi);
+       writel(0, &regs->DmaReadHostLo);
+       writel(0, &regs->DmaReadLen);
+       writel(0, &regs->DmaWriteLen);
+       writel(0, &regs->DmaWriteLcl);
+       writel(0, &regs->DmaWriteIPchecksum);
+       writel(0, &regs->DmaReadLcl);
+       writel(0, &regs->DmaReadIPchecksum);
+       writel(0, &regs->PciState);
+#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN
+       writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, &regs->Mode);
+#elif (BITS_PER_LONG == 64)
+       writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, &regs->Mode);
+#else
+       writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, &regs->Mode);
+#endif
 
 #if 0
        /*
         * Don't worry, this is just black magic.
         */
-       regs->RxBase = 0xdf000;
-       regs->RxPrd = 0xdf000;
-       regs->RxCon = 0xdf000;
-       regs->TxBase = 0xce000;
-       regs->TxPrd = 0xce000;
-       regs->TxCon = 0xce000;
-       regs->RxIndPro = 0;
-       regs->RxIndCon = 0;
-       regs->RxIndRef = 0;
-       regs->TxIndPro = 0;
-       regs->TxIndCon = 0;
-       regs->TxIndRef = 0;
-       regs->pad10[0] = 0xcc000;
-       regs->DrCmndPro = 0;
-       regs->DrCmndCon = 0;
-       regs->DwCmndPro = 0;
-       regs->DwCmndCon = 0;
-       regs->DwCmndRef = 0;
-       regs->DrDataPro = 0;
-       regs->DrDataCon = 0;
-       regs->DrDataRef = 0;
-       regs->DwDataPro = 0;
-       regs->DwDataCon = 0;
-       regs->DwDataRef = 0;
+       writel(0xdf000, &regs->RxBase);
+       writel(0xdf000, &regs->RxPrd);
+       writel(0xdf000, &regs->RxCon);
+       writel(0xce000, &regs->TxBase);
+       writel(0xce000, &regs->TxPrd);
+       writel(0xce000, &regs->TxCon);
+       writel(0, &regs->RxIndPro);
+       writel(0, &regs->RxIndCon);
+       writel(0, &regs->RxIndRef);
+       writel(0, &regs->TxIndPro);
+       writel(0, &regs->TxIndCon);
+       writel(0, &regs->TxIndRef);
+       writel(0xcc000, &regs->pad10[0]);
+       writel(0, &regs->DrCmndPro);
+       writel(0, &regs->DrCmndCon);
+       writel(0, &regs->DwCmndPro);
+       writel(0, &regs->DwCmndCon);
+       writel(0, &regs->DwCmndRef);
+       writel(0, &regs->DrDataPro);
+       writel(0, &regs->DrDataCon);
+       writel(0, &regs->DrDataRef);
+       writel(0, &regs->DwDataPro);
+       writel(0, &regs->DwDataCon);
+       writel(0, &regs->DwDataRef);
 #endif
 
-       regs->MbEvent = 0xffffffff;
-       regs->Event = 0;
+       writel(0xffffffff, &regs->MbEvent);
+       writel(0, &regs->Event);
 
-       regs->TxPi = 0;
-       regs->IpRxPi = 0;
+       writel(0, &regs->TxPi);
+       writel(0, &regs->IpRxPi);
 
-       regs->EvtCon = 0;
-       regs->EvtPrd = 0;
+       writel(0, &regs->EvtCon);
+       writel(0, &regs->EvtPrd);
 
        rrpriv->info->evt_ctrl.pi = 0;
 
        for (i = 0; i < CMD_RING_ENTRIES; i++)
-               regs->CmdRing[i] = 0;
+               writel(0, &regs->CmdRing[i]);
 
-       regs->PciState = 0;
+/*
+ * Why 32 ? is this not cache line size dependant?
+ */
+       writel(WBURST_32, &regs->PciState);
+       mb();
 
-       start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart);
+       start_pc = rr_read_eeprom_word(rrpriv, &hw->rncd_info.FwStart);
 
 #if (DEBUG > 1)
        printk("%s: Executing firmware at address 0x%06x\n",
               dev->name, start_pc);
 #endif
 
-       regs->Pc = start_pc + 0x800;
+       writel(start_pc + 0x800, &regs->Pc);
+       mb();
        udelay(5);
 
-       regs->Pc = start_pc;
+       writel(start_pc, &regs->Pc);
+       mb();
 
        return 0;
 }
@@ -360,7 +398,7 @@ static int rr_reset(struct device *dev)
 /*
  * Read a string from the EEPROM.
  */
-static unsigned int read_eeprom(struct rr_private *rrpriv,
+static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
                                unsigned long offset,
                                unsigned char *buf,
                                unsigned long length)
@@ -368,22 +406,25 @@ static unsigned int read_eeprom(struct rr_private *rrpriv,
        struct rr_regs *regs = rrpriv->regs;
        u32 misc, io, host, i;
 
-       io = regs->ExtIo;
-       regs->ExtIo = 0;
-       misc = regs->LocalCtrl;
-       regs->LocalCtrl = 0;
-       host = regs->HostCtrl;
-       regs->HostCtrl |= HALT_NIC;
+       io = readl(&regs->ExtIo);
+       writel(0, &regs->ExtIo);
+       misc = readl(&regs->LocalCtrl);
+       writel(0, &regs->LocalCtrl);
+       host = readl(&regs->HostCtrl);
+       writel(host | HALT_NIC, &regs->HostCtrl);
+       mb();
 
        for (i = 0; i < length; i++){
-               regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));
-               buf[i] = (regs->WinData >> 24) & 0xff;
+               writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
+               mb();
+               buf[i] = (readl(&regs->WinData) >> 24) & 0xff;
+               mb();
        }
 
-       regs->HostCtrl = host;
-       regs->LocalCtrl = misc;
-       regs->ExtIo = io;
-
+       writel(host, &regs->HostCtrl);
+       writel(misc, &regs->LocalCtrl);
+       writel(io, &regs->ExtIo);
+       mb();
        return i;
 }
 
@@ -392,13 +433,13 @@ static unsigned int read_eeprom(struct rr_private *rrpriv,
  * Shortcut to read one word (4 bytes) out of the EEPROM and convert
  * it to our CPU byte-order.
  */
-static u32 read_eeprom_word(struct rr_private *rrpriv,
+static u32 rr_read_eeprom_word(struct rr_private *rrpriv,
                            void * offset)
 {
        u32 word;
 
-       if ((read_eeprom(rrpriv, (unsigned long)offset,
-                        (char *)&word, 4) == 4))
+       if ((rr_read_eeprom(rrpriv, (unsigned long)offset,
+                           (char *)&word, 4) == 4))
                return be32_to_cpu(word);
        return 0;
 }
@@ -410,38 +451,42 @@ static u32 read_eeprom_word(struct rr_private *rrpriv,
  * This is only called when the firmware is not running.
  */
 static unsigned int write_eeprom(struct rr_private *rrpriv,
-                               unsigned long offset,
-                               unsigned char *buf,
-                               unsigned long length)
+                                unsigned long offset,
+                                unsigned char *buf,
+                                unsigned long length)
 {
        struct rr_regs *regs = rrpriv->regs;
        u32 misc, io, data, i, j, ready, error = 0;
 
-       io = regs->ExtIo;
-       regs->ExtIo = 0;
-       misc = regs->LocalCtrl;
-       regs->LocalCtrl = ENABLE_EEPROM_WRITE;
+       io = readl(&regs->ExtIo);
+       writel(0, &regs->ExtIo);
+       misc = readl(&regs->LocalCtrl);
+       writel(ENABLE_EEPROM_WRITE, &regs->LocalCtrl);
+       mb();
 
        for (i = 0; i < length; i++){
-               regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));
+               writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
+               mb();
                data = buf[i] << 24;
                /*
                 * Only try to write the data if it is not the same
                 * value already.
                 */
-               if ((regs->WinData & 0xff000000) != data){
-                       regs->WinData = data;
+               if ((readl(&regs->WinData) & 0xff000000) != data){
+                       writel(data, &regs->WinData);
                        ready = 0;
                        j = 0;
                        mb();
                        while(!ready){
-                               udelay(1000);
-                               if ((regs->WinData & 0xff000000) == data)
+                               udelay(20);
+                               if ((readl(&regs->WinData) & 0xff000000) ==
+                                   data)
                                        ready = 1;
+                               mb();
                                if (j++ > 5000){
                                        printk("data mismatch: %08x, "
                                               "WinData %08x\n", data,
-                                              regs->WinData);
+                                              readl(&regs->WinData));
                                        ready = 1;
                                        error = 1;
                                }
@@ -449,8 +494,9 @@ static unsigned int write_eeprom(struct rr_private *rrpriv,
                }
        }
 
-       regs->LocalCtrl = misc;
-       regs->ExtIo = io;
+       writel(misc, &regs->LocalCtrl);
+       writel(io, &regs->ExtIo);
+       mb();
 
        return error;
 }
@@ -465,7 +511,8 @@ __initfunc(static int rr_init(struct device *dev))
        rrpriv = (struct rr_private *)dev->priv;
        regs = rrpriv->regs;
 
-       rev = regs->FwRev;
+       rev = readl(&regs->FwRev);
+       rrpriv->fw_rev = rev;
        if (rev > 0x00020024)
                printk("  Firmware revision: %i.%i.%i\n", (rev >> 16),
                       ((rev >> 8) & 0xff), (rev & 0xff));
@@ -477,13 +524,13 @@ __initfunc(static int rr_init(struct device *dev))
                printk("  Firmware revision too old: %i.%i.%i, please "
                       "upgrade to 2.0.37 or later.\n",
                       (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff));
-               return -EFAULT;
-               
        }
 
-       printk("  Maximum receive rings %i\n", regs->MaxRxRng);
+#if (DEBUG > 2)
+       printk("  Maximum receive rings %i\n", readl(&regs->MaxRxRng));
+#endif
 
-       sram_size = read_eeprom_word(rrpriv, (void *)8);
+       sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
        printk("  SRAM size 0x%06x\n", sram_size);
 
        if (sysctl_rmem_max < 262144){
@@ -498,6 +545,9 @@ __initfunc(static int rr_init(struct device *dev))
                sysctl_wmem_max = 262144;
        }
 
+       rrpriv->next = root_dev;
+       root_dev = dev;
+
        return 0;
 }
 
@@ -507,7 +557,7 @@ static int rr_init1(struct device *dev)
        struct rr_private *rrpriv;
        struct rr_regs *regs;
        u32 hostctrl;
-       unsigned long myjif, flags, tmp_ptr;
+       unsigned long myjif, flags;
        struct cmd cmd;
        short i;
 
@@ -516,8 +566,9 @@ static int rr_init1(struct device *dev)
 
        spin_lock_irqsave(&rrpriv->lock, flags);
 
-       hostctrl = regs->HostCtrl;
-       regs->HostCtrl |= HALT_NIC;
+       hostctrl = readl(&regs->HostCtrl);
+       writel(hostctrl | HALT_NIC | RR_CLEAR_INT, &regs->HostCtrl);
+       mb();
 
        if (hostctrl & PARITY_ERR){
                printk("%s: Parity error halting NIC - this is serious!\n",
@@ -526,31 +577,14 @@ static int rr_init1(struct device *dev)
                return -EFAULT;
        }
 
-
-       memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl));
-       memset(rrpriv->info, 0, sizeof(struct rr_info));
-
-       tmp_ptr = virt_to_bus((void *)rrpriv->rx_ctrl);
-#if (BITS_PER_LONG == 64)
-       regs->RxRingHi = (tmp_ptr >> 32);
-#else
-       regs->RxRingHi = 0;
-#endif
-       regs->RxRingLo = ((tmp_ptr) & 0xffffffff);
-
-       tmp_ptr = virt_to_bus((void *)rrpriv->info);
-#if (BITS_PER_LONG == 64)
-       regs->InfoPtrHi = (tmp_ptr >> 32);
-#else
-       regs->InfoPtrHi = 0;
-#endif
-       regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff);
+       set_rxaddr(regs, rrpriv->rx_ctrl);
+       set_infoaddr(regs, rrpriv->info);
 
        rrpriv->info->evt_ctrl.entry_size = sizeof(struct event);
        rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES;
        rrpriv->info->evt_ctrl.mode = 0;
        rrpriv->info->evt_ctrl.pi = 0;
-       rrpriv->info->evt_ctrl.rngptr = virt_to_bus(rrpriv->evt_ring);
+       set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring);
 
        rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd);
        rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES;
@@ -558,20 +592,19 @@ static int rr_init1(struct device *dev)
        rrpriv->info->cmd_ctrl.pi = 15;
 
        for (i = 0; i < CMD_RING_ENTRIES; i++) {
-               regs->CmdRing[i] = 0;
+               writel(0, &regs->CmdRing[i]);
        }
 
        for (i = 0; i < TX_RING_ENTRIES; i++) {
                rrpriv->tx_ring[i].size = 0;
-               rrpriv->tx_ring[i].addr = 0;
+               set_rraddr(&rrpriv->tx_ring[i].addr, 0);
                rrpriv->tx_skbuff[i] = 0;
        }
-
        rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc);
        rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES;
        rrpriv->info->tx_ctrl.mode = 0;
        rrpriv->info->tx_ctrl.pi = 0;
-       rrpriv->info->tx_ctrl.rngptr = virt_to_bus(rrpriv->tx_ring);
+       set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring);
 
        /*
         * Set dirty_tx before we start receiving interrupts, otherwise
@@ -585,14 +618,20 @@ static int rr_init1(struct device *dev)
 
        rr_reset(dev);
 
-       regs->IntrTmr = 0x60;
-       regs->WriteDmaThresh = 0x80 | 0x1f;
-       regs->ReadDmaThresh = 0x80 | 0x1f;
+       writel(0x60, &regs->IntrTmr);
+       /*
+        * These seem to have no real effect as the Firmware sets
+        * it's own default values
+        */
+       writel(0x10, &regs->WriteDmaThresh);
+       writel(0x20, &regs->ReadDmaThresh);
 
        rrpriv->fw_running = 0;
+       mb();
 
        hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR);
-       regs->HostCtrl = hostctrl;
+       writel(hostctrl, &regs->HostCtrl);
+       mb();
 
        spin_unlock_irqrestore(&rrpriv->lock, flags);
 
@@ -626,10 +665,7 @@ static int rr_init1(struct device *dev)
                if ((((unsigned long)skb->data) & 0xfff) > ~65320)
                        printk("skb alloc error\n");
 
-#if (BITS_PER_LONG == 32)
-               rrpriv->rx_ring[i].zero = 0;
-#endif
-               rrpriv->rx_ring[i].addr = virt_to_bus(skb->data);
+               set_rraddr(&rrpriv->rx_ring[i].addr, skb->data);
                rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN;
        }
 
@@ -637,7 +673,8 @@ static int rr_init1(struct device *dev)
        rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES;
        rrpriv->rx_ctrl[4].mode = 8;
        rrpriv->rx_ctrl[4].pi = 0;
-       rrpriv->rx_ctrl[4].rngptr = virt_to_bus(rrpriv->rx_ring);
+       mb();
+       set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring);
 
        cmd.code = C_NEW_RNG;
        cmd.ring = 4;
@@ -647,18 +684,15 @@ static int rr_init1(struct device *dev)
 #if 0
 {
        u32 tmp;
-       tmp = regs->ExtIo;
-       regs->ExtIo = 0x80;
+       tmp = readl(&regs->ExtIo);
+       writel(0x80, &regs->ExtIo);
        
        i = jiffies + 1 * HZ;
        while (jiffies < i);
-       regs->ExtIo = tmp;
+       writel(tmp, &regs->ExtIo);
 }
 #endif
        dev->tbusy = 0;
-#if 0
-       dev->interrupt = 0;
-#endif
        dev->start = 1;
        return 0;
 }
@@ -669,24 +703,24 @@ static int rr_init1(struct device *dev)
  * events) and are handled here, outside the main interrupt handler,
  * to reduce the size of the handler.
  */
-static u32 rr_handle_event(struct device *dev, u32 prodidx)
+static u32 rr_handle_event(struct device *dev, u32 prodidx, u32 eidx)
 {
        struct rr_private *rrpriv;
        struct rr_regs *regs;
-       u32 tmp, eidx;
+       u32 tmp;
 
        rrpriv = (struct rr_private *)dev->priv;
        regs = rrpriv->regs;
-       eidx = rrpriv->info->evt_ctrl.pi;
 
        while (prodidx != eidx){
                switch (rrpriv->evt_ring[eidx].code){
                case E_NIC_UP:
-                       tmp = regs->FwRev;
+                       tmp = readl(&regs->FwRev);
                        printk("%s: Firmware revision %i.%i.%i up and running\n",
                               dev->name, (tmp >> 16), ((tmp >> 8) & 0xff),
                               (tmp & 0xff));
                        rrpriv->fw_running = 1;
+                       mb();
                        break;
                case E_LINK_ON:
                        printk("%s: Optical link ON\n", dev->name);
@@ -729,7 +763,7 @@ static u32 rr_handle_event(struct device *dev, u32 prodidx)
 #if (DEBUG > 2)
                        printk("%s: RX ring valid event\n", dev->name);
 #endif
-                       regs->IpRxPi = RX_RING_ENTRIES - 1;
+                       writel(RX_RING_ENTRIES - 1, &regs->IpRxPi);
                        break;
                case E_INV_RNG:
                        printk("%s: RX ring invalid event\n", dev->name);
@@ -756,35 +790,24 @@ static u32 rr_handle_event(struct device *dev, u32 prodidx)
        }
 
        rrpriv->info->evt_ctrl.pi = eidx;
+       mb();
        return eidx;
 }
 
 
-static int rx_int(struct device *dev, u32 rxlimit)
+static void rx_int(struct device *dev, u32 rxlimit, u32 index)
 {
        struct rr_private *rrpriv = (struct rr_private *)dev->priv;
-       u32 index, pkt_len;
+       u32 pkt_len;
        struct rr_regs *regs = rrpriv->regs;
 
-       index = rrpriv->cur_rx;
-
-       while(index != rxlimit){
+       do {
                pkt_len = rrpriv->rx_ring[index].size;
 #if (DEBUG > 2)
                printk("index %i, rxlimit %i\n", index, rxlimit);
                printk("len %x, mode %x\n", pkt_len,
                       rrpriv->rx_ring[index].mode);
 #endif
-#if 0
-/*
- * I have never seen this occur
- */
-               if(!(rrpriv->rx_skbuff[index])){
-                       printk("Trying to receive in empty skbuff\n");
-                       goto out;
-               }
-#endif
-
                if (pkt_len > 0){
                        struct sk_buff *skb;
 
@@ -808,7 +831,7 @@ static int rx_int(struct device *dev, u32 rxlimit)
                                        skb = rrpriv->rx_skbuff[index];
                                        skb_put(skb, pkt_len);
                                        rrpriv->rx_skbuff[index] = newskb;
-                                       rrpriv->rx_ring[index].addr = virt_to_bus(newskb->data);
+                                       set_rraddr(&rrpriv->rx_ring[index].addr, newskb->data);
                                }else{
                                        printk("%s: Out of memory, deferring "
                                               "packet\n", dev->name);
@@ -829,13 +852,13 @@ static int rx_int(struct device *dev, u32 rxlimit)
                rrpriv->rx_ring[index].size = dev->mtu + HIPPI_HLEN;
 
                if ((index & 7) == 7)
-                       regs->IpRxPi = index;
+                       writel(index, &regs->IpRxPi);
 
                index = (index + 1) % RX_RING_ENTRIES;
-       }
+       } while(index != rxlimit);
 
        rrpriv->cur_rx = index;
-       return index;
+       mb();
 }
 
 
@@ -844,25 +867,18 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
        struct rr_private *rrpriv;
        struct rr_regs *regs;
        struct device *dev = (struct device *)dev_id;
-       u32 prodidx, eidx, txcsmr, rxlimit, txcon;
+       u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon;
        unsigned long flags;
 
        rrpriv = (struct rr_private *)dev->priv;
        regs = rrpriv->regs;
 
-       if (!(regs->HostCtrl & RR_INT))
+       if (!(readl(&regs->HostCtrl) & RR_INT))
                return;
 
-#if 0
-       if (test_and_set_bit(0, (void*)&dev->interrupt) != 0) {
-               printk("%s: Re-entering the interrupt handler.\n", dev->name);
-               return;
-       }
-#endif
-
        spin_lock_irqsave(&rrpriv->lock, flags);
 
-       prodidx = regs->EvtPrd;
+       prodidx = readl(&regs->EvtPrd);
        txcsmr = (prodidx >> 8) & 0xff;
        rxlimit = (prodidx >> 16) & 0xff;
        prodidx &= 0xff;
@@ -872,6 +888,10 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
               prodidx, rrpriv->info->evt_ctrl.pi);
 #endif
 
+       rxindex = rrpriv->cur_rx;
+       if (rxindex != rxlimit)
+               rx_int(dev, rxlimit, rxindex);
+
        txcon = rrpriv->dirty_tx;
        if (txcsmr != txcon) {
                do {
@@ -881,11 +901,12 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 
                        rrpriv->tx_skbuff[txcon] = NULL;
                        rrpriv->tx_ring[txcon].size = 0;
-                       rrpriv->tx_ring[txcon].addr = 0;
+                       set_rraddr(&rrpriv->tx_ring[txcon].addr, 0);
                        rrpriv->tx_ring[txcon].mode = 0;
 
                        txcon = (txcon + 1) % TX_RING_ENTRIES;
                } while (txcsmr != txcon);
+               mb();
 
                rrpriv->dirty_tx = txcon;
                if (rrpriv->tx_full && dev->tbusy &&
@@ -897,21 +918,15 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
                }
        }
 
-       rx_int(dev, rxlimit);
-
        eidx = rrpriv->info->evt_ctrl.pi;
-
        if (prodidx != eidx)
-               eidx = rr_handle_event(dev, prodidx);
+               eidx = rr_handle_event(dev, prodidx, eidx);
 
        eidx |= ((txcsmr << 8) | (rxlimit << 16));
-       regs->EvtCon = eidx;
+       writel(eidx, &regs->EvtCon);
+       mb();
 
        spin_unlock_irqrestore(&rrpriv->lock, flags);
-
-#if 0
-       dev->interrupt = 0;
-#endif
 }
 
 
@@ -919,35 +934,64 @@ static int rr_open(struct device *dev)
 {
        struct rr_private *rrpriv;
        struct rr_regs *regs;
+       int ecode = 0;
+       unsigned long flags;
 
        rrpriv = (struct rr_private *)dev->priv;
        regs = rrpriv->regs;
 
-#if 0
-       regs->HostCtrl |= (HALT_NIC | RR_CLEAR_INT);
-#endif
+       if (rrpriv->fw_rev < 0x00020000) {
+               printk(KERN_WARNING "%s: trying to configure device with "
+                      "obsolete firmware\n", dev->name);
+               ecode = -EBUSY;
+               goto error;
+       }
+
+       rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl),
+                                 GFP_KERNEL | GFP_DMA);
+       if (!rrpriv->rx_ctrl) {
+               ecode = -ENOMEM;
+               goto error;
+       }
+
+       rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA);
+       if (!rrpriv->info){
+               kfree(rrpriv->rx_ctrl);
+               ecode = -ENOMEM;
+               goto error;
+       }
+       memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl));
+       memset(rrpriv->info, 0, sizeof(struct rr_info));
+       mb();
+
+       spin_lock_irqsave(&rrpriv->lock, flags);
+       writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
+       spin_unlock_irqrestore(&rrpriv->lock, flags);
 
        if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev))
        {
                printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
                       dev->name, dev->irq);
-               return -EAGAIN;
+               ecode = -EAGAIN;
+               goto error;
        }
 
-       rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl),
-                                 GFP_KERNEL | GFP_DMA);
-       rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA);
-
        rr_init1(dev);
 
        dev->tbusy = 0;
-#if 0
-       dev->interrupt = 0;
-#endif
        dev->start = 1;
 
        MOD_INC_USE_COUNT;
        return 0;
+
+ error:
+       spin_lock_irqsave(&rrpriv->lock, flags);
+       writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
+       spin_unlock_irqrestore(&rrpriv->lock, flags);
+
+       dev->tbusy = 1;
+       dev->start = 0;
+       return -ENOMEM;
 }
 
 
@@ -965,12 +1009,13 @@ static void rr_dump(struct device *dev)
        printk("%s: dumping NIC TX rings\n", dev->name);
 
        printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n",
-              regs->RxPrd, regs->TxPrd, regs->EvtPrd, regs->TxPi,
+              readl(&regs->RxPrd), readl(&regs->TxPrd),
+              readl(&regs->EvtPrd), readl(&regs->TxPi),
               rrpriv->info->tx_ctrl.pi);
 
-       printk("Error code 0x%x\n", regs->Fail1);
+       printk("Error code 0x%x\n", readl(&regs->Fail1));
 
-       index = (((regs->EvtPrd >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES;
+       index = (((readl(&regs->EvtPrd) >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES;
        cons = rrpriv->dirty_tx;
        printk("TX ring index %i, TX consumer %i\n",
               index, cons);
@@ -989,12 +1034,12 @@ static void rr_dump(struct device *dev)
        if (rrpriv->tx_skbuff[cons]){
                len = min(0x80, rrpriv->tx_skbuff[cons]->len);
                printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len);
-               printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08x), skbuff-addr %08x, truesize 0x%x\n",
+               printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n",
                       rrpriv->tx_ring[cons].mode,
                       rrpriv->tx_ring[cons].size,
-                      rrpriv->tx_ring[cons].addr,
-                      (unsigned int)bus_to_virt(rrpriv->tx_ring[cons].addr),
-                      (unsigned int)rrpriv->tx_skbuff[cons]->data,
+                      rrpriv->tx_ring[cons].addr.addrlo,
+                      (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo),
+                      (unsigned long)rrpriv->tx_skbuff[cons]->data,
                       (unsigned int)rrpriv->tx_skbuff[cons]->truesize);
                for (i = 0; i < len; i++){
                        if (!(i & 7))
@@ -1009,7 +1054,7 @@ static void rr_dump(struct device *dev)
                printk("mode 0x%x, size 0x%x, phys-addr %08x\n",
                       rrpriv->tx_ring[i].mode,
                       rrpriv->tx_ring[i].size,
-                      rrpriv->tx_ring[i].addr);
+                      rrpriv->tx_ring[i].addr.addrlo);
 
 }
 
@@ -1033,24 +1078,26 @@ static int rr_close(struct device *dev)
         */
        spin_lock(&rrpriv->lock);
 
-       tmp = regs->HostCtrl;
+       tmp = readl(&regs->HostCtrl);
        if (tmp & NIC_HALTED){
                printk("%s: NIC already halted\n", dev->name);
                rr_dump(dev);
-       }else
-               tmp |= HALT_NIC;
-       regs->HostCtrl = tmp;
+       }else{
+               tmp |= HALT_NIC | RR_CLEAR_INT;
+               writel(tmp, &regs->HostCtrl);
+               mb();
+       }
 
        rrpriv->fw_running = 0;
 
-       regs->TxPi = 0;
-       regs->IpRxPi = 0;
+       writel(0, &regs->TxPi);
+       writel(0, &regs->IpRxPi);
 
-       regs->EvtCon = 0;
-       regs->EvtPrd = 0;
+       writel(0, &regs->EvtCon);
+       writel(0, &regs->EvtPrd);
 
        for (i = 0; i < CMD_RING_ENTRIES; i++)
-               regs->CmdRing[i] = 0;
+               writel(0, &regs->CmdRing[i]);
 
        rrpriv->info->tx_ctrl.entries = 0;
        rrpriv->info->cmd_ctrl.pi = 0;
@@ -1060,7 +1107,7 @@ static int rr_close(struct device *dev)
        for (i = 0; i < TX_RING_ENTRIES; i++) {
                if (rrpriv->tx_skbuff[i]) {
                        rrpriv->tx_ring[i].size = 0;
-                       rrpriv->tx_ring[i].addr = 0;
+                       set_rraddr(&rrpriv->tx_ring[i].addr, 0);
                        dev_kfree_skb(rrpriv->tx_skbuff[i]);
                }
        }
@@ -1068,7 +1115,7 @@ static int rr_close(struct device *dev)
        for (i = 0; i < RX_RING_ENTRIES; i++) {
                if (rrpriv->rx_skbuff[i]) {
                        rrpriv->rx_ring[i].size = 0;
-                       rrpriv->rx_ring[i].addr = 0;
+                       set_rraddr(&rrpriv->rx_ring[i].addr, 0);
                        dev_kfree_skb(rrpriv->rx_skbuff[i]);
                }
        }
@@ -1094,6 +1141,10 @@ static int rr_start_xmit(struct sk_buff *skb, struct device *dev)
        u32 *ifield;
        struct sk_buff *new_skb;
 
+       if (readl(&regs->Mode) & FATAL_ERR)
+               printk("error codes Fail1 %02x, Fail2 %02x\n",
+                      readl(&regs->Fail1), readl(&regs->Fail2));
+
        /*
         * We probably need to deal with tbusy here to prevent overruns.
         */
@@ -1128,11 +1179,11 @@ static int rr_start_xmit(struct sk_buff *skb, struct device *dev)
        index = txctrl->pi;
 
        rrpriv->tx_skbuff[index] = skb;
-       rrpriv->tx_ring[index].addr = virt_to_bus(skb->data);
+       set_rraddr(&rrpriv->tx_ring[index].addr, skb->data);
        rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */
        rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END;
        txctrl->pi = (index + 1) % TX_RING_ENTRIES;
-       regs->TxPi = txctrl->pi;
+       writel(txctrl->pi, &regs->TxPi);
 
        if (txctrl->pi == rrpriv->dirty_tx){
                rrpriv->tx_full = 1;
@@ -1167,8 +1218,9 @@ static int rr_load_firmware(struct device *dev)
 {
        struct rr_private *rrpriv;
        struct rr_regs *regs;
+       unsigned long eptr, segptr;
        int i, j;
-       u32 localctrl, eptr, sptr, segptr, len, tmp;
+       u32 localctrl, sptr, len, tmp;
        u32 p2len, p2size, nr_seg, revision, io, sram_size;
        struct eeprom *hw = NULL;
 
@@ -1178,40 +1230,44 @@ static int rr_load_firmware(struct device *dev)
        if (dev->flags & IFF_UP)
                return -EBUSY;
 
-       if (!(regs->HostCtrl & NIC_HALTED)){
+       if (!(readl(&regs->HostCtrl) & NIC_HALTED)){
                printk("%s: Trying to load firmware to a running NIC.\n", 
                       dev->name);
                return -EBUSY;
        }
 
-       localctrl = regs->LocalCtrl;
-       regs->LocalCtrl = 0;
+       localctrl = readl(&regs->LocalCtrl);
+       writel(0, &regs->LocalCtrl);
 
-       regs->EvtPrd = 0;
-       regs->RxPrd = 0;
-       regs->TxPrd = 0;
+       writel(0, &regs->EvtPrd);
+       writel(0, &regs->RxPrd);
+       writel(0, &regs->TxPrd);
 
        /*
         * First wipe the entire SRAM, otherwise we might run into all
         * kinds of trouble ... sigh, this took almost all afternoon
         * to track down ;-(
         */
-       io = regs->ExtIo;
-       regs->ExtIo = 0;
-       sram_size = read_eeprom_word(rrpriv, (void *)8);
+       io = readl(&regs->ExtIo);
+       writel(0, &regs->ExtIo);
+       sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
 
        for (i = 200; i < sram_size / 4; i++){
-               regs->WinBase = i * 4;
-               regs->WinData = 0;
+               writel(i * 4, &regs->WinBase);
+               mb();
+               writel(0, &regs->WinData);
+               mb();
        }
-       regs->ExtIo = io;
+       writel(io, &regs->ExtIo);
+       mb();
 
-       eptr = read_eeprom_word(rrpriv, &hw->rncd_info.AddrRunCodeSegs);
+       eptr = (unsigned long)rr_read_eeprom_word(rrpriv,
+                                              &hw->rncd_info.AddrRunCodeSegs);
        eptr = ((eptr & 0x1fffff) >> 3);
 
-       p2len = read_eeprom_word(rrpriv, (void *)(0x83*4));
+       p2len = rr_read_eeprom_word(rrpriv, (void *)(0x83*4));
        p2len = (p2len << 2);
-       p2size = read_eeprom_word(rrpriv, (void *)(0x84*4));
+       p2size = rr_read_eeprom_word(rrpriv, (void *)(0x84*4));
        p2size = ((p2size & 0x1fffff) >> 3);
 
        if ((eptr < p2size) || (eptr > (p2size + p2len))){
@@ -1219,7 +1275,7 @@ static int rr_load_firmware(struct device *dev)
                goto out;
        }
 
-       revision = read_eeprom_word(rrpriv, &hw->manf.HeaderFmt);
+       revision = rr_read_eeprom_word(rrpriv, &hw->manf.HeaderFmt);
 
        if (revision != 1){
                printk("%s: invalid firmware format (%i)\n",
@@ -1227,18 +1283,18 @@ static int rr_load_firmware(struct device *dev)
                goto out;
        }
 
-       nr_seg = read_eeprom_word(rrpriv, (void *)eptr);
+       nr_seg = rr_read_eeprom_word(rrpriv, (void *)eptr);
        eptr +=4;
 #if (DEBUG > 1)
        printk("%s: nr_seg %i\n", dev->name, nr_seg);
 #endif
 
        for (i = 0; i < nr_seg; i++){
-               sptr = read_eeprom_word(rrpriv, (void *)eptr);
+               sptr = rr_read_eeprom_word(rrpriv, (void *)eptr);
                eptr += 4;
-               len = read_eeprom_word(rrpriv, (void *)eptr);
+               len = rr_read_eeprom_word(rrpriv, (void *)eptr);
                eptr += 4;
-               segptr = read_eeprom_word(rrpriv, (void *)eptr);
+               segptr = (unsigned long)rr_read_eeprom_word(rrpriv, (void *)eptr);
                segptr = ((segptr & 0x1fffff) >> 3);
                eptr += 4;
 #if (DEBUG > 1)
@@ -1246,16 +1302,19 @@ static int rr_load_firmware(struct device *dev)
                       dev->name, i, sptr, len, segptr);
 #endif
                for (j = 0; j < len; j++){
-                       tmp = read_eeprom_word(rrpriv, (void *)segptr);
-                       regs->WinBase = sptr;
-                       regs->WinData = tmp;
+                       tmp = rr_read_eeprom_word(rrpriv, (void *)segptr);
+                       writel(sptr, &regs->WinBase);
+                       mb();
+                       writel(tmp, &regs->WinData);
+                       mb();
                        segptr += 4;
                        sptr += 4;
                }
        }
 
 out:
-       regs->LocalCtrl = localctrl;
+       writel(localctrl, &regs->LocalCtrl);
+       mb();
        return 0;
 }
 
@@ -1291,7 +1350,7 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                        error = -ENOMEM;
                        goto out;
                }
-               i = read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
+               i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
                if (i != EEPROM_BYTES){
                        kfree(image);
                        printk(KERN_ERR "%s: Error reading EEPROM\n",
@@ -1325,7 +1384,7 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                }
 
                oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
-               if (!image){
+               if (!oldimage){
                        printk(KERN_ERR "%s: Unable to allocate memory "
                               "for old EEPROM image\n", dev->name);
                        error = -ENOMEM;
@@ -1343,7 +1402,7 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                        printk(KERN_ERR "%s: Error writing EEPROM\n",
                               dev->name);
 
-               i = read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
+               i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
                if (i != EEPROM_BYTES)
                        printk(KERN_ERR "%s: Error reading back EEPROM "
                               "image\n", dev->name);
@@ -1354,7 +1413,6 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd)
                               dev->name);
                        error = -EFAULT;
                }
-
                kfree(image);
                kfree(oldimage);
                break;
@@ -1374,6 +1432,6 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd)
 
 /*
  * Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
  * End:
  */
index d475137007c9af087d797ed9ca2248c7106ba0cf..e274efa3919e1bed810eae2408a071148802c2dd 100644 (file)
@@ -278,7 +278,6 @@ struct rr_regs {
 #define TRACE_ON_WHAT_BIT      0x00020000    /* Traces on */
 #define ONEM_BUF_WHAT_BIT      0x00040000    /* 1Meg vs 256K */
 #define CHAR_API_WHAT_BIT      0x00080000    /* Char API vs network only */
-#define MS_DOS_WHAT_BIT                0x00100000    /* MS_DOS */
 #define CMD_EVT_WHAT_BIT       0x00200000    /* Command event */
 #define LONG_TX_WHAT_BIT       0x00400000
 #define LONG_RX_WHAT_BIT       0x00800000
@@ -486,6 +485,63 @@ struct cmd {
 #define  SAME_IFIELD           0x80
 
 
+typedef struct {
+#if (BITS_PER_LONG == 64)
+       u64 addrlo;
+#else
+       u32 addrhi;
+       u32 addrlo;
+#endif
+} rraddr;
+
+
+static inline void set_rraddr(rraddr *ra, volatile void *addr)
+{
+       unsigned long baddr = virt_to_bus((void *)addr);
+#if (BITS_PER_LONG == 64)
+       ra->addrlo = baddr;
+#else
+    /* Don't bother setting zero every time */
+       ra->addrlo = baddr;
+#endif
+       mb();
+}
+
+
+static inline void set_rxaddr(struct rr_regs *regs, volatile void *addr)
+{
+       unsigned long baddr = virt_to_bus((void *)addr);
+#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN)
+       writel(baddr & 0xffffffff, &regs->RxRingHi);
+       writel(baddr >> 32, &regs->RxRingLo);
+#elif (BITS_PER_LONG == 64)
+       writel(baddr >> 32, &regs->RxRingHi);
+       writel(baddr & 0xffffffff, &regs->RxRingLo);
+#else
+       writel(0, &regs->RxRingHi);
+       writel(baddr, &regs->RxRingLo);
+#endif
+       mb();
+}
+
+
+static inline void set_infoaddr(struct rr_regs *regs, volatile void *addr)
+{
+       unsigned long baddr = virt_to_bus((void *)addr);
+#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN)
+       writel(baddr & 0xffffffff, &regs->InfoPtrHi);
+       writel(baddr >> 32, &regs->InfoPtrLo);
+#elif (BITS_PER_LONG == 64)
+       writel(baddr >> 32, &regs->InfoPtrHi);
+       writel(baddr & 0xffffffff, &regs->InfoPtrLo);
+#else
+       writel(0, &regs->InfoPtrHi);
+       writel(baddr, &regs->InfoPtrLo);
+#endif
+       mb();
+}
+
+
 /*
  * TX ring
  */
@@ -498,12 +554,7 @@ struct cmd {
 #define TX_RING_SIZE   (TX_RING_ENTRIES * sizeof(struct tx_desc))
 
 struct tx_desc{
-#if (BITS_PER_LONG == 64)
-       u64     addr;
-#else
-        u32    zero;
-       u32     addr;
-#endif
+       rraddr  addr;
        u32     res;
 #ifdef __LITTLE_ENDIAN
        u16     size;
@@ -525,12 +576,7 @@ struct tx_desc{
 #define RX_RING_SIZE   (RX_RING_ENTRIES * sizeof(struct rx_desc))
 
 struct rx_desc{
-#if (BITS_PER_LONG == 64)
-       u64     addr;
-#else
-        u32    zero;
-       u32     addr;
-#endif
+       rraddr  addr;
        u32     res;
 #ifdef __LITTLE_ENDIAN
        u16     size;
@@ -714,12 +760,7 @@ struct rr_stats {
  * This struct is shared with the NIC firmware.
  */
 struct ring_ctrl {
-#if (BITS_PER_LONG == 64)
-       u64     rngptr;
-#else
-       u32     zero;
-       u32     rngptr;
-#endif
+       rraddr  rngptr;
 #ifdef __LITTLE_ENDIAN
        u16     entries;
        u8      pad;
@@ -759,19 +800,19 @@ struct rr_private
        struct rx_desc          rx_ring[RX_RING_ENTRIES];
        struct tx_desc          tx_ring[TX_RING_ENTRIES];
        struct event            evt_ring[EVT_RING_ENTRIES];
-       struct sk_buff          *tx_skbuff[TX_RING_ENTRIES];
        struct sk_buff          *rx_skbuff[RX_RING_ENTRIES];
+       struct sk_buff          *tx_skbuff[TX_RING_ENTRIES];
        struct rr_regs          *regs;          /* Register base */
        struct ring_ctrl        *rx_ctrl;       /* Receive ring control */
        struct rr_info          *info;          /* Shared info page */
+       struct device           *next;
        spinlock_t              lock;
        struct timer_list       timer;
        u32                     cur_rx, cur_cmd, cur_evt;
        u32                     dirty_rx, dirty_tx;
        u32                     tx_full;
+       u32                     fw_rev;
        short                   fw_running;
-       u8                      pci_bus;        /* PCI bus number */
-       u8                      pci_dev_fun;    /* PCI device numbers */
        char                    name[24];       /* The assigned name */
        struct net_device_stats stats;
 };
@@ -789,5 +830,11 @@ static int rr_start_xmit(struct sk_buff *skb, struct device *dev);
 static int rr_close(struct device *dev);
 static struct net_device_stats *rr_get_stats(struct device *dev);
 static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
+                                  unsigned long offset,
+                                  unsigned char *buf,
+                                  unsigned long length);
+static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset);
+static int rr_load_firmware(struct device *dev);
 
 #endif /* _RRUNNER_H_ */
index 18cf1709f117ed4f9991089621c27c6a4a2b0088..889a82d90e75610407edf2f8df0c5e842ca8bdd1 100644 (file)
@@ -48,6 +48,7 @@
 #include <asm/spinlock.h>
 
 #include "z85230.h"
+#include "syncppp.h"
 
 
 static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
index 7c75b570cf5ed42c0b58f20bd92f2282877c746a..6e14d6d7c7d29f1e40b1b3997bf62c6f25675f4c 100644 (file)
@@ -262,29 +262,22 @@ int do_acknowledge(unsigned char scancode)
                        return 0;
                }
        }
-       if(scancode == 0) {
-               prev_scancode = 0;
-               return 0;
-       }
        return 1;
 }
 
-int pcikbd_pretranslate(unsigned char scancode, char raw_mode)
+int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
+                    char raw_mode)
 {
-       if(scancode == 0xff) {
-               prev_scancode = 0;
+       static int prev_scancode = 0;
+
+       if (scancode == 0xe0 || scancode == 0xe1) {
+               prev_scancode = scancode;
                return 0;
        }
-       if(scancode == 0xe0 || scancode == 0xe1) {
-               prev_scancode = scancode;
+       if (scancode == 0x00 || scancode == 0xff) {
+               prev_scancode = 0;
                return 0;
        }
-       return 1;
-}
-
-int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
-                    char raw_mode)
-{
        if(prev_scancode) {
                if(prev_scancode != 0xe0) {
                        if(prev_scancode == 0xe1 && scancode == 0x1d) {
@@ -338,7 +331,7 @@ pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                        break;
                scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);
                if((status & KBD_STAT_OBF) && do_acknowledge(scancode))
-                       handle_scancode(scancode);
+                       handle_scancode(scancode, !(scancode & 0x80));
                status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
        } while(status & KBD_STAT_OBF);
        mark_bh(KEYBOARD_BH);
diff --git a/drivers/usb/CREDITS b/drivers/usb/CREDITS
new file mode 100644 (file)
index 0000000..ea9e550
--- /dev/null
@@ -0,0 +1,23 @@
+Credits for the Simple Linux USB Driver:
+
+The following people have contributed to this code (in alphabetical
+order by last name).  I'm sure this list should be longer, its
+difficult to maintain.
+
+  Johannes Erdfelt <jerdfelt@sventech.com>
+  ham <ham@unsuave.com>
+  Bradley M Keryan <keryan@andrew.cmu.edu>
+  Vojtech Pavlik <vojtech@twilight.ucw.cz>
+  Gregory P. Smith <greg@electricrain.com>
+  Linus Torvalds <torvalds@transmeta.com>
+  <Kazuki.Yasumatsu@fujixerox.co.jp>
+
+Special thanks to:
+
+  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
+  Linux USB driver effort and writing much of the larger uusbd driver.
+  Much has been learned from that effort.
+
+  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
+  and offering suggestions and sharing implementation experiences.
+
diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in
new file mode 100644 (file)
index 0000000..b7955ad
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# USB device configuration
+#
+# NOTE NOTE NOTE! This is still considered extremely experimental.
+# Right now hubs, mice and keyboards work - at least with UHCI.
+# But that may be more a lucky coincidence than anything else..
+#
+# This was all developed modularly, but I've been lazy in cleaning
+# it up, so right now they are all bools. 
+#
+mainmenu_option next_comment
+comment 'USB drivers - not for the faint of heart'
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
+  if [ "$CONFIG_USB" = "y" ]; then
+    bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
+    bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
+
+    bool 'USB mouse support' CONFIG_USB_MOUSE
+    bool 'USB keyboard support' CONFIG_USB_KBD
+  fi
+fi
+
+endmenu
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
new file mode 100644 (file)
index 0000000..8675608
--- /dev/null
@@ -0,0 +1,59 @@
+#
+# Makefile for the kernel usb device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+# This isn't actually supported yet. Don't try to use it.
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := usb.a
+M_OBJS   :=
+L_OBJS   := usb.o hub.o usb-debug.o
+LX_OBJS  :=
+
+ifeq ($(CONFIG_USB_UHCI),y)
+  L_OBJS += uhci.o uhci-debug.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += usb-uhci.o uhci-debug.o
+  endif
+endif
+
+ifeq ($(CONFIG_USB_OHCI),y)
+  L_OBJS += ohci.o ohci-debug.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += ohci.o ohci-debug.o
+  endif
+endif
+
+ifeq ($(CONFIG_USB_MOUSE),y)
+  L_OBJS += mouse.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += mouse.o
+  endif
+endif
+
+ifeq ($(CONFIG_USB_KBD),y)
+  L_OBJS += keyboard.o keymap.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += keyboard.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+keymap.o: keymap.c
+
+keymap.c: maps/serial.map maps/usb.map maps/fixup.map
+       ./mkmap > $@
diff --git a/drivers/usb/README.kbd b/drivers/usb/README.kbd
new file mode 100644 (file)
index 0000000..84a77d9
--- /dev/null
@@ -0,0 +1,65 @@
+This is a simple USB keyboard driver written from Linus'
+USB driver (started with Greg's usb-0.03b.tar.gz source
+tree)
+
+It works fine with my BTC keyboard but I'm still investigating
+trouble with my MS keyboard (trouble starts with an inability
+to set into boot protocol mode, though, this very well could
+be all due to crappy hardware).
+
+Anyway, I would appreciate you taking a look if you have
+any USB keyboards lying around.  Oh also, I'm doing this on
+UHCI so sorry if it breaks with OHCI.
+
+-ham
+
+
+
+Keyboard patch
+--------------
+
+Instead of using the multiple keyboard patch and then running into all
+of the kernel version problems that the current Linux-USB project has
+had, I'm just mapping the USB keycodes to the standard AT-101 keycodes
+and sending them directly to "handle_scancode".
+
+This may or may not be considered a hack.  Anyway it is effective, and
+I think safe, and allows USB keyboards to coexist with a serial
+keyboard (oh yeah, one side effect is that you can for example hold
+down the control key on the serial keyboard and press "a" on the USB
+keyboard and you get Control-a like with Windows USB) and works
+fine for console and X.
+
+You do need to make a *tiny* patch the kernel source tree so that the
+function "handle_scancode" is exported from keyboard.c though.
+
+  $ cd /usr/src/linux
+  $ patch -p0 < kbd.patch
+
+And, of course, then, you need to rebuild and install the kernel.
+
+** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want
+to use the keyboard and are too lazy to patch the kernel.
+
+Keyboard map
+------------
+
+I'm including a stupid utility "mkmap" which generates the USB->serial
+keymap.  It takes in maps/serial.map (the current serial keymap,
+generated by "dumpkeys"), maps/usb.map (the USB keymap), and
+maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c
+Anyway, it is not beautiful but should serve its purpose for the
+moment.
+
+Other changes
+-------------
+uhci.c:
+  * added a context value to the irq callback function
+    (this is exactly like the "dev_id" field to request_irq)
+  * played with uhci_reset_port to get better hot-plug results
+    (eg. do a wait_ms(200) before calling uhci_reset_port)
+usb.c:
+  * disconnect all devices after uhci-control thread is killed
+  * skip over the HID descriptor
+  * disconnect the high-level driver in usb_disconnect
+
diff --git a/drivers/usb/README.ohci b/drivers/usb/README.ohci
new file mode 100644 (file)
index 0000000..6a37448
--- /dev/null
@@ -0,0 +1,8 @@
+April 24, 1999 04:37:42 PST
+
+Okay, I've written a lot more of the OHCI code and actually got it back to
+a compiling state now with all of the recent improvements to the way stuff
+is structured.  It is completely untested.
+
+- greg@electricrain.com
+
diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c
new file mode 100644 (file)
index 0000000..6f0af08
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * USB hub driver.
+ *
+ * This is horrible, it knows about the UHCI driver
+ * internals, but it's just meant as a rough example,
+ * let's do the virtualization later when this works.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+
+#include <asm/spinlock.h>
+
+#include "usb.h"
+#include "uhci.h"
+#include "hub.h"
+
+extern struct usb_operations uhci_device_operations;
+
+/* Wakes up khubd */
+static struct wait_queue *usb_hub_wait = NULL;
+static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+
+/* List of hubs needing servicing */
+static struct list_head hub_event_list;
+
+/*
+ * A irq handler returns non-zero to indicate to
+ * the low-level driver that it wants to be re-activated,
+ * or zero to say "I'm done".
+ */
+static int hub_irq(int status, void *__buffer, void *dev_id)
+{
+       struct usb_hub *hub = dev_id;
+       unsigned long flags;
+
+       if (waitqueue_active(&usb_hub_wait)) {
+               /* Add the hub to the event queue */
+               spin_lock_irqsave(&hub_event_lock, flags);
+               if (hub->event_list.next == &hub->event_list) {
+                       list_add(&hub->event_list, &hub_event_list);
+                       /* Wake up khubd */
+                       wake_up(&usb_hub_wait);
+               }
+               spin_unlock_irqrestore(&hub_event_lock, flags);
+       }
+
+       return 1;
+}
+
+static void usb_hub_configure(struct usb_hub *hub)
+{
+       struct usb_device *dev = hub->dev;
+       unsigned char hubdescriptor[8], buf[4];
+       int charac, i;
+
+       usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+
+       if (usb_get_hub_descriptor(dev, hubdescriptor, 8))
+               return;
+
+       hub->nports = dev->maxchild = hubdescriptor[2];
+       printk("hub: %d-port%s detected\n", hub->nports,
+               (hub->nports == 1) ? "" : "s");
+
+       charac = (hubdescriptor[4] << 8) + hubdescriptor[3];
+       switch (charac & HUB_CHAR_LPSM) {
+               case 0x00:
+                       printk("hub: ganged power switching\n");
+                       break;
+               case 0x01:
+                       printk("hub: individual port power switching\n");
+                       break;
+               case 0x02:
+               case 0x03:
+                       printk("hub: unknown reserved power switching mode\n");
+                       break;
+       }
+
+       if (charac & HUB_CHAR_COMPOUND)
+               printk("hub: part of a compound device\n");
+       else
+               printk("hub: standalone hub\n");
+
+       switch (charac & HUB_CHAR_OCPM) {
+               case 0x00:
+                       printk("hub: global over current protection\n");
+                       break;
+               case 0x08:
+                       printk("hub: individual port over current protection\n");
+                       break;
+               case 0x10:
+               case 0x18:
+                       printk("hub: no over current protection\n");
+                        break;
+       }
+
+       printk("hub: power on to power good time: %dms\n",
+               hubdescriptor[5] * 2);
+
+       printk("hub: hub controller current requirement: %dmA\n",
+               hubdescriptor[6]);
+
+       for (i = 0; i < dev->maxchild; i++)
+               printk("hub:  port %d is%s removable\n", i + 1,
+                       hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8))
+                       ? " not" : "");
+
+       if (usb_get_hub_status(dev, buf))
+               return;
+
+       printk("hub: local power source is %s\n",
+               (buf[0] & 1) ? "lost (inactive)" : "good");
+
+       printk("hub: %sover current condition exists\n",
+               (buf[0] & 2) ? "" : "no ");
+
+#if 0
+       for (i = 0; i < hub->nports; i++) {
+               int portstat, portchange;
+               unsigned char portstatus[4];
+
+               if (usb_get_port_status(dev, i + 1, portstatus))
+                       return;
+               portstat = (portstatus[1] << 8) + portstatus[0];
+               portchange = (portstatus[3] << 8) + portstatus[2];
+
+               printk("hub: port %d status\n", i + 1);
+               printk("hub:  %sdevice present\n", (portstat & 1) ? "" : "no ");
+               printk("hub:  %s\n", (portstat & 2) ? "enabled" : "disabled");
+               printk("hub:  %ssuspended\n", (portstat & 4) ? "" : "not ");
+               printk("hub:  %sover current\n", (portstat & 8) ? "" : "not ");
+               printk("hub:  has %spower\n", (portstat & 0x100) ? "" : "no ");
+               printk("hub:  %s speed\n", (portstat & 0x200) ? "low" : "full");
+       }
+#endif
+
+       /* Enable power to the ports */
+       printk("enabling power on all ports\n");
+       for (i = 0; i < hub->nports; i++)
+               usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+}
+
+static int hub_probe(struct usb_device *dev)
+{
+       struct usb_interface_descriptor *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct usb_hub *hub;
+
+       /* We don't handle multi-config hubs */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -1;
+
+       /* We don't handle multi-interface hubs */
+       if (dev->config[0].bNumInterfaces != 1)
+               return -1;
+
+       interface = &dev->config[0].interface[0];
+
+       /* Is it a hub? */
+       if (interface->bInterfaceClass != 9)
+               return -1;
+       if (interface->bInterfaceSubClass != 0)
+               return -1;
+
+       /* Multiple endpoints? What kind of mutant ninja-hub is this? */
+       if (interface->bNumEndpoints != 1)
+               return -1;
+
+       endpoint = &interface->endpoint[0];
+
+       /* Output endpoint? Curiousier and curiousier.. */
+       if (!(endpoint->bEndpointAddress & 0x80))
+               return -1;
+
+       /* If it's not an interrupt endpoint, we'd better punt! */
+       if ((endpoint->bmAttributes & 3) != 3)
+               return -1;
+
+       /* We found a hub */
+       printk("USB hub found\n");
+
+       if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
+               printk("couldn't kmalloc hub struct\n");
+               return -1;
+       }
+
+       memset(hub, 0, sizeof(*hub));
+
+       dev->private = hub;
+
+       INIT_LIST_HEAD(&hub->event_list);
+       hub->dev = dev;
+
+       usb_hub_configure(hub);
+
+       usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+
+       /* Wake up khubd */
+       wake_up(&usb_hub_wait);
+
+       return 0;
+}
+
+static void hub_disconnect(struct usb_device *dev)
+{
+       struct usb_hub *hub = dev->private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hub_event_lock, flags);
+
+       /* Delete it and then reset it */
+       list_del(&hub->event_list);
+       INIT_LIST_HEAD(&hub->event_list);
+
+       spin_unlock_irqrestore(&hub_event_lock, flags);
+
+       /* Free the memory */
+       kfree(hub);
+}
+
+static void usb_hub_port_connect_change(struct usb_device *hub, int port)
+{
+       struct usb_device *usb;
+       unsigned char buf[4];
+       unsigned short portstatus, portchange;
+
+       usb_disconnect(&hub->children[port]);
+
+       usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+
+       wait_ms(50);    /* FIXME: This is from the *BSD stack, thanks! :) */
+
+       if (usb_get_port_status(hub, port + 1, buf)) {
+               printk("get_port_status failed\n");
+               return;
+       }
+
+       portstatus = *((unsigned short *)buf + 0);
+       portchange = *((unsigned short *)buf + 1);
+
+       if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+               (!(portstatus & USB_PORT_STAT_ENABLE))) {
+               /* We're done now, we already disconnected the device */
+               /* printk("not connected/enabled\n"); */
+               return;
+       }
+
+       usb = hub->bus->op->allocate(hub);
+       if (!usb) {
+               printk("couldn't allocate usb_device\n");
+               return;
+       }
+
+       usb_connect(usb);
+
+       usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
+
+       hub->children[port] = usb;
+
+       usb_new_device(usb);
+}
+
+static void usb_hub_events(void)
+{
+       unsigned long flags;
+       unsigned char buf[4];
+       unsigned short portstatus, portchange;
+       int i;
+       struct list_head *next, *tmp, *head = &hub_event_list;
+       struct usb_device *dev;
+       struct usb_hub *hub;
+
+       spin_lock_irqsave(&hub_event_lock, flags);
+
+       tmp = head->next;
+       while (tmp != head) {
+               hub = list_entry(tmp, struct usb_hub, event_list);
+               dev = hub->dev;
+
+               next = tmp->next;
+
+               list_del(tmp);
+               INIT_LIST_HEAD(tmp);
+
+               for (i = 0; i < hub->nports; i++) {
+                       if (usb_get_port_status(dev, i + 1, buf)) {
+                               printk("get_port_status failed\n");
+                               continue;
+                       }
+
+                       portstatus = *((unsigned short *)buf + 0);
+                       portchange = *((unsigned short *)buf + 1);
+
+                       if (portchange & USB_PORT_STAT_C_CONNECTION) {
+                               printk("hub: port %d connection change\n", i + 1);
+
+                               usb_clear_port_feature(dev, i + 1,
+                                       USB_PORT_FEAT_C_CONNECTION);
+
+                               usb_hub_port_connect_change(dev, i);
+                       }
+
+                       if (portchange & USB_PORT_STAT_C_ENABLE) {
+                               printk("hub: port %d enable change\n", i + 1);
+                               usb_clear_port_feature(dev, i + 1,
+                                       USB_PORT_FEAT_C_ENABLE);
+                       }
+
+                       if (portchange & USB_PORT_STAT_C_SUSPEND)
+                               printk("hub: port %d suspend change\n", i + 1);
+
+                       if (portchange & USB_PORT_STAT_C_OVERCURRENT)
+                               printk("hub: port %d over-current change\n", i + 1);
+
+                       if (portchange & USB_PORT_STAT_C_RESET) {
+                               printk("hub: port %d reset change\n", i + 1);
+                               usb_clear_port_feature(dev, i + 1,
+                                       USB_PORT_FEAT_C_RESET);
+                       }
+
+#if 0
+                       if (!portchange)
+                               continue;
+
+                       if (usb_get_port_status(dev, i + 1, buf))
+                               return;
+
+                       portstatus = (buf[1] << 8) + buf[0];
+                       portchange = (buf[3] << 8) + buf[2];
+
+                       printk("hub: port %d status\n", i + 1);
+                       printk("hub:  %sdevice present\n", (portstatus & 1) ? "" : "no ");
+                       printk("hub:  %s\n", (portstatus & 2) ? "enabled" : "disabled");
+                       printk("hub:  %ssuspended\n", (portstatus & 4) ? "" : "not ");
+                       printk("hub:  %sover current\n", (portstatus & 8) ? "" : "not ");
+                       printk("hub:  has %spower\n", (portstatus & 0x100) ? "" : "no ");
+                       printk("hub:  %s speed\n", (portstatus & 0x200) ? "low" : "full");
+#endif
+               }
+               tmp = next;
+#if 0
+               wait_ms(1000);
+#endif
+        }
+
+       spin_unlock_irqrestore(&hub_event_lock, flags);
+}
+
+static int usb_hub_thread(void *__hub)
+{
+       lock_kernel();
+
+       /*
+        * This thread doesn't need any user-level access,
+        * so get rid of all our resources
+        */
+       printk("usb_hub_thread at %p\n", &usb_hub_thread);
+       exit_mm(current);
+       exit_files(current);
+       exit_fs(current);
+
+       /* Setup a nice name */
+       strcpy(current->comm, "khubd");
+
+       /* Send me a signal to get me die (for debugging) */
+       do {
+               interruptible_sleep_on(&usb_hub_wait);
+               usb_hub_events();
+       } while (!signal_pending(current));
+
+       printk("usb_hub_thread exiting\n");
+
+       return 0;
+}
+
+static struct usb_driver hub_driver = {
+       "hub",
+       hub_probe,
+       hub_disconnect,
+       { NULL, NULL }
+};
+
+/*
+ * This should be a separate module.
+ */
+int hub_init(void)
+{
+       int pid;
+
+       INIT_LIST_HEAD(&hub_event_list);
+
+       usb_register(&hub_driver);
+       pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+       if (pid >= 0)
+               return 0;
+
+       /* Fall through if kernel_thread failed */
+       usb_deregister(&hub_driver);
+
+       return 0;
+}
+
diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h
new file mode 100644 (file)
index 0000000..d015c5a
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef __LINUX_HUB_H
+#define __LINUX_HUB_H
+
+#include <linux/list.h>
+
+/*
+ * Hub feature numbers
+ */
+#define C_HUB_LOCAL_POWER      0
+#define C_HUB_OVER_CURRENT     1
+
+/*
+ * Port feature numbers
+ */
+#define USB_PORT_FEAT_ENABLE           1
+#define USB_PORT_FEAT_SUSPEND          2
+#define USB_PORT_FEAT_OVER_CURRENT     3
+#define USB_PORT_FEAT_RESET            4
+#define USB_PORT_FEAT_POWER            8
+#define USB_PORT_FEAT_LOWSPEED         9
+#define USB_PORT_FEAT_C_CONNECTION     16
+#define USB_PORT_FEAT_C_ENABLE         17
+#define USB_PORT_FEAT_C_SUSPEND                18
+#define USB_PORT_FEAT_C_OVER_CURRENT   19
+#define USB_PORT_FEAT_C_RESET          20
+
+/* wPortStatus */
+#define USB_PORT_STAT_CONNECTION       0x0001
+#define USB_PORT_STAT_ENABLE           0x0002
+#define USB_PORT_STAT_SUSPEND          0x0004
+#define USB_PORT_STAT_OVERCURRENT      0x0008
+#define USB_PORT_STAT_RESET            0x0010
+#define USB_PORT_STAT_POWER            0x0100
+#define USB_PORT_STAT_LOW_SPEED                0x0200
+
+/* wPortChange */
+#define USB_PORT_STAT_C_CONNECTION     0x0001
+#define USB_PORT_STAT_C_ENABLE         0x0002
+#define USB_PORT_STAT_C_SUSPEND                0x0004
+#define USB_PORT_STAT_C_OVERCURRENT    0x0008
+#define USB_PORT_STAT_C_RESET          0x0010
+
+/* Characteristics */
+#define HUB_CHAR_LPSM          0x0003
+#define HUB_CHAR_COMPOUND      0x0004
+#define HUB_CHAR_OCPM          0x0018
+
+struct usb_device;
+
+typedef enum {
+       USB_PORT_UNPOWERED = 0,         /* Default state */
+       USB_PORT_POWERED,               /* When we've put power to it */
+       USB_PORT_ENABLED,               /* When it's been enabled */
+       USB_PORT_DISABLED,              /* If it's been disabled */
+       USB_PORT_ADMINDISABLED,         /* Forced down */
+} usb_hub_port_state;
+
+struct usb_hub_port {
+       usb_hub_port_state cstate;      /* Configuration state */
+
+       struct usb_device *child;       /* Device attached to this port */
+
+       struct usb_hub *parent;         /* Parent hub */
+};
+
+struct usb_hub {
+       /* Device structure */
+       struct usb_device *dev;
+
+       /* Temporary event list */
+       struct list_head event_list;
+
+       /* Number of ports on the hub */
+       int nports;
+
+       struct usb_hub_port ports[0];   /* Dynamically allocated */
+};
+
+#endif
+
diff --git a/drivers/usb/inits.h b/drivers/usb/inits.h
new file mode 100644 (file)
index 0000000..d598486
--- /dev/null
@@ -0,0 +1,3 @@
+int bp_mouse_init(void);
+int usb_kbd_init(void);
+int hub_init(void);
diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c
new file mode 100644 (file)
index 0000000..c60c812
--- /dev/null
@@ -0,0 +1,226 @@
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/kbd_ll.h>
+#include "usb.h"
+
+#define PCKBD_PRESSED  0x00
+#define PCKBD_RELEASED 0x80
+#define PCKBD_NEEDS_E0 0x80
+
+#define USBKBD_MODIFIER_BASE  120
+#define USBKBD_KEYCODE_OFFSET 2
+#define USBKBD_KEYCODE_COUNT  6
+
+#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3)
+#define USBKBD_FIND_KEYCODE(down, key, count) \
+    ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count)))
+
+#define USBKBD_REPEAT_DELAY (HZ / 4)
+#define USBKBD_REPEAT_RATE (HZ / 20)
+
+struct usb_keyboard
+{
+    struct usb_device *dev;
+    unsigned long down[2];
+    unsigned char repeat_key;
+    struct timer_list repeat_timer;
+    struct list_head list;
+};
+
+extern unsigned char usb_kbd_map[];
+
+static int usb_kbd_probe(struct usb_device *dev);
+static void usb_kbd_disconnect(struct usb_device *dev);
+static void usb_kbd_repeat(unsigned long dummy);
+
+static LIST_HEAD(usb_kbd_list);
+
+static struct usb_driver usb_kbd_driver =
+{
+    "keyboard",
+    usb_kbd_probe,
+    usb_kbd_disconnect,
+    {NULL, NULL}
+};
+
+
+static void
+usb_kbd_handle_key(unsigned char key, int down)
+{
+    int scancode = (int) usb_kbd_map[key];
+    if(scancode)
+    {
+        if(scancode & PCKBD_NEEDS_E0)
+        {
+            handle_scancode(0xe0, 1);
+        }
+        handle_scancode((scancode & ~PCKBD_NEEDS_E0), down);
+    }
+}
+
+static void
+usb_kbd_repeat(unsigned long dev_id)
+{
+    struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
+
+    unsigned long flags;
+    save_flags(flags);
+    cli();
+
+    if(kbd->repeat_key)
+    {
+        usb_kbd_handle_key(kbd->repeat_key, 1);
+
+        /* reset repeat timer */
+        kbd->repeat_timer.function = usb_kbd_repeat;
+        kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE;
+        kbd->repeat_timer.data = (unsigned long) kbd;
+        kbd->repeat_timer.prev = NULL;
+        kbd->repeat_timer.next = NULL;
+        add_timer(&kbd->repeat_timer);
+    }
+
+    restore_flags(flags);
+}
+
+static int
+usb_kbd_irq(int state, void *buffer, void *dev_id)
+{
+    struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
+    unsigned long *down = (unsigned long*) buffer;
+
+    if(kbd->down[0] != down[0] || kbd->down[1] != down[1])
+    {
+        unsigned char *olddown, *newdown;
+        unsigned char modsdelta, key;
+        int i;
+
+        /* handle modifier change */
+        modsdelta = (*(unsigned char*) down ^ *(unsigned char*) kbd->down);
+        if(modsdelta)
+        {
+            for(i = 0; i < 8; i++)
+            {
+                if(modsdelta & 0x01)
+                {
+                    int pressed = (*(unsigned char*) down >> i) & 0x01;
+                    usb_kbd_handle_key(
+                        i + USBKBD_MODIFIER_BASE,
+                        pressed);
+                }
+                modsdelta >>= 1;
+            }
+        }
+
+        olddown = (unsigned char*) kbd->down + USBKBD_KEYCODE_OFFSET;
+        newdown = (unsigned char*) down + USBKBD_KEYCODE_OFFSET;
+
+        /* handle released keys */
+        for(i = 0; i < USBKBD_KEYCODE_COUNT; i++)
+        {
+            key = olddown[i];
+            if(USBKBD_VALID_KEYCODE(key)
+               && !USBKBD_FIND_KEYCODE(newdown, key, USBKBD_KEYCODE_COUNT))
+            {
+                usb_kbd_handle_key(key, 0);
+            }
+        }
+
+        /* handle pressed keys */
+        kbd->repeat_key = 0;
+        for(i = 0; i < USBKBD_KEYCODE_COUNT; i++)
+        {
+            key = newdown[i];
+            if(USBKBD_VALID_KEYCODE(key)
+               && !USBKBD_FIND_KEYCODE(olddown, key, USBKBD_KEYCODE_COUNT))
+            {
+                usb_kbd_handle_key(key, 1);
+                kbd->repeat_key = key;
+            }
+        }
+
+        /* set repeat timer if any keys were pressed */
+        if(kbd->repeat_key)
+        {
+            del_timer(&kbd->repeat_timer);
+            kbd->repeat_timer.function = usb_kbd_repeat;
+            kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_DELAY;
+            kbd->repeat_timer.data = (unsigned long) kbd;
+            kbd->repeat_timer.prev = NULL;
+            kbd->repeat_timer.next = NULL;
+            add_timer(&kbd->repeat_timer);
+        }
+
+        kbd->down[0] = down[0];
+        kbd->down[1] = down[1];
+    }
+
+    return 1;
+}
+
+static int
+usb_kbd_probe(struct usb_device *dev)
+{
+    struct usb_interface_descriptor *interface;
+    struct usb_endpoint_descriptor *endpoint;
+    struct usb_keyboard *kbd;
+
+    interface = &dev->config[0].interface[0];
+    endpoint = &interface->endpoint[0];
+
+    if(interface->bInterfaceClass != 3
+       || interface->bInterfaceSubClass != 1
+       || interface->bInterfaceProtocol != 1)
+    {
+        return -1;
+    }
+
+    printk(KERN_INFO "USB HID boot protocol keyboard detected.\n");
+
+    kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL);
+    if(kbd)
+    {
+        memset(kbd, 0, sizeof(*kbd));
+        kbd->dev = dev;
+        dev->private = kbd;
+
+        usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+        usb_set_protocol(dev, 0);
+        usb_set_idle(dev, 0, 0);
+        
+        usb_request_irq(dev,
+                        usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
+                        usb_kbd_irq,
+                        endpoint->bInterval,
+                        kbd);
+
+        list_add(&kbd->list, &usb_kbd_list);
+    }
+
+    return 0;
+}
+
+static void
+usb_kbd_disconnect(struct usb_device *dev)
+{
+    struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private;
+    if(kbd)
+    {
+        dev->private = NULL;
+        list_del(&kbd->list);
+        del_timer(&kbd->repeat_timer);
+        kfree(kbd);
+    }
+
+    printk(KERN_INFO "USB HID boot protocol keyboard removed.\n");
+}
+
+int
+usb_kbd_init(void)
+{
+    usb_register(&usb_kbd_driver);
+    return 0;
+}
diff --git a/drivers/usb/keymap.c b/drivers/usb/keymap.c
new file mode 100644 (file)
index 0000000..16c7b28
--- /dev/null
@@ -0,0 +1,50 @@
+unsigned char usb_kbd_map[256] = 
+{
+    0x00,  0x00,  0x00,  0x00,  0x1e,  0x30,  0x2e,  0x20,
+    0x12,  0x21,  0x22,  0x23,  0x17,  0x24,  0x25,  0x26,
+
+    0x32,  0x31,  0x18,  0x19,  0x10,  0x13,  0x1f,  0x14,
+    0x16,  0x2f,  0x11,  0x2d,  0x15,  0x2c,  0x02,  0x03,
+
+    0x04,  0x05,  0x06,  0x07,  0x08,  0x09,  0x0a,  0x0b,
+    0x1c,  0x01,  0xd3,  0x0f,  0x39,  0x0c,  0x0d,  0x1a,
+
+    0x1b,  0x2b,  0x00,  0x27,  0x28,  0x29,  0x33,  0x34,
+    0x35,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,  0x40,
+
+    0x41,  0x42,  0x43,  0x44,  0x57,  0x58,  0xb7,  0x46,
+    0x00,  0xd2,  0xc7,  0xc9,  0x63,  0xcf,  0xd1,  0xcd,
+
+    0xcb,  0xd0,  0xc8,  0x45,  0xb5,  0x37,  0x4a,  0x4e,
+    0x9c,  0x4f,  0x50,  0x51,  0x4b,  0x4c,  0x4d,  0x47,
+
+    0x48,  0x49,  0x52,  0x53,  0x00,  0x6d,  0x00,  0x00,
+    0xbd,  0xbe,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x1d,  0x2a,  0x38,  0xdb,  0x9d,  0x36,  0xb8,  0xdc,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+};
diff --git a/drivers/usb/maps/fixup.map b/drivers/usb/maps/fixup.map
new file mode 100644 (file)
index 0000000..fc5d1ed
--- /dev/null
@@ -0,0 +1,31 @@
+# misc fixes
+keycode   0 = Pause
+keycode  29 = Control
+keycode  99 = Remove
+keycode  42 = Shift
+keycode  54 = Shift_R
+keycode 109 = Application
+
+# E0 keys (or'ed with 0x80)
+keycode 156 = KP_Enter
+keycode 157 = Control_R
+keycode 181 = KP_Divide
+keycode 183 = Print_Screen
+keycode 184 = Alt_R
+keycode 189 = F13
+keycode 190 = F14
+keycode 193 = F17
+keycode 198 = Break
+keycode 199 = Home
+keycode 200 = Up
+keycode 201 = Prior
+keycode 203 = Left
+keycode 205 = Right
+keycode 207 = End
+keycode 208 = Down
+keycode 209 = Next
+keycode 210 = Insert
+keycode 211 = Delete
+keycode 219 = Window
+keycode 220 = Window_R
+keycode 221 = Menu
diff --git a/drivers/usb/maps/serial.map b/drivers/usb/maps/serial.map
new file mode 100644 (file)
index 0000000..e421a0d
--- /dev/null
@@ -0,0 +1,370 @@
+keymaps 0-2,4-6,8-9,12
+keycode   1 = Escape          
+       alt     keycode   1 = Meta_Escape     
+       shift   alt     keycode   1 = Meta_Escape     
+       control alt     keycode   1 = Meta_Escape     
+keycode   2 = one              exclam          
+       alt     keycode   2 = Meta_one        
+       shift   alt     keycode   2 = Meta_exclam     
+keycode   3 = two              at               at               nul              nul             
+       alt     keycode   3 = Meta_two        
+       shift   alt     keycode   3 = Meta_at         
+       control alt     keycode   3 = Meta_nul        
+keycode   4 = three            numbersign      
+       control keycode   4 = Escape          
+       alt     keycode   4 = Meta_three      
+       shift   alt     keycode   4 = Meta_numbersign 
+keycode   5 = four             dollar           dollar           Control_backslash
+       alt     keycode   5 = Meta_four       
+       shift   alt     keycode   5 = Meta_dollar     
+       control alt     keycode   5 = Meta_Control_backslash
+keycode   6 = five             percent         
+       control keycode   6 = Control_bracketright
+       alt     keycode   6 = Meta_five       
+       shift   alt     keycode   6 = Meta_percent    
+keycode   7 = six              asciicircum     
+       control keycode   7 = Control_asciicircum
+       alt     keycode   7 = Meta_six        
+       shift   alt     keycode   7 = Meta_asciicircum
+keycode   8 = seven            ampersand        braceleft        Control_underscore
+       alt     keycode   8 = Meta_seven      
+       shift   alt     keycode   8 = Meta_ampersand  
+       control alt     keycode   8 = Meta_Control_underscore
+keycode   9 = eight            asterisk         bracketleft      Delete          
+       alt     keycode   9 = Meta_eight      
+       shift   alt     keycode   9 = Meta_asterisk   
+       control alt     keycode   9 = Meta_Delete     
+keycode  10 = nine             parenleft        bracketright    
+       alt     keycode  10 = Meta_nine       
+       shift   alt     keycode  10 = Meta_parenleft  
+keycode  11 = zero             parenright       braceright      
+       alt     keycode  11 = Meta_zero       
+       shift   alt     keycode  11 = Meta_parenright 
+keycode  12 = minus            underscore       backslash        Control_underscore Control_underscore
+       alt     keycode  12 = Meta_minus      
+       shift   alt     keycode  12 = Meta_underscore 
+       control alt     keycode  12 = Meta_Control_underscore
+keycode  13 = equal            plus            
+       alt     keycode  13 = Meta_equal      
+       shift   alt     keycode  13 = Meta_plus       
+keycode  14 = Delete          
+       alt     keycode  14 = Meta_Delete     
+       shift   alt     keycode  14 = Meta_Delete     
+       control alt     keycode  14 = Meta_Delete     
+keycode  15 = Tab             
+       alt     keycode  15 = Meta_Tab        
+       shift   alt     keycode  15 = Meta_Tab        
+       control alt     keycode  15 = Meta_Tab        
+keycode  16 = q               
+keycode  17 = w               
+keycode  18 = e               
+keycode  19 = r               
+keycode  20 = t               
+keycode  21 = y               
+keycode  22 = u               
+keycode  23 = i               
+keycode  24 = o               
+keycode  25 = p               
+keycode  26 = bracketleft      braceleft       
+       control keycode  26 = Escape          
+       alt     keycode  26 = Meta_bracketleft
+       shift   alt     keycode  26 = Meta_braceleft  
+keycode  27 = bracketright     braceright       asciitilde       Control_bracketright
+       alt     keycode  27 = Meta_bracketright
+       shift   alt     keycode  27 = Meta_braceright 
+       control alt     keycode  27 = Meta_Control_bracketright
+keycode  28 = Return          
+       alt     keycode  28 = Meta_Control_m  
+keycode  29 = Control         
+keycode  30 = a               
+keycode  31 = s               
+keycode  32 = d               
+keycode  33 = f               
+keycode  34 = g               
+keycode  35 = h               
+keycode  36 = j               
+keycode  37 = k               
+keycode  38 = l               
+keycode  39 = semicolon        colon           
+       alt     keycode  39 = Meta_semicolon  
+       shift   alt     keycode  39 = Meta_colon      
+keycode  40 = apostrophe       quotedbl        
+       control keycode  40 = Control_g       
+       alt     keycode  40 = Meta_apostrophe 
+       shift   alt     keycode  40 = Meta_quotedbl   
+keycode  41 = grave            asciitilde      
+       control keycode  41 = nul             
+       alt     keycode  41 = Meta_grave      
+       shift   alt     keycode  41 = Meta_asciitilde 
+keycode  42 = Shift           
+keycode  43 = backslash        bar             
+       control keycode  43 = Control_backslash
+       alt     keycode  43 = Meta_backslash  
+       shift   alt     keycode  43 = Meta_bar        
+keycode  44 = z               
+keycode  45 = x               
+keycode  46 = c               
+keycode  47 = v               
+keycode  48 = b               
+keycode  49 = n               
+keycode  50 = m               
+keycode  51 = comma            less            
+       alt     keycode  51 = Meta_comma      
+       shift   alt     keycode  51 = Meta_less       
+keycode  52 = period           greater         
+       alt     keycode  52 = Meta_period     
+       shift   alt     keycode  52 = Meta_greater    
+keycode  53 = slash            question        
+       control keycode  53 = Delete          
+       alt     keycode  53 = Meta_slash      
+       shift   alt     keycode  53 = Meta_question   
+keycode  54 = Shift           
+keycode  55 = KP_Multiply     
+       altgr   keycode  55 = Hex_C           
+keycode  56 = Alt             
+keycode  57 = space           
+       control keycode  57 = nul             
+       alt     keycode  57 = Meta_space      
+       shift   alt     keycode  57 = Meta_space      
+       control alt     keycode  57 = Meta_nul        
+keycode  58 = Caps_Lock       
+keycode  59 = F1               F13              Console_13       F25             
+       alt     keycode  59 = Console_1       
+       control alt     keycode  59 = Console_1       
+keycode  60 = F2               F14              Console_14       F26             
+       alt     keycode  60 = Console_2       
+       control alt     keycode  60 = Console_2       
+keycode  61 = F3               F15              Console_15       F27             
+       alt     keycode  61 = Console_3       
+       control alt     keycode  61 = Console_3       
+keycode  62 = F4               F16              Console_16       F28             
+       alt     keycode  62 = Console_4       
+       control alt     keycode  62 = Console_4       
+keycode  63 = F5               F17              Console_17       F29             
+       alt     keycode  63 = Console_5       
+       control alt     keycode  63 = Console_5       
+keycode  64 = F6               F18              Console_18       F30             
+       alt     keycode  64 = Console_6       
+       control alt     keycode  64 = Console_6       
+keycode  65 = F7               F19              Console_19       F31             
+       alt     keycode  65 = Console_7       
+       control alt     keycode  65 = Console_7       
+keycode  66 = F8               F20              Console_20       F32             
+       alt     keycode  66 = Console_8       
+       control alt     keycode  66 = Console_8       
+keycode  67 = F9               F21              Console_21       F33             
+       alt     keycode  67 = Console_9       
+       control alt     keycode  67 = Console_9       
+keycode  68 = F10              F22              Console_22       F34             
+       alt     keycode  68 = Console_10      
+       control alt     keycode  68 = Console_10      
+keycode  69 = Num_Lock        
+       altgr   keycode  69 = Hex_E           
+keycode  70 = Scroll_Lock      Show_Memory      Show_Registers   Show_State      
+       alt     keycode  70 = Scroll_Lock     
+keycode  71 = KP_7            
+       altgr   keycode  71 = Hex_7           
+       alt     keycode  71 = Ascii_7         
+keycode  72 = KP_8            
+       altgr   keycode  72 = Hex_8           
+       alt     keycode  72 = Ascii_8         
+keycode  73 = KP_9            
+       altgr   keycode  73 = Hex_9           
+       alt     keycode  73 = Ascii_9         
+keycode  74 = KP_Subtract     
+keycode  75 = KP_4            
+       altgr   keycode  75 = Hex_4           
+       alt     keycode  75 = Ascii_4         
+keycode  76 = KP_5            
+       altgr   keycode  76 = Hex_5           
+       alt     keycode  76 = Ascii_5         
+keycode  77 = KP_6            
+       altgr   keycode  77 = Hex_6           
+       alt     keycode  77 = Ascii_6         
+keycode  78 = KP_Add          
+keycode  79 = KP_1            
+       altgr   keycode  79 = Hex_1           
+       alt     keycode  79 = Ascii_1         
+keycode  80 = KP_2            
+       altgr   keycode  80 = Hex_2           
+       alt     keycode  80 = Ascii_2         
+keycode  81 = KP_3            
+       altgr   keycode  81 = Hex_3           
+       alt     keycode  81 = Ascii_3         
+keycode  82 = KP_0            
+       altgr   keycode  82 = Hex_0           
+       alt     keycode  82 = Ascii_0         
+keycode  83 = KP_Period       
+       altgr   control keycode  83 = Boot            
+       control alt     keycode  83 = Boot            
+keycode  84 = Last_Console    
+keycode  85 =
+keycode  86 = less             greater          bar             
+       alt     keycode  86 = Meta_less       
+       shift   alt     keycode  86 = Meta_greater    
+keycode  87 = F11              F23              Console_23       F35             
+       alt     keycode  87 = Console_11      
+       control alt     keycode  87 = Console_11      
+keycode  88 = F12              F24              Console_24       F36             
+       alt     keycode  88 = Console_12      
+       control alt     keycode  88 = Console_12      
+keycode  89 =
+keycode  90 =
+keycode  91 =
+keycode  92 =
+keycode  93 =
+keycode  94 =
+keycode  95 =
+keycode  96 = KP_Enter        
+keycode  97 = Control         
+keycode  98 = KP_Divide       
+       altgr   keycode  98 = Hex_B           
+keycode  99 = Control_backslash
+       alt     keycode  99 = Meta_Control_backslash
+       shift   alt     keycode  99 = Meta_Control_backslash
+       control alt     keycode  99 = Meta_Control_backslash
+keycode 100 = AltGr           
+keycode 101 = Break           
+keycode 102 = Find            
+keycode 103 = Up              
+       alt     keycode 103 = KeyboardSignal  
+keycode 104 = Prior           
+       shift   keycode 104 = Scroll_Backward 
+keycode 105 = Left            
+       alt     keycode 105 = Decr_Console    
+keycode 106 = Right           
+       alt     keycode 106 = Incr_Console    
+keycode 107 = Select          
+keycode 108 = Down            
+keycode 109 = Next            
+       shift   keycode 109 = Scroll_Forward  
+keycode 110 = Insert          
+keycode 111 = Remove          
+       altgr   control keycode 111 = Boot            
+       control alt     keycode 111 = Boot            
+keycode 112 = Macro           
+       altgr   control keycode 112 = VoidSymbol      
+       shift   alt     keycode 112 = VoidSymbol      
+keycode 113 = F13             
+       altgr   control keycode 113 = VoidSymbol      
+       shift   alt     keycode 113 = VoidSymbol      
+keycode 114 = F14             
+       altgr   control keycode 114 = VoidSymbol      
+       shift   alt     keycode 114 = VoidSymbol      
+keycode 115 = Help            
+       altgr   control keycode 115 = VoidSymbol      
+       shift   alt     keycode 115 = VoidSymbol      
+keycode 116 = Do              
+       altgr   control keycode 116 = VoidSymbol      
+       shift   alt     keycode 116 = VoidSymbol      
+keycode 117 = F17             
+       altgr   control keycode 117 = VoidSymbol      
+       shift   alt     keycode 117 = VoidSymbol      
+keycode 118 = KP_MinPlus      
+       altgr   control keycode 118 = VoidSymbol      
+       shift   alt     keycode 118 = VoidSymbol      
+keycode 119 = Pause           
+keycode 120 =
+keycode 121 =
+keycode 122 =
+keycode 123 =
+keycode 124 =
+keycode 125 =
+keycode 126 =
+keycode 127 =
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff --git a/drivers/usb/maps/usb.map b/drivers/usb/maps/usb.map
new file mode 100644 (file)
index 0000000..e05c71c
--- /dev/null
@@ -0,0 +1,233 @@
+# USB kernel keymap.
+keymaps 0-2,4-5,8,12
+
+keycode   4 = a
+       altgr   keycode  30 = Hex_A
+keycode   5 = b
+       altgr   keycode  48 = Hex_B
+keycode   6 = c
+       altgr   keycode  46 = Hex_C   
+keycode   7 = d
+       altgr   keycode  32 = Hex_D   
+keycode   8 = e
+       altgr   keycode  18 = Hex_E   
+keycode   9 = f
+       altgr   keycode  33 = Hex_F               
+keycode  10 = g               
+keycode  11 = h               
+keycode  12 = i               
+keycode  13 = j               
+keycode  14 = k               
+keycode  15 = l               
+keycode  16 = m               
+keycode  17 = n               
+keycode  18 = o               
+keycode  19 = p               
+keycode  20 = q               
+keycode  21 = r               
+keycode  22 = s               
+keycode  23 = t               
+keycode  24 = u               
+keycode  25 = v               
+keycode  26 = w               
+keycode  27 = x               
+keycode  28 = y               
+keycode  29 = z               
+keycode  30 = one              exclam          
+       alt     keycode   2 = Meta_one        
+keycode  31 = two              at
+       control keycode   3 = nul             
+       shift   control keycode   3 = nul             
+       alt     keycode   3 = Meta_two        
+keycode  32 = three            numbersign      
+       control keycode   4 = Escape          
+       alt     keycode   4 = Meta_three      
+keycode  33 = four             dollar
+       control keycode   5 = Control_backslash
+       alt     keycode   5 = Meta_four       
+keycode  34 = five             percent         
+       control keycode   6 = Control_bracketright
+       alt     keycode   6 = Meta_five       
+keycode  35 = six              asciicircum     
+       control keycode   7 = Control_asciicircum
+       alt     keycode   7 = Meta_six        
+keycode  36 = seven            ampersand
+       control keycode   8 = Control_underscore
+       alt     keycode   8 = Meta_seven      
+keycode  37 = eight            asterisk
+       control keycode   9 = Delete          
+       alt     keycode   9 = Meta_eight      
+keycode  38 = nine             parenleft
+       alt     keycode  10 = Meta_nine       
+keycode  39 = zero             parenright
+       alt     keycode  11 = Meta_zero       
+keycode  40 = Return          
+       alt     keycode  28 = Meta_Control_m  
+keycode  41 = Escape           Escape          
+       alt     keycode   1 = Meta_Escape     
+keycode  42 = Delete           Delete          
+       control keycode  14 = BackSpace
+       alt     keycode  14 = Meta_Delete     
+keycode  43 = Tab              Tab             
+       alt     keycode  15 = Meta_Tab        
+keycode  44 = space            space           
+       control keycode  57 = nul             
+       alt     keycode  57 = Meta_space      
+keycode  45 = minus            underscore       backslash       
+       control keycode  12 = Control_underscore
+       shift   control keycode  12 = Control_underscore
+       alt     keycode  12 = Meta_minus      
+keycode  46 = equal            plus            
+       alt     keycode  13 = Meta_equal      
+keycode  47 = bracketleft      braceleft       
+       control keycode  26 = Escape          
+       alt     keycode  26 = Meta_bracketleft
+keycode  48 = bracketright     braceright       asciitilde      
+       control keycode  27 = Control_bracketright
+       alt     keycode  27 = Meta_bracketright
+keycode  49 = backslash        bar             
+       control keycode  43 = Control_backslash
+       alt     keycode  43 = Meta_backslash  
+keycode 50 =
+keycode  51 = semicolon        colon           
+       alt     keycode  39 = Meta_semicolon  
+keycode  52 = apostrophe       quotedbl        
+       control keycode  40 = Control_g       
+       alt     keycode  40 = Meta_apostrophe 
+keycode  53 = grave            asciitilde      
+       control keycode  41 = nul             
+       alt     keycode  41 = Meta_grave      
+keycode  54 = comma            less            
+       alt     keycode  51 = Meta_comma      
+keycode  55 = period           greater         
+       control keycode  52 = Compose         
+       alt     keycode  52 = Meta_period     
+keycode  56 = slash            question        
+       control keycode  53 = Delete          
+       alt     keycode  53 = Meta_slash      
+keycode  57 = Caps_Lock       
+keycode  58 = F1               F11              Console_13      
+       control keycode  59 = F1              
+       alt     keycode  59 = Console_1       
+       control alt     keycode  59 = Console_1       
+keycode  59 = F2               F12              Console_14      
+       control keycode  60 = F2              
+       alt     keycode  60 = Console_2       
+       control alt     keycode  60 = Console_2       
+keycode  60 = F3               F13              Console_15      
+       control keycode  61 = F3              
+       alt     keycode  61 = Console_3       
+       control alt     keycode  61 = Console_3       
+keycode  61 = F4               F14              Console_16      
+       control keycode  62 = F4              
+       alt     keycode  62 = Console_4       
+       control alt     keycode  62 = Console_4       
+keycode  62 = F5               F15              Console_17      
+       control keycode  63 = F5              
+       alt     keycode  63 = Console_5       
+       control alt     keycode  63 = Console_5       
+keycode  63 = F6               F16              Console_18      
+       control keycode  64 = F6              
+       alt     keycode  64 = Console_6       
+       control alt     keycode  64 = Console_6       
+keycode  64 = F7               F17              Console_19      
+       control keycode  65 = F7              
+       alt     keycode  65 = Console_7       
+       control alt     keycode  65 = Console_7       
+keycode  65 = F8               F18              Console_20      
+       control keycode  66 = F8              
+       alt     keycode  66 = Console_8       
+       control alt     keycode  66 = Console_8       
+keycode  66 = F9               F19              Console_21      
+       control keycode  67 = F9              
+       alt     keycode  67 = Console_9       
+       control alt     keycode  67 = Console_9       
+keycode  67 = F10              F20              Console_22      
+       control keycode  68 = F10             
+       alt     keycode  68 = Console_10      
+       control alt     keycode  68 = Console_10      
+keycode  68 = F11              F11              Console_23      
+       control keycode  87 = F11             
+       alt     keycode  87 = Console_11      
+       control alt     keycode  87 = Console_11      
+keycode  69 = F12              F12              Console_24      
+       control keycode  88 = F12             
+       alt     keycode  88 = Console_12      
+       control alt     keycode  88 = Console_12      
+keycode  70 = Print_Screen
+keycode  71 = Scroll_Lock      Show_Memory      Show_Registers  
+       control keycode  70 = Show_State      
+       alt     keycode  70 = Scroll_Lock     
+keycode  72 = Pause           
+keycode  73 = Insert          
+keycode  74 = Home
+keycode  75 = Prior           
+       shift   keycode 104 = Scroll_Backward 
+keycode  76 = Remove          
+#      altgr   control keycode 111 = Boot            
+       control alt     keycode 111 = Boot            
+keycode  77 = End
+keycode  78 = Next            
+       shift   keycode 109 = Scroll_Forward  
+keycode  79 = Right           
+       alt     keycode 106 = Incr_Console
+keycode  80 = Left            
+       alt     keycode 105 = Decr_Console
+keycode  81 = Down            
+keycode  82 = Up              
+keycode  83 = Num_Lock
+       shift   keycode  69 = Bare_Num_Lock
+keycode  84 = KP_Divide       
+keycode  85 = KP_Multiply     
+keycode  86 = KP_Subtract     
+keycode  87 = KP_Add          
+keycode  88 = KP_Enter        
+keycode  89 = KP_1            
+       alt     keycode  79 = Ascii_1         
+       altgr   keycode  79 = Hex_1         
+keycode  90 = KP_2            
+       alt     keycode  80 = Ascii_2         
+       altgr   keycode  80 = Hex_2         
+keycode  91 = KP_3            
+       alt     keycode  81 = Ascii_3         
+       altgr   keycode  81 = Hex_3         
+keycode  92 = KP_4            
+       alt     keycode  75 = Ascii_4         
+       altgr   keycode  75 = Hex_4         
+keycode  93 = KP_5            
+       alt     keycode  76 = Ascii_5         
+       altgr   keycode  76 = Hex_5         
+keycode  94 = KP_6            
+       alt     keycode  77 = Ascii_6         
+       altgr   keycode  77 = Hex_6         
+keycode  95 = KP_7            
+       alt     keycode  71 = Ascii_7         
+       altgr   keycode  71 = Hex_7         
+keycode  96 = KP_8            
+       alt     keycode  72 = Ascii_8         
+       altgr   keycode  72 = Hex_8         
+keycode  97 = KP_9            
+       alt     keycode  73 = Ascii_9         
+       altgr   keycode  73 = Hex_9         
+keycode  98 = KP_0            
+       alt     keycode  82 = Ascii_0         
+       altgr   keycode  82 = Hex_0         
+keycode  99 = KP_Period       
+#      altgr   control keycode  83 = Boot            
+       control alt     keycode  83 = Boot            
+keycode 100 =
+keycode 101 = Application
+keycode 102 =
+keycode 103 =
+keycode 104 = F13             
+keycode 105 = F14             
+
+# modifiers
+keycode 120 = Control
+keycode 121 = Shift
+keycode 122 = Alt
+keycode 123 = Window
+keycode 124 = Control_R
+keycode 125 = Shift_R
+keycode 126 = Alt_R
+keycode 127 = Window_R
diff --git a/drivers/usb/mkmap b/drivers/usb/mkmap
new file mode 100644 (file)
index 0000000..35808f2
--- /dev/null
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+($ME = $0) =~ s|.*/||;
+
+$file = "maps/serial.map";
+$line = 1;
+open(PC, $file) || die("$!");
+while(<PC>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/)
+    {
+       my($idx) = int($1);
+       my($sym) = $2;
+       if(defined($map{uc($sym)}))
+       {
+           # print STDERR "$file:$line: warning: `$sym' redefined\n";
+       }
+       $map{uc($sym)} = $idx;
+    }
+    $line++;
+}
+close(PC);
+
+$file = "maps/fixup.map";
+$line = 1;
+open(FIXUP, $file) || die("$!");
+while(<FIXUP>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*/)
+    {
+       my($idx) = int($1);
+       for $sym (split(/\s+/, $'))
+        {
+           $map{uc($sym)} = $idx;
+       }
+    }
+    $line++;
+}
+close(FIXUP);
+
+$file = "maps/usb.map";
+$line = 1;
+open(USB, $file) || die("$!");
+while(<USB>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*/)
+    {
+       my($idx) = int($1);
+       for $sym (split(/\s+/, $'))
+        {
+           my($val) = $map{uc($sym)};
+           $map[$idx] = $val;
+           if(!defined($val))
+           {
+               print STDERR "$file:$line: warning: `$sym' undefined\n";
+           }
+           else
+           {
+               last;
+           }
+       }
+    }
+    $line++;
+}
+close(USB);
+
+print "unsigned char usb_kbd_map[256] = \n{\n";
+for($x = 0; $x < 32; $x++)
+{
+    if($x && !($x % 2))
+    {
+       print "\n";
+    }
+    print "  ";
+    for($y = 0; $y < 8; $y++)
+    {
+       my($idx) = $x * 8 + $y;
+       print sprintf("  0x%02x,",
+                     int(defined($map[$idx]) ? $map[$idx]:0));
+    }
+    print "\n";
+}
+print "};\n";
diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c
new file mode 100644 (file)
index 0000000..a724a40
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ * USB HID boot protocol mouse support based on MS BusMouse driver, psaux 
+ * driver, and Linus's skeleton USB mouse driver
+ *
+ * Brad Keryan 4/3/1999
+ *
+ * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events.
+ * This is wrong: when an application (like X or gpm) reads the mouse device,
+ * it wants to find out the mouse's current position, not its recent history.
+ * The button thing turned out to be UHCI not flipping data toggle, so half the
+ * packets were thrown out.
+ *
+ * version 0.01: Switched over to busmouse protocol, and changed the minor
+ * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, 
+ * but it still doesn't generate button events unless you move the mouse.
+ *
+ * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I 
+ * know that's not very nice). Moving in the X and Y axes works. Buttons don't
+ * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease 
+ * combos when you hold down a button and drag the mouse around. Probably has 
+ * some additional bugs on an SMP machine.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+#define USB_MOUSE_MINOR 32
+
+struct mouse_state {
+       unsigned char buttons; /* current button state */
+       long dx; /* dx, dy, dz are change since last read */
+       long dy; 
+       long dz;
+       int present; /* this mouse is plugged in */
+       int active; /* someone is has this mouse's device open */
+       int ready; /* the mouse has changed state since the last read */
+       struct wait_queue *wait; /* for polling */
+       struct fasync_struct *fasync;
+       /* later, add a list here to support multiple mice */
+       /* but we will also need a list of file pointers to identify it */
+};
+
+static struct mouse_state static_mouse_state;
+
+spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
+
+static int mouse_irq(int state, void *__buffer, void *dev_id)
+{
+       signed char *data = __buffer;
+       /* finding the mouse is easy when there's only one */
+       struct mouse_state *mouse = &static_mouse_state; 
+
+       /* if a mouse moves with no one listening, do we care? no */
+       if(!mouse->active)
+               return 1;
+
+       /* if the USB mouse sends an interrupt, then something noteworthy
+          must have happened */
+       mouse->buttons = data[0] & 0x07;
+       mouse->dx += data[1]; /* data[] is signed, so this works */
+       mouse->dy -= data[2]; /* y-axis is reversed */
+       mouse->dz += data[3];
+       mouse->ready = 1;
+
+       add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + 
+                                    (mouse->dy << 8) + mouse->dx);
+
+       wake_up_interruptible(&mouse->wait);
+       if (mouse->fasync)
+               kill_fasync(mouse->fasync, SIGIO);
+
+       return 1;
+}
+
+static int fasync_mouse(int fd, struct file *filp, int on)
+{
+       int retval;
+       struct mouse_state *mouse = &static_mouse_state;
+
+       retval = fasync_helper(fd, filp, on, &mouse->fasync);
+       if (retval < 0)
+               return retval;
+       return 0;
+}
+
+static int release_mouse(struct inode * inode, struct file * file)
+{
+       struct mouse_state *mouse = &static_mouse_state;
+
+       fasync_mouse(-1, file, 0);
+       if (--mouse->active)
+               return 0;
+       return 0;
+}
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+       struct mouse_state *mouse = &static_mouse_state;
+
+       if (!mouse->present)
+               return -EINVAL;
+       if (mouse->active++)
+               return 0;
+       /* flush state */
+       mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
+       return 0;
+}
+
+static ssize_t write_mouse(struct file * file,
+       const char * buffer, size_t count, loff_t *ppos)
+{
+       return -EINVAL;
+}
+
+/*
+ * Look like a PS/2 mouse, please..
+ *
+ * The PS/2 protocol is fairly strange, but
+ * oh, well, it's at least common..
+ */
+static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos)
+{
+       int retval = 0;
+       static int state = 0;
+       struct mouse_state *mouse = &static_mouse_state;
+
+       if (count) {
+               mouse->ready = 0;
+               switch (state) {
+               case 0: { /* buttons and sign */
+                       int buttons = mouse->buttons;
+                       mouse->buttons = 0;
+                       if (mouse->dx < 0)
+                               buttons |= 0x10;
+                       if (mouse->dy < 0)
+                               buttons |= 0x20;
+                       put_user(buttons, buffer);
+                       buffer++;
+                       retval++;
+                       state = 1;
+                       if (!--count)
+                               break;
+               }
+               case 1: { /* dx */
+                       int dx = mouse->dx;
+                       mouse->dx = 0;
+                       put_user(dx, buffer);
+                       buffer++;
+                       retval++;
+                       state = 2;
+                       if (!--count)
+                               break;
+               }
+               case 2: { /* dy */
+                       int dy = mouse->dy;
+                       mouse->dy = 0;
+                       put_user(dy, buffer);
+                       buffer++;
+                       retval++;
+                       state = 0;
+               }
+               break;
+               }
+       }
+       return retval;
+}
+
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
+{
+       struct mouse_state *mouse = &static_mouse_state;
+
+       poll_wait(file, &mouse->wait, wait);
+       if (mouse->ready)
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+struct file_operations usb_mouse_fops = {
+       NULL,           /* mouse_seek */
+       read_mouse,
+       write_mouse,
+       NULL,           /* mouse_readdir */
+       mouse_poll,     /* mouse_poll */
+       NULL,           /* mouse_ioctl */
+       NULL,           /* mouse_mmap */
+       open_mouse,
+       NULL,           /* flush */
+       release_mouse,
+       NULL,
+       fasync_mouse,
+};
+
+static struct miscdevice usb_mouse = {
+       USB_MOUSE_MINOR, "USB mouse", &usb_mouse_fops
+};
+
+static int mouse_probe(struct usb_device *dev)
+{
+       struct usb_interface_descriptor *interface;
+       struct usb_endpoint_descriptor *endpoint;
+       struct mouse_state *mouse = &static_mouse_state;
+
+       /* We don't handle multi-config mice */
+       if (dev->descriptor.bNumConfigurations != 1)
+               return -1;
+
+       /* We don't handle multi-interface mice */
+       if (dev->config[0].bNumInterfaces != 1)
+               return -1;
+
+       /* Is it a mouse interface? */
+       interface = &dev->config[0].interface[0];
+       if (interface->bInterfaceClass != 3)
+               return -1;
+       if (interface->bInterfaceSubClass != 1)
+               return -1;
+       if (interface->bInterfaceProtocol != 2)
+               return -1;
+
+       /* Multiple endpoints? What kind of mutant ninja-mouse is this? */
+       if (interface->bNumEndpoints != 1)
+               return -1;
+
+       endpoint = &interface->endpoint[0];
+
+       /* Output endpoint? Curiousier and curiousier.. */
+       if (!(endpoint->bEndpointAddress & 0x80))
+               return -1;
+
+       /* If it's not an interrupt endpoint, we'd better punt! */
+       if ((endpoint->bmAttributes & 3) != 3)
+               return -1;
+
+       printk("USB mouse found\n");
+
+       usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+
+       usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL);
+
+       mouse->present = 1;
+       return 0;
+}
+
+static void mouse_disconnect(struct usb_device *dev)
+{
+       struct mouse_state *mouse = &static_mouse_state;
+
+       /* this might need work */
+       mouse->present = 0;
+}
+
+static struct usb_driver mouse_driver = {
+       "mouse",
+       mouse_probe,
+       mouse_disconnect,
+       { NULL, NULL }
+};
+
+int usb_mouse_init(void)
+{
+       struct mouse_state *mouse = &static_mouse_state;
+
+       misc_register(&usb_mouse);
+
+       mouse->present = mouse->active = 0;
+       mouse->wait = NULL;
+       mouse->fasync = NULL;
+
+       usb_register(&mouse_driver);
+       printk(KERN_INFO "USB HID boot protocol mouse registered.\n");
+       return 0;
+}
+
+#if 0
+
+int init_module(void)
+{
+       return usb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+       /* this, too, probably needs work */
+       usb_deregister(&mouse_driver);
+       misc_deregister(&usb_mouse);
+}
+
+#endif
diff --git a/drivers/usb/ohci-debug.c b/drivers/usb/ohci-debug.c
new file mode 100644 (file)
index 0000000..5f90bbe
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * OHCI debugging code.  It's gross.
+ *
+ * (C) Copyright 1999 Gregory P. Smith
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "ohci.h"
+
+void show_ohci_status(struct ohci *ohci)
+{
+       struct ohci_regs regs;
+       int i;
+
+       regs.revision = readl(ohci->regs->revision);
+       regs.control = readl(ohci->regs->control);
+       regs.cmdstatus = readl(ohci->regs->cmdstatus);
+       regs.intrstatus = readl(ohci->regs->intrstatus);
+       regs.intrenable = readl(ohci->regs->intrenable);
+       regs.intrdisable = readl(ohci->regs->intrdisable);
+       regs.hcca = readl(ohci->regs->hcca);
+       regs.ed_periodcurrent = readl(ohci->regs->ed_periodcurrent);
+       regs.ed_controlhead = readl(ohci->regs->ed_controlhead);
+       regs.ed_bulkhead = readl(ohci->regs->ed_bulkhead);
+       regs.ed_bulkcurrent = readl(ohci->regs->ed_bulkcurrent);
+       regs.current_donehead = readl(ohci->regs->current_donehead);
+       regs.fminterval = readl(ohci->regs->fminterval);
+       regs.fmremaining = readl(ohci->regs->fmremaining);
+       regs.fmnumber = readl(ohci->regs->fmnumber);
+       regs.periodicstart = readl(ohci->regs->periodicstart);
+       regs.lsthresh = readl(ohci->regs->lsthresh);
+       regs.roothub.a = readl(ohci->regs->roothub.a);
+       regs.roothub.b = readl(ohci->regs->roothub.b);
+       regs.roothub.status = readl(ohci->regs->roothub.status);
+       for (i=0; i<MAX_ROOT_PORTS; ++i)
+               regs.roothub.portstatus[i] = readl(ohci->regs->roothub.portstatus[i]);
+
+       printk("  ohci revision    =  0x%x\n", regs.revision);
+       printk("  ohci control     =  0x%x\n", regs.control);
+       printk("  ohci cmdstatus   =  0x%x\n", regs.cmdstatus);
+       printk("  ohci intrstatus  =  0x%x\n", regs.intrstatus);
+       printk("  ohci roothub.a   =  0x%x\n", regs.roothub.a);
+       printk("  ohci roothub.b   =  0x%x\n", regs.roothub.b);
+       printk("  ohci root status =  0x%x\n", regs.roothub.status);
+} /* show_ohci_status() */
+
+
+static void show_ohci_ed(struct ohci_ed *ed)
+{
+       int stat = ed->status;
+       int skip = (stat & OHCI_ED_SKIP);
+       int mps = (stat & OHCI_ED_MPS) >> 16;
+       int isoc = (stat & OHCI_ED_F_ISOC);
+       int low_speed = (stat & OHCI_ED_S_LOW);
+       int dir = (stat & OHCI_ED_D);
+       int endnum = (stat & OHCI_ED_EN) >> 7;
+       int funcaddr = (stat & OHCI_ED_FA);
+       int halted = (ed->head_td & 1);
+       int toggle = (ed->head_td & 2) >> 1;
+
+       printk("   ohci ED:\n");
+       printk("     status     =  0x%x\n", stat);
+       printk("       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
+                       skip ? "Skip " : "",
+                       mps,
+                       isoc ? "Isoc. " : "",
+                       low_speed ? "LowSpd " : "",
+                       (dir == OHCI_ED_D_IN) ? "Input " :
+                       (dir == OHCI_ED_D_OUT) ? "Output " : "",
+                       halted ? "Halted " : "",
+                       toggle,
+                       endnum,
+                       funcaddr);
+       printk("     tail_td    =  0x%x\n", ed->tail_td);
+       printk("     head_td    =  0x%x\n", ed->head_td);
+       printk("     next_ed    =  0x%x\n", ed->next_ed);
+} /* show_ohci_ed() */
+
+
+static void show_ohci_td(struct ohci_td *td)
+{
+       int td_round = td->info & OHCI_TD_ROUND;
+       int td_dir = td->info & OHCI_TD_D;
+       int td_int_delay = td->info & OHCI_TD_IOC_DELAY;
+       int td_toggle = td->info & OHCI_TD_DT;
+       int td_errcnt = td_errorcount(td->info);
+       int td_cc = td->info & OHCI_TD_CC;
+
+       printk("   ohci TD hardware fields:\n");
+       printk("      info     =  0x%x\n", td->info);
+       printk("        %s%s%s%d%s%s%d%s%d\n",
+               td_round ? "Rounding " : "",
+               (td_dir == OHCI_TD_D_IN) ? "Input " :
+               (td_dir == OHCI_TD_D_OUT) ? "Output " :
+               (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
+               "IntDelay ", td_int_delay >> 21,
+               td_toggle ? "Data1 " : "Data0 ",
+               "ErrorCnt ", td_errcnt,
+               "ComplCode ", td_cc);
+       printk("       %sAccessed, %sActive\n",
+                       td_cc_accessed(td->info) ? "" : "Not ",
+                       td_active(td->info) ? "" : "Not ");
+
+       printk("      cur_buf  =  0x%x\n", td->cur_buf);
+       printk("      next_td  =  0x%x\n", td->next_td);
+       printk("      buf_end  =  0x%x\n", td->buf_end);
+       printk("   ohci TD driver fields:\n");
+       printk("      data     =  %p\n", td->data);
+       printk("      dev_id   =  %p\n", td->dev_id);
+       printk("      ed_bus   =  %x\n", td->ed_bus);
+} /* show_ohci_td() */
+
+
+void show_ohci_device(struct ohci_device *dev)
+{
+       int idx;
+       printk("  ohci_device usb       =  %p\n", dev->usb);
+       printk("  ohci_device ohci      =  %p\n", dev->ohci);
+       printk("  ohci_device ohci_hcca =  %p\n", dev->hcca);
+       for (idx=0; idx<8 /*NUM_EDS*/; ++idx) {
+               printk("   [ed num %d] ", idx);
+               show_ohci_ed(&dev->ed[idx]);
+       }
+       for (idx=0; idx<8 /*NUM_TDS*/; ++idx) {
+               printk("   [td num %d] ", idx);
+               show_ohci_td(&dev->td[idx]);
+       }
+       printk("  ohci_device data\n    ");
+       for (idx=0; idx<4; ++idx) {
+               printk(" %08lx", dev->data[idx]);
+       }
+       printk("\n");
+} /* show_ohci_device() */
+
+
+/* vim:sw=8
+ */
diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c
new file mode 100644 (file)
index 0000000..6207dcd
--- /dev/null
@@ -0,0 +1,1040 @@
+/*
+ * Open Host Controller Interface driver for USB.
+ *
+ * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
+ *
+ * This is the "other" host controller interface for USB.  You will
+ * find this on many non-Intel based motherboards, and of course the
+ * Mac.  As Linus hacked his UHCI driver together first, I modeled
+ * this after his.. (it should be obvious)
+ *
+ * From the programming standpoint the OHCI interface seems a little
+ * prettier and potentially less CPU intensive.  This remains to be
+ * proven.  In reality, I don't believe it'll make one darn bit of
+ * difference.  USB v1.1 is a slow bus by today's standards.
+ *
+ * OHCI hardware takes care of most of the scheduling of different
+ * transfer types with the correct prioritization for us.
+ *
+ * To get started in USB, I used the "Universal Serial Bus System
+ * Architecture" book by Mindshare, Inc.  It was a reasonable introduction
+ * and overview of USB and the two dominant host controller interfaces
+ * however you're better off just reading the real specs available
+ * from www.usb.org as you'll need them to get enough detailt to
+ * actually implement a HCD.  The book has many typos and omissions
+ * Beware, the specs are the victim of a committee.
+ *
+ * This code was written with Guinness on the brain, xsnow on the desktop
+ * and Orbital, Orb, Enya & Massive Attack on the CD player.  What a life!  ;) 
+ *
+ * No filesystems were harmed in the development of this code.
+ *
+ * $Id: ohci.c,v 1.11 1999/04/25 00:18:52 greg Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "ohci.h"
+#include "inits.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+static struct wait_queue *ohci_configure = NULL;
+
+
+static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
+{
+       unsigned int status;
+
+       status = td->info & OHCI_TD_CC;
+
+       /* TODO Debugging code for TD failures goes here */
+
+       return status;
+}
+
+
+static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Add a TD to the end of the TD list on a given ED.  td->next_td is
+ * assumed to be set correctly for the situation of no TDs already
+ * being on the list (ie: pointing to NULL).
+ */
+static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+       struct ohci_td *tail = bus_to_virt(ed->tail_td);
+       struct ohci_td *head = bus_to_virt(ed->head_td);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+       if (tail == head) {     /* empty list, put it on the head */
+               head = (struct ohci_td *) virt_to_bus(td);
+               tail = 0;
+       } else {
+               if (!tail) {    /* no tail, single element list */
+                       td->next_td = head->next_td;
+                       head->next_td = virt_to_bus(td);
+                       tail = (struct ohci_td *) virt_to_bus(td);
+               } else {        /* append to the list */
+                       td->next_td = tail->next_td;
+                       tail->next_td = virt_to_bus(td);
+                       tail = (struct ohci_td *) virt_to_bus(td);
+               }
+       }
+       /* save the reverse link */
+       td->ed_bus = virt_to_bus(ed);
+
+       spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_add_td_to_ed() */
+
+
+/*
+ *  Remove a TD from the given EDs TD list
+ */
+static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+       struct ohci_td *head = bus_to_virt(ed->head_td);
+       struct ohci_td *tmp_td;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+       /* set the "skip me bit" in this ED */
+       writel_set(OHCI_ED_SKIP, ed->status);
+
+       /* XXX Assuming this list will never be circular */
+
+       if (td == head) {
+               /* unlink this TD; it was at the beginning */
+               ed->head_td = head->next_td;
+       }
+
+       tmp_td = head;
+       head = (struct ohci_td *) ed->head_td;
+       
+       while (head != NULL) {
+
+               if (td == head) {
+                       /* unlink this TD from the middle or end */
+                       tmp_td->next_td = head->next_td;
+               }
+
+               tmp_td = head;
+               head = bus_to_virt(head->next_td);
+       }
+
+       td->next_td = virt_to_bus(NULL);  /* remove links to ED list */
+
+       /* XXX mark this TD for possible cleanup? */
+
+       /* unset the "skip me bit" in this ED */
+       writel_mask(~(__u32)OHCI_ED_SKIP, ed->status);
+
+       spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_remove_td_from_ed() */
+
+
+/*
+ * Get a pointer (virtual) to an available TD from the given device's
+ * pool.
+ *
+ * Return NULL if none are left.
+ */
+static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
+{
+       int idx;
+
+       for (idx=0; idx < NUM_TDS; idx++) {
+               if (td_done(dev->td[idx].info)) {
+                       /* XXX should this also zero out the structure? */
+                       /* mark all new TDs as unaccessed */
+                       dev->td[idx].info = OHCI_TD_CC_NEW;
+                       return &dev->td[idx];
+               }
+       }
+
+       return NULL;
+} /* ohci_get_free_td() */
+
+
+/**********************************
+ * OHCI interrupt list operations *
+ **********************************/
+static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
+
+static void ohci_add_irq_list(struct ohci *ohci, struct ohci_td *td, usb_device_irq completed, void *dev_id)
+{
+       unsigned long flags;
+
+       /* save the irq in our private portion of the TD */
+       td->completed = completed;
+       td->dev_id = dev_id;
+
+       spin_lock_irqsave(&irqlist_lock, flags);
+       list_add(&td->irq_list, &ohci->interrupt_list);
+       spin_unlock_irqrestore(&irqlist_lock, flags);
+} /* ohci_add_irq_list() */
+
+static void ohci_remove_irq_list(struct ohci_td *td)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&irqlist_lock, flags);
+       list_del(&td->irq_list);
+       spin_unlock_irqrestore(&irqlist_lock, flags);
+} /* ohci_remove_irq_list() */
+
+/*
+ * Request an interrupt handler for one "pipe" of a USB device.
+ * (this function is pretty minimal right now)
+ *
+ * At the moment this is only good for input interrupts. (ie: for a
+ * mouse)
+ *
+ * period is desired polling interval in ms.  The closest, shorter
+ * match will be used.  Powers of two from 1-32 are supported by OHCI.
+ */
+static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
+       usb_device_irq handler, int period, void *dev_id)
+{
+       struct ohci_device *dev = usb_to_ohci(usb);
+       struct ohci_td *td = dev->td;   /* */
+       struct ohci_ed *interrupt_ed;   /* endpoint descriptor for this irq */
+
+       /*
+        * Pick a good frequency endpoint based on the requested period
+        */
+       interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)];
+
+       /*
+        * Set the max packet size, device speed, endpoint number, usb
+        * device number (function address), and type of TD.
+        *
+        * FIXME: Isochronous transfers need a pool of special 32 byte
+        * TDs (32 byte aligned) in order to be supported.
+        */
+       interrupt_ed->status = \
+               ed_set_maxpacket(usb_maxpacket(pipe)) |
+               ed_set_speed(usb_pipeslow(pipe)) |
+               usb_pipe_endpdev(pipe) |
+               OHCI_ED_F_NORM;
+
+       /*
+        * Set the not accessed condition code, allow odd sized data,
+        * and set the data transfer direction.
+        */
+       td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
+               td_set_dir_out(usb_pipeout(pipe));
+
+       /* point it to our data buffer */
+       td->cur_buf = virt_to_bus(dev->data);
+
+       /* FIXME: we're only using 1 TD right now! */
+       td->next_td = virt_to_bus(&td);
+
+       /*
+        * FIXME: be aware that OHCI won't advance out of the 4kb
+        * page cur_buf started in.  It'll wrap around to the start
+        * of the page...  annoying or useful? you decide.
+        *
+        * A pointer to the last *byte* in the buffer (ergh.. we get
+        * to work around C's pointer arithmatic here with a typecast)
+        */
+       td->buf_end = virt_to_bus(((u8*)(dev->data + DATA_BUF_LEN)) - 1);
+
+       /* does this make sense for ohci?.. time to think.. */
+       ohci_add_irq_list(dev->ohci, td, handler, dev_id);
+       wmb();     /* found in asm/system.h; scary concept... */
+       ohci_add_td_to_ed(td, interrupt_ed);
+
+       return 0;
+} /* ohci_request_irq() */
+
+/*
+ * Control thread operations:
+ */
+static struct wait_queue *control_wakeup;
+
+static int ohci_control_completed(int stats, void *buffer, void *dev_id)
+{
+       wake_up(&control_wakeup);
+       return 0;
+} /* ohci_control_completed() */
+
+
+/*
+ * Run a control transaction from the root hub's control endpoint.
+ * The passed in TD is the control transfer's Status TD.
+ */
+static int ohci_run_control(struct ohci_device *dev, struct ohci_td *status_td)
+{
+       struct wait_queue wait = { current, NULL };
+       struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
+
+       current->state = TASK_UNINTERRUPTIBLE;
+       add_wait_queue(&control_wakeup, &wait);
+
+       ohci_add_irq_list(dev->ohci, status_td, ohci_control_completed, NULL);
+       ohci_add_td_to_ed(status_td, control_ed);
+
+       /* FIXME? isn't this a little gross */
+       schedule_timeout(HZ/10);
+
+       ohci_remove_irq_list(status_td);
+       ohci_remove_td_from_ed(status_td, control_ed);
+
+       return ohci_td_result(dev, status_td);
+} /* ohci_run_control() */
+
+/*
+ * Send or receive a control message on a "pipe"
+ *
+ * A control message contains:
+ *   - The command itself
+ *   - An optional data phase
+ *   - Status complete phase
+ *
+ * The data phase can be an arbitrary number of TD's.  Currently since
+ * we use statically allocated TDs if too many come in we'll just
+ * start tossing them and printk() some warning goo...  Most control
+ * messages won't have much data anyways.
+ */
+static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
+{
+       struct ohci_device *dev = usb_to_ohci(usb);
+       /*
+        * ideally dev->ed should be linked into the root hub's
+        * control_ed list and used instead of just using it directly.
+        * This could present a problem as is with more than one
+        * device.  (but who wants to use a keyboard AND a mouse
+        * anyways? ;)
+        */
+       struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
+       struct ohci_td *control_td;
+       struct ohci_td *data_td;
+       struct ohci_td *last_td;
+       __u32 data_td_info;
+
+       /*
+        * Set the max packet size, device speed, endpoint number, usb
+        * device number (function address), and type of TD.
+        *
+        */
+       control_ed->status = \
+               ed_set_maxpacket(usb_maxpacket(pipe)) |
+               ed_set_speed(usb_pipeslow(pipe)) |
+               usb_pipe_endpdev(pipe) |
+               OHCI_ED_F_NORM;
+
+       /*
+        * Build the control TD
+        */
+
+       /* get a TD to send this control message with */
+       control_td = ohci_get_free_td(dev);
+       /* TODO check for NULL */
+
+       /*
+        * Set the not accessed condition code, allow odd sized data,
+        * and set the data transfer type to SETUP.  Setup DATA always
+        * uses a DATA0 packet.
+        */
+       control_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
+               OHCI_TD_D_SETUP | OHCI_TD_IOC_OFF | td_force_toggle(0);
+
+       /* point it to the command */
+       control_td->cur_buf = virt_to_bus(cmd);
+
+       /* link to a free TD for the control data input */
+       data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+       control_td->next_td = virt_to_bus(data_td);
+
+       /*
+        * Build the DATA TDs
+        */
+
+       data_td_info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | OHCI_TD_IOC_OFF |
+               td_set_dir_out(usb_pipeout(pipe));
+
+       while (len > 0) {
+               int pktsize = len;
+               struct ohci_td *tmp_td;
+
+               if (pktsize > usb_maxpacket(pipe))
+                       pktsize = usb_maxpacket(pipe);
+
+               /* set the data transaction type */
+               data_td->info = data_td_info;
+               /* point to the current spot in the data buffer */
+               data_td->cur_buf = virt_to_bus(data);
+               /* point to the end of this data */
+               data_td->buf_end = virt_to_bus(data+pktsize-1);
+
+               /* allocate the next TD */
+               tmp_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+               data_td->next_td = virt_to_bus(tmp_td);
+               data_td = tmp_td;
+
+               /* move on.. */
+               data += pktsize;
+               len -= pktsize;
+       }
+
+       /* point it at the newly allocated TD from above */
+       last_td = data_td;
+
+       /* The control status packet always uses a DATA1 */
+       last_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | td_force_toggle(1);
+       last_td->next_td = 0; /* end of TDs */
+       last_td->cur_buf = 0; /* no data in this packet */
+       last_td->buf_end = 0;
+
+       /*
+        * Start the control transaction.. give it the last TD so the
+        * result can be returned.
+        */
+       return ohci_run_control(dev, last_td);
+} /* ohci_control_msg() */
+
+
+static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
+{
+       struct usb_device *usb_dev;
+       struct ohci_device *dev;
+
+       usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
+       if (!usb_dev)
+               return NULL;
+
+       memset(usb_dev, 0, sizeof(*usb_dev));
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               kfree(usb_dev);
+               return NULL;
+       }
+
+       /* Initialize "dev" */
+       memset(dev, 0, sizeof(*dev));
+
+       usb_dev->hcpriv = dev;
+       dev->usb = usb_dev;
+
+       usb_dev->parent = parent;
+
+       if (parent) {
+               usb_dev->bus = parent->bus;
+               dev->ohci = usb_to_ohci(parent)->ohci;
+       }
+
+       return usb_dev;
+}
+
+static int ohci_usb_deallocate(struct usb_device *usb_dev)
+{
+       kfree(usb_to_ohci(usb_dev));
+       kfree(usb_dev);
+       return 0;
+}
+
+/*
+ * functions for the generic USB driver
+ */
+struct usb_operations ohci_device_operations = {
+       ohci_usb_allocate,
+       ohci_usb_deallocate,
+       ohci_control_msg,
+       ohci_request_irq,
+};
+
+/*
+ * Reset an OHCI controller
+ */
+static void reset_hc(struct ohci *ohci)
+{
+       writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+       writel(1,  &ohci->regs->cmdstatus);        /* HC Reset */
+       writel_mask(0x3f, &ohci->regs->control);   /* move to UsbReset state */
+} /* reset_hc() */
+
+
+/*
+ * Reset and start an OHCI controller
+ */
+static void start_hc(struct ohci *ohci)
+{
+       int timeout = 1000;     /* used to prevent an infinite loop. */
+
+       reset_hc(ohci);
+
+       while ((readl(&ohci->regs->control) & 0xc0) == 0) {
+               if (!--timeout) {
+                       printk("USB HC Reset timed out!\n");
+                       break;
+               }
+       }
+
+       /* Choose the interrupts we care about */
+       writel( OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_SF |
+               OHCI_INTR_WDH | OHCI_INTR_SO | OHCI_INTR_UE |
+               OHCI_INTR_FNO,
+               &ohci->regs->intrenable);
+
+       /* Enter the USB Operational state & start the frames a flowing.. */
+       writel_set(OHCI_USB_OPER, &ohci->regs->control);
+
+} /* start_hc() */
+
+
+/*
+ * Reset a root hub port
+ */
+static void ohci_reset_port(struct ohci *ohci, unsigned int port)
+{
+       short ms;
+       int status;
+
+       /* Don't allow overflows. */
+       if (port >= MAX_ROOT_PORTS) {
+               printk("Bad port # passed to ohci_reset_port\n");
+               port = MAX_ROOT_PORTS-1;
+       }
+
+       writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);  /* Reset */
+
+       /*
+        * Get the time required for a root hub port to reset and wait
+        * it out (adding 1ms for good measure).
+        */
+       ms = (readl(&ohci->regs->roothub.a) >> 24) * 2 + 1;
+       wait_ms(ms);
+
+       /* check port status to see that the reset completed */
+       status = readl(&ohci->regs->roothub.portstatus[port]);
+       if (status & PORT_PRS) {
+               /* reset failed, try harder? */
+               printk("usb-ohci: port %d reset failed, retrying\n", port);
+               writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);
+               wait_ms(50);
+       }
+
+       /* TODO we might need to re-enable the port here or is that
+        * done elsewhere? */
+
+} /* ohci_reset_port */
+
+
+/*
+ * This gets called if the connect status on the root hub changes.
+ */
+static void ohci_connect_change(struct ohci * ohci, int port)
+{
+       struct usb_device *usb_dev;
+       struct ohci_device *dev;
+       /* memory I/O address of the port status register */
+       void *portaddr = &ohci->regs->roothub.portstatus[port];
+       int portstatus; 
+
+       /*
+        * Because of the status change we have to forget
+        * everything we think we know about the device
+        * on this root hub port.  It may have changed.
+        */
+       usb_disconnect(ohci->root_hub->usb->children + port);
+
+       portstatus = readl(portaddr);
+
+       /* disable the port if nothing is connected */
+       if (!(portstatus & PORT_CCS)) {
+               writel(PORT_CCS, portaddr);
+               return;
+       }
+
+       /*
+        * Allocate a device for the new thingy that's been attached
+        */
+       usb_dev = ohci_usb_allocate(ohci->root_hub->usb);
+       dev = usb_dev->hcpriv;
+
+       dev->ohci = ohci;
+
+       usb_connect(dev->usb);
+
+       /* link it into the bus's device tree */
+       ohci->root_hub->usb->children[port] = usb_dev;
+
+       wait_ms(200); /* wait for powerup; XXX is this needed? */
+       ohci_reset_port(ohci, port);
+
+       /* Get information on speed by using LSD */
+       usb_dev->slow = readl(portaddr) & PORT_LSDA ? 1 : 0;
+
+       /*
+        * Do generic USB device tree processing on the new device.
+        */
+       usb_new_device(usb_dev);
+} /* ohci_connect_change() */
+
+
+/*
+ * This gets called when the root hub configuration
+ * has changed.  Just go through each port, seeing if
+ * there is something interesting happening.
+ */
+static void ohci_check_configuration(struct ohci *ohci)
+{
+       int num = 0;
+       int maxport = readl(&ohci->regs->roothub) & 0xff;
+
+       do {
+               if (readl(ohci->regs->roothub.portstatus[num]) & PORT_CSC)
+                       ohci_connect_change(ohci, num);
+       } while (++num < maxport);
+} /* ohci_check_configuration() */
+
+
+/*
+ * Get annoyed at the controller for bothering us.
+ */
+static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
+{
+       struct ohci *ohci = __ohci;
+       struct ohci_regs *regs = ohci->regs;
+       struct ohci_hcca *hcca = ohci->root_hub->hcca;
+       __u32 donehead = hcca->donehead;
+
+       /*
+        * Check the interrupt status register if needed
+        */
+       if (!donehead || (donehead & 1)) {
+               __u32 intrstatus = readl(&regs->intrstatus);
+
+               /*
+                * XXX eek! printk's in an interrupt handler.  shoot me!
+                */
+               if (intrstatus & OHCI_INTR_SO) {
+                       printk(KERN_DEBUG "usb-ohci: scheduling overrun\n");
+               }
+               if (intrstatus & OHCI_INTR_RD) {
+                       printk(KERN_DEBUG "usb-ohci: resume detected\n");
+               }
+               if (intrstatus & OHCI_INTR_UE) {
+                       printk(KERN_DEBUG "usb-ohci: unrecoverable error\n");
+               }
+               if (intrstatus & OHCI_INTR_OC) {
+                       printk(KERN_DEBUG "usb-ohci: ownership change?\n");
+               }
+
+               if (intrstatus & OHCI_INTR_RHSC) {
+                       /* TODO Process events on the root hub */
+               }
+       }
+
+       /*
+        * Process the done list
+        */
+       if (donehead &= ~0x1) {
+               /*
+                * TODO See which TD's completed..
+                */
+       }
+
+       /* Re-enable done queue interrupts and reset the donehead */
+       hcca->donehead = 0;
+       writel(OHCI_INTR_WDH, &regs->intrenable);
+       
+} /* ohci_interrupt() */
+
+
+/*
+ * Allocate the resources required for running an OHCI controller.
+ * Host controller interrupts must not be running while calling this
+ * function or the penguins will get angry.
+ *
+ * The mem_base parameter must be the usable -virtual- address of the
+ * host controller's memory mapped I/O registers.
+ */
+static struct ohci *alloc_ohci(void* mem_base)
+{
+       int i;
+       struct ohci *ohci;
+       struct usb_bus *bus;
+       struct ohci_device *dev;
+       struct usb_device *usb;
+
+       ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
+       if (!ohci)
+               return NULL;
+
+       memset(ohci, 0, sizeof(*ohci));
+
+       ohci->irq = -1;
+       ohci->regs = mem_base;
+       INIT_LIST_HEAD(&ohci->interrupt_list);
+
+       bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+       if (!bus)
+               return NULL;
+
+       memset(bus, 0, sizeof(*bus));
+
+       ohci->bus = bus;
+       bus->hcpriv = ohci;
+       bus->op = &ohci_device_operations;
+
+       /*
+        * Here we allocate our own root hub and TDs as well as the
+        * OHCI host controller communications area.  The HCCA is just
+        * a nice pool of memory with pointers to endpoint descriptors
+        * for the different interrupts.
+        */
+       usb = ohci_usb_allocate(NULL);
+       if (!usb)
+               return NULL;
+
+       dev = ohci->root_hub = usb_to_ohci(usb);
+
+       usb->bus = bus;
+
+       /* Initialize the root hub */
+       memset(dev, 0, sizeof(*dev));
+       dev->ohci = ohci;    /* link back to the controller */
+
+       /*
+        * Allocate the Host Controller Communications Area
+        */
+       dev->hcca = (struct ohci_hcca *) kmalloc(sizeof(*dev->hcca), GFP_KERNEL);
+
+       /* Tell the controller where the HCCA is */
+       writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
+
+       /* Get the number of ports on the root hub */
+       usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
+       if (usb->maxchild > MAX_ROOT_PORTS) {
+               printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
+               usb->maxchild = MAX_ROOT_PORTS;
+       }
+       if (usb->maxchild < 1) {
+               printk("usb-ohci: Less than one root hub port? Impossible!\n");
+               usb->maxchild = 1;
+       }
+       printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
+
+       printk("alloc_ohci() controller\n");
+       show_ohci_status(ohci);
+       printk("alloc_ohci() root_hub device\n");
+       show_ohci_device(dev);
+
+       /*
+        * Initialize the ED polling "tree" (for simplicity's sake in
+        * this driver many nodes in the tree will be identical)
+        */
+       dev->ed[ED_INT_32].next_ed = virt_to_bus(&dev->ed[ED_INT_16]);
+       dev->ed[ED_INT_16].next_ed = virt_to_bus(&dev->ed[ED_INT_8]);
+       dev->ed[ED_INT_8].next_ed = virt_to_bus(&dev->ed[ED_INT_4]);
+       dev->ed[ED_INT_4].next_ed = virt_to_bus(&dev->ed[ED_INT_2]);
+       dev->ed[ED_INT_2].next_ed = virt_to_bus(&dev->ed[ED_INT_1]);
+
+       /*
+        * Initialize the polling table to call interrupts at the
+        * intended intervals.
+        */
+       for (i = 0; i < NUM_INTS; i++) {
+               if (i == 0)
+                       dev->hcca->int_table[i] =
+                               virt_to_bus(&dev->ed[ED_INT_32]);
+               else if (i & 1)
+                       dev->hcca->int_table[i] =
+                               virt_to_bus(&dev->ed[ED_INT_16]);
+               else if (i & 2)
+                       dev->hcca->int_table[i] =
+                               virt_to_bus(&dev->ed[ED_INT_8]);
+               else if (i & 4)
+                       dev->hcca->int_table[i] =
+                               virt_to_bus(&dev->ed[ED_INT_4]);
+               else if (i & 8)
+                       dev->hcca->int_table[i] =
+                               virt_to_bus(&dev->ed[ED_INT_2]);
+               else if (i & 16)
+                       dev->hcca->int_table[i] =
+                               virt_to_bus(&dev->ed[ED_INT_1]);
+       }
+
+       /*
+        * Tell the controller where the control and bulk lists are
+        */
+       writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
+       writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
+
+       return ohci;
+} /* alloc_ohci() */
+
+
+/*
+ * De-allocate all resoueces..
+ */
+static void release_ohci(struct ohci *ohci)
+{
+       if (ohci->irq >= 0) {
+               free_irq(ohci->irq, ohci);
+               ohci->irq = -1;
+       }
+
+       if (ohci->root_hub) {
+               /* ensure that HC is stopped before releasing the HCCA */
+               writel(OHCI_USB_SUSPEND, &ohci->regs->control);
+               free_pages((unsigned int) ohci->root_hub->hcca, 1);
+               free_pages((unsigned int) ohci->root_hub, 1);
+               ohci->root_hub->hcca = NULL;
+               ohci->root_hub = NULL;
+       }
+
+       /* unmap the IO address space */
+       iounmap(ohci->regs);
+
+       /* If the ohci itself were dynamic we'd free it here */
+
+} /* release_ohci() */
+
+/*
+ * USB OHCI control thread
+ */
+static int ohci_control_thread(void * __ohci)
+{
+       struct ohci *ohci = (struct ohci *)__ohci;
+       
+       /*
+        * I'm unfamiliar with the SMP kernel locking.. where should
+        * this be released?  -greg
+        */
+       lock_kernel();
+
+       /*
+        * This thread doesn't need any user-level access,
+        * so get rid of all of our resources..
+        */
+       printk("ohci_control_thread at %p\n", &ohci_control_thread);
+       exit_mm(current);
+       exit_files(current);
+       exit_fs(current);
+
+       strcpy(current->comm, "ohci-control");
+
+       /*
+        * Damn the torpedoes, full speed ahead
+        */
+       start_hc(ohci);
+       do {
+               interruptible_sleep_on(&ohci_configure);
+#ifdef CONFIG_APM
+               if (apm_resume) {
+                       apm_resume = 0;
+                       start_hc(ohci);
+                       continue;
+               }
+#endif
+               ohci_check_configuration(ohci);
+       } while (!signal_pending(current));
+
+       reset_hc(ohci);
+
+       release_ohci(ohci);
+       MOD_DEC_USE_COUNT;
+       return 0;
+} /* ohci_control_thread() */
+
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+       static int down = 0;
+
+       switch (event) {
+       case APM_SYS_SUSPEND:
+       case APM_USER_SUSPEND:
+               if (down) {
+                       printk(KERN_DEBUG "usb-ohci: received extra suspend event\n");
+                       break;
+               }
+               down = 1;
+               break;
+       case APM_NORMAL_RESUME:
+       case APM_CRITICAL_RESUME:
+               if (!down) {
+                       printk(KERN_DEBUG "usb-ohci: received bogus resume event\n");
+                       break;
+               }
+               down = 0;
+               if (waitqueue_active(&ohci_configure)) {
+                       apm_resume = 1;
+                       wake_up(&ohci_configure);
+               }
+               break;
+       }
+       return 0;
+}
+#endif
+
+/* ... */
+
+/*
+ * Increment the module usage count, start the control thread and
+ * return success if the controller is good.
+ */
+static int found_ohci(int irq, void* mem_base)
+{
+       int retval;
+       struct ohci *ohci;
+
+       /* Allocate the running OHCI structures */
+       ohci = alloc_ohci(mem_base);
+       if (!ohci)
+               return -ENOMEM;
+
+       printk("usb-ohci: alloc_ohci() = %p\n", ohci);
+
+       reset_hc(ohci);
+
+       retval = -EBUSY;
+       if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
+               int pid;
+
+               MOD_INC_USE_COUNT;
+               ohci->irq = irq;
+
+               /* fork off the handler */
+               pid = kernel_thread(ohci_control_thread, ohci,
+                               CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+               if (pid >= 0)
+                       return 0;
+
+               MOD_DEC_USE_COUNT;
+               retval = pid;
+       }
+       release_ohci(ohci);
+       return retval;
+} /* found_ohci() */
+
+
+/*
+ * If this controller is for real, map the IO memory and proceed
+ */
+static int init_ohci(struct pci_dev *dev)
+{
+       unsigned int mem_base = dev->base_address[0];
+       
+       printk("usb-ohci: mem_base is %p\n", (void*)mem_base);
+
+       /* If its OHCI, its memory */
+       if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
+               return -ENODEV;
+
+       /* Get the memory address and map it for IO */
+       mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+       /* 
+        * FIXME ioremap_nocache isn't implemented on all CPUs (such
+        * as the Alpha) [?]  What should I use instead...
+        *
+        * The iounmap() is done on in release_ohci.
+        */
+       mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+
+       if (!mem_base) {
+               printk("Error mapping OHCI memory\n");
+               return -EFAULT;
+       }
+
+       return found_ohci(dev->irq, (void *) mem_base);
+} /* init_ohci() */
+
+
+#ifdef MODULE
+
+/*
+ *  Clean up when unloading the module
+ */
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+       apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define ohci_init init_module
+
+#endif
+
+
+/* TODO this should be named following Linux convention and go in pci.h */
+#define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010)
+
+/*
+ * Search the PCI bus for an OHCI USB controller and set it up
+ *
+ * If anyone wants multiple controllers this will need to be
+ * updated..  Right now, it just picks the first one it finds.
+ */
+int ohci_init(void)
+{
+       int retval;
+       struct pci_dev *dev = NULL;
+       /*u8 type;*/
+
+       if (sizeof(struct ohci_device) > 4096) {
+               printk("usb-ohci: struct ohci_device to large\n");
+               return -ENODEV;
+       }
+
+       retval = -ENODEV;
+       for (;;) {
+               /* Find an OHCI USB controller */
+               dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev);
+               if (!dev)
+                       break;
+
+               /* Verify that its OpenHCI by checking for MMIO */
+               /* pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
+               if (!type)
+                       continue; */
+
+               /* Ok, set it up */
+               retval = init_ohci(dev);
+               if (retval < 0)
+                       continue;
+
+               /* TODO check module params here to determine what to load */
+
+/*             usb_mouse_init(); */
+/*             usb_kbd_init();
+               hub_init();     */
+#ifdef CONFIG_APM
+               apm_register_callback(&handle_apm_event);
+#endif
+
+               return 0; /* no error */
+       }
+       return retval;
+} /* init_module() */
+
+/* vim:sw=8
+ */
diff --git a/drivers/usb/ohci.h b/drivers/usb/ohci.h
new file mode 100644 (file)
index 0000000..6c94bbc
--- /dev/null
@@ -0,0 +1,301 @@
+#ifndef __LINUX_OHCI_H
+#define __LINUX_OHCI_H
+
+/*
+ * Open Host Controller Interface data structures and defines.
+ *
+ * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
+ *
+ * $Id: ohci.h,v 1.6 1999/04/24 22:50:06 greg Exp $
+ */
+
+#include <linux/list.h>
+#include <asm/io.h>
+
+#include "usb.h"
+
+/*
+ * Each TD must be aligned on a 16-byte boundary.  From the OHCI v1.0 spec
+ * it does not state that TDs must be contiguious in memory (due to the
+ * use of the next_td field).  This gives us extra room at the end of a
+ * TD for our own driver specific data.
+ *
+ * This structure's size must be a multiple of 16 bytes.
+ */
+struct ohci_td {
+       /* OHCI Hardware fields */
+       __u32 info;
+       __u32 cur_buf;          /* Current Buffer Pointer */
+       __u32 next_td;          /* Next TD Pointer */
+       __u32 buf_end;          /* Memory Buffer End Pointer */
+
+       /* Driver specific fields */
+       struct list_head irq_list;      /* Active interrupt list */
+       usb_device_irq completed;       /* Completion handler routine */
+       void *data;     /* XXX ? */
+       void *dev_id;   /* XXX ? */
+       __u32 ed_bus;                   /* bus address of original ED */
+} __attribute((aligned(32)));
+
+#define OHCI_TD_ROUND  (1 << 18)       /* buffer rounding bit */
+#define OHCI_TD_D      (3 << 11)       /* direction of xfer: */
+#define OHCI_TD_D_IN   (2 << 11)
+#define OHCI_TD_D_OUT  (1 << 11)
+#define OHCI_TD_D_SETUP (0)
+#define td_set_dir_in(d)       ((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT )
+#define td_set_dir_out(d)      ((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
+#define OHCI_TD_IOC_DELAY (7 << 21)    /* frame delay allowed before int. */
+#define OHCI_TD_IOC_OFF        (OHCI_TD_IOC_DELAY)     /* no interrupt on complete */
+#define OHCI_TD_DT     (3 << 24)       /* data toggle bits */
+#define td_force_toggle(b)     (((b) | 2) << 24)
+#define OHCI_TD_ERRCNT (3 << 26)       /* error count */
+#define td_errorcount(td)      (((td) >> 26) & 3)
+#define OHCI_TD_CC     (0xf << 28)     /* condition code */
+#define OHCI_TD_CC_NEW (OHCI_TD_CC)    /* set this on all unaccessed TDs! */
+#define td_cc_notaccessed(td)  ((td >> 29) == 7)
+#define td_cc_accessed(td)     ((td >> 29) != 7)
+#define td_cc_noerror(td)      (((td) & OHCI_TD_CC) == 0)
+#define td_active(td)  (!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
+#define td_done(td)    (td_cc_noerror((td)) || (td_errorcount((td)) == 3))
+
+/*
+ * The endpoint descriptors also requires 16-byte alignment
+ */
+struct ohci_ed {
+       /* OHCI hardware fields */
+       __u32 status;
+       __u32 tail_td;  /* TD Queue tail pointer */
+       __u32 head_td;  /* TD Queue head pointer */
+       __u32 next_ed;  /* Next ED */
+} __attribute((aligned(16)));
+
+#define OHCI_ED_SKIP   (1 << 14)
+#define OHCI_ED_MPS    (0x7ff << 16)
+/* FIXME: should cap at the USB max packet size [0x4ff] */
+#define ed_set_maxpacket(s)    (((s) << 16) & OHCI_ED_MPS)
+#define OHCI_ED_F_NORM (0)
+#define OHCI_ED_F_ISOC (1 << 15)
+#define ed_set_type_isoc(i)    ((i) ? OHCI_ED_F_ISOC : OHCI_ED_F_NORM)
+#define OHCI_ED_S_LOW  (1 << 13)
+#define OHCI_ED_S_HIGH (0)
+#define ed_set_speed(s)                ((s) ? OHCI_ED_S_LOW : OHCI_ED_S_HIGH)
+#define OHCI_ED_D      (3 << 11)
+#define OHCI_ED_D_IN   (2 << 11)
+#define OHCI_ED_D_OUT  (1 << 11)
+#define ed_set_dir_in(d)       ((d) ? OHCI_ED_D_IN : OHCI_ED_D_OUT)
+#define ed_set_dir_out(d)      ((d) ? OHCI_ED_D_OUT : OHCI_ED_D_IN)
+#define OHCI_ED_EN     (0xf << 7)
+#define OHCI_ED_FA     (0x7f)
+
+
+/* NOTE: bits 27-31 of the status dword are reserved for the driver */
+/*
+ * We'll use this status flag for the non-predefined EDs to mark if
+ * they're in use or not.
+ *
+ * FIXME: unimplemented (needed?)
+ */
+#define ED_USED        (1 << 31)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32    /* part of the OHCI standard */
+struct ohci_hcca {
+       __u32   int_table[NUM_INTS];    /* Interrupt ED table */
+       __u16   frame_no;               /* current frame number */
+       __u16   pad1;                   /* set to 0 on each frame_no change */
+       __u32   donehead;               /* info returned for an interrupt */
+       u8      reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+/*
+ * The TD entries here are pre-allocated as Linus did with his simple
+ * UHCI implementation.  With the current state of this driver that
+ * shouldn't be a problem.  However if someone ever connects 127
+ * supported devices to this driver and tries to use them all at once:
+ *     a)  They're insane!
+ *     b)  They should code in dynamic allocation
+ */
+struct ohci;
+
+/*
+ *  Warning: These constants must not be so large as to cause the
+ *  ohci_device structure to exceed one 4096 byte page.  Or "weird
+ *  things will happen" as the alloc_ohci() function assumes that
+ *  its less than one page.  (FIXME)
+ */
+#define NUM_TDS        32              /* num of preallocated transfer descriptors */
+#define DATA_BUF_LEN 16                /* num of unsigned long's for the data buf */
+
+/*
+ * For this "simple" driver we only support a single ED for each
+ * polling rate.
+ *
+ * Later on this driver should be extended to use a full tree of EDs
+ * so that there can be 32 different 32ms polling frames, etc.
+ * Individual devices shouldn't need as many as the root hub in that
+ * case; complicating how things are done at the moment.
+ *
+ * Bulk and Control transfers hang off of their own ED lists.
+ */
+#define NUM_EDS 16             /* num of preallocated endpoint descriptors */
+
+#define ohci_to_usb(ohci)      ((ohci)->usb)
+#define usb_to_ohci(usb)       ((struct ohci_device *)(usb)->hcpriv)
+
+/* The usb_device must be first! */
+struct ohci_device {
+       struct usb_device       *usb;
+
+       struct ohci             *ohci;
+       struct ohci_hcca        *hcca;          /* OHCI mem. mapped IO area */
+
+       struct ohci_ed          ed[NUM_EDS];    /* Endpoint Descriptors */
+       struct ohci_td          td[NUM_TDS];    /* Transfer Descriptors */
+
+       unsigned long           data[DATA_BUF_LEN];
+};
+
+/* .... */
+
+#define ED_INT_1       0
+#define ED_INT_2       1
+#define ED_INT_4       2
+#define ED_INT_8       3
+#define ED_INT_16      4
+#define ED_INT_32      5
+#define ED_CONTROL     6
+#define ED_BULK                7
+#define ED_ISO         ED_INT_1        /* same as 1ms interrupt queue */
+#define ED_FIRST_AVAIL  8              /* first non-reserved ED */
+
+/*
+ * Given a period p in ms, convert it to the closest endpoint
+ * interrupt frequency; rounding down.  I'm sure many feel that this
+ * is a gross macro.  Feel free to toss it for actual code.
+ */
+#define ms_to_ed_int(p) \
+       ((p >= 32) ? ED_INT_32 : \
+        ((p & 16) ? ED_INT_16 : \
+         ((p & 8) ? ED_INT_8 : \
+          ((p & 4) ? ED_INT_4 : \
+           ((p & 2) ? ED_INT_2 : \
+            ED_INT_1)))))  /* hmm.. scheme or lisp anyone? */
+
+/*
+ * This is the maximum number of root hub ports.  I don't think we'll
+ * ever see more than two as that's the space available on an ATX
+ * motherboard's case, but it could happen.  The OHCI spec allows for
+ * up to 15... (which is insane!)
+ * 
+ * Although I suppose several "ports" could be connected directly to
+ * internal laptop devices such as a keyboard, mouse, camera and
+ * serial/parallel ports.  hmm...  That'd be neat.
+ */
+#define MAX_ROOT_PORTS 15      /* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+       /* control and status registers */
+       __u32   revision;
+       __u32   control;
+       __u32   cmdstatus;
+       __u32   intrstatus;
+       __u32   intrenable;
+       __u32   intrdisable;
+       /* memory pointers */
+       __u32   hcca;
+       __u32   ed_periodcurrent;
+       __u32   ed_controlhead;
+       __u32   ed_controlcurrent;
+       __u32   ed_bulkhead;
+       __u32   ed_bulkcurrent;
+       __u32   current_donehead; /* The driver should get this from the HCCA */
+       /* frame counters */
+       __u32   fminterval;
+       __u32   fmremaining;
+       __u32   fmnumber;
+       __u32   periodicstart;
+       __u32   lsthresh;
+       /* Root hub ports */
+       struct  ohci_roothub_regs {
+               __u32   a;
+               __u32   b;
+               __u32   status;
+               __u32   portstatus[MAX_ROOT_PORTS];
+       } roothub;
+} __attribute((aligned(32)));
+
+/* 
+ * Read a MMIO register and re-write it after ANDing with (m)
+ */
+#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
+
+/*
+ * Read a MMIO register and re-write it after ORing with (b)
+ */
+#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
+
+
+#define PORT_CCS       (1)             /* port current connect status */
+#define PORT_PES       (1 << 1)        /* port enable status */
+#define PORT_PSS       (1 << 2)        /* port suspend status */
+#define PORT_POCI      (1 << 3)        /* port overcurrent indicator */
+#define PORT_PRS       (1 << 4)        /* port reset status */
+#define PORT_PPS       (1 << 8)        /* port power status */
+#define PORT_LSDA      (1 << 9)        /* port low speed dev. attached */
+#define PORT_CSC       (1 << 16)       /* port connect status change */
+#define PORT_PESC      (1 << 17)       /* port enable status change */
+#define PORT_PSSC      (1 << 18)       /* port suspend status change */
+#define PORT_OCIC      (1 << 19)       /* port over current indicator chg */
+#define PORT_PRSC      (1 << 20)       /* port reset status change */
+
+
+/*
+ * Interrupt register masks
+ */
+#define OHCI_INTR_SO   (1)
+#define OHCI_INTR_WDH  (1 << 1)
+#define OHCI_INTR_SF   (1 << 2)
+#define OHCI_INTR_RD   (1 << 3)
+#define OHCI_INTR_UE   (1 << 4)
+#define OHCI_INTR_FNO  (1 << 5)
+#define OHCI_INTR_RHSC (1 << 6)
+#define OHCI_INTR_OC   (1 << 30)
+#define OHCI_INTR_MIE  (1 << 31)
+
+/*
+ * Control register masks
+ */
+#define OHCI_USB_OPER          (2 << 6)
+#define OHCI_USB_SUSPEND       (3 << 6)
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+struct ohci {
+       int irq;
+       struct ohci_regs *regs;                 /* OHCI controller's memory */
+       struct usb_bus *bus;
+       struct ohci_device *root_hub;           /* Root hub & controller */
+       struct list_head interrupt_list;        /* List of interrupt active TDs for this OHCI */
+};
+
+/* Debugging code */
+void show_ed(struct ohci_ed *ed);
+void show_td(struct ohci_td *td);
+void show_status(struct ohci *ohci);
+
+#endif
+/* vim:sw=8
+ */
diff --git a/drivers/usb/restart b/drivers/usb/restart
new file mode 100644 (file)
index 0000000..e90e846
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+ME=`basename $0`
+
+#UMOD=`lsmod | grep '^bp-mouse' | grep -v grep`
+#if test "$UMOD"; then
+#  echo "$ME: removing bp-mouse.o"
+#  if ! rmmod bp-mouse; then
+#    echo "$ME: cannot remove bp-mouse.o"
+#    exit 1
+#  fi
+#fi
+
+UPID=`ps aux | grep uhci-control | grep -v grep | awk '{print $2}'`
+if test "$UPID"; then
+  echo "$ME: killing $UPID"
+  kill $UPID
+fi
+
+UMOD=`lsmod | grep '^usb-uhci' | grep -v grep`
+if test "$UMOD"; then
+  echo "$ME: removing usb-uhci.o"
+  sleep 1
+  if ! rmmod usb-uhci; then
+    echo "$ME: cannot remove usb-uhci.o"
+    exit 1
+  fi
+fi
+
+dmesg -c > /dev/null
+
+echo "$ME: starting usb-uhci.o"
+insmod -m usb-uhci.o > usb-uhci.map
+#echo "$ME: starting bp-mouse.o"
+#insmod -m bp-mouse.o > bp-mouse.map
diff --git a/drivers/usb/stopusb b/drivers/usb/stopusb
new file mode 100644 (file)
index 0000000..ffd4230
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+killall uhci-control
+killall khubd
+
+sleep 1
+
+rmmod usb-uhci
diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c
new file mode 100644 (file)
index 0000000..fd2aba6
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+void show_td(struct uhci_td * td)
+{
+       printk("%08x ", td->link);
+       printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+               ((td->status >> 29) & 1) ? "SPD " : "",
+               ((td->status >> 27) & 3),
+               ((td->status >> 26) & 1) ? "LS " : "",
+               ((td->status >> 25) & 1) ? "IOS " : "",
+               ((td->status >> 24) & 1) ? "IOC " : "",
+               ((td->status >> 23) & 1) ? "Active " : "",
+               ((td->status >> 22) & 1) ? "Stalled " : "",
+               ((td->status >> 21) & 1) ? "DataBufErr " : "",
+               ((td->status >> 20) & 1) ? "Babble " : "",
+               ((td->status >> 19) & 1) ? "NAK " : "",
+               ((td->status >> 18) & 1) ? "CRC/Timeo " : "",
+               ((td->status >> 17) & 1) ? "BitStuff " : "",
+               td->status & 0x7ff);
+       printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ",
+               td->info >> 21,
+                ((td->info >> 19) & 1) ? "DT " : "",
+                (td->info >> 15) & 15,
+                (td->info >> 8) & 127,
+                td->info & 0xff);
+       printk("(buf=%08x)\n", td->buffer);
+}
+
+static void show_sc(int port, unsigned short status)
+{
+       printk("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+               port,
+               status,
+               (status & (1 << 12)) ? " PortSuspend" : "",
+               (status & (1 << 9)) ? " PortReset" : "",
+               (status & (1 << 8)) ? " LowSpeed" : "",
+               (status & 0x40) ? " ResumeDetect" : "",
+               (status & 0x08) ? " EnableChange" : "",
+               (status & 0x04) ? " PortEnabled" : "",
+               (status & 0x02) ? " ConnectChange" : "",
+               (status & 0x01) ? " PortConnected" : "");
+}
+
+void show_status(struct uhci *uhci)
+{
+       unsigned int io_addr = uhci->io_addr;
+       unsigned short usbcmd, usbstat, usbint, usbfrnum;
+       unsigned int flbaseadd;
+       unsigned char sof;
+       unsigned short portsc1, portsc2;
+
+       usbcmd    = inw(io_addr + 0);
+       usbstat   = inw(io_addr + 2);
+       usbint    = inw(io_addr + 4);
+       usbfrnum  = inw(io_addr + 6);
+       flbaseadd = inl(io_addr + 8);
+       sof       = inb(io_addr + 12);
+       portsc1   = inw(io_addr + 16);
+       portsc2   = inw(io_addr + 18);
+
+       printk("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+               usbcmd,
+               (usbcmd & 0x80) ? " Maxp64" : " Maxp32",
+               (usbcmd & 0x40) ? " CF" : "",
+               (usbcmd & 0x20) ? " SWDBG" : "",
+               (usbcmd & 0x10) ? " FGR" : "",
+               (usbcmd & 0x08) ? " EGSM" : "",
+               (usbcmd & 0x04) ? " GRESET" : "",
+               (usbcmd & 0x02) ? " HCRESET" : "",
+               (usbcmd & 0x01) ? " RS" : "");
+
+       printk("  usbstat   =     %04x   %s%s%s%s%s%s\n",
+               usbstat,
+               (usbstat & 0x20) ? " HCHalted" : "",
+               (usbstat & 0x10) ? " HostControllerProcessError" : "",
+               (usbstat & 0x08) ? " HostSystemError" : "",
+               (usbstat & 0x04) ? " ResumeDetect" : "",
+               (usbstat & 0x02) ? " USBError" : "",
+               (usbstat & 0x01) ? " USBINT" : "");
+
+       printk("  usbint    =     %04x\n", usbint);
+       printk("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum));
+       printk("  flbaseadd = %08x\n", flbaseadd);
+       printk("  sof       =       %02x\n", sof);
+       show_sc(1, portsc1);
+       show_sc(2, portsc2);
+}
+
+#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
+
+struct uhci_td * uhci_link_to_td(unsigned int link)
+{
+       if (link & 1)
+               return NULL;
+
+       return bus_to_virt(link & ~15);
+}
+
+void show_queue(struct uhci_qh *qh)
+{
+       struct uhci_td *td;
+       int i = 0;
+
+#if 0
+       printk("    link = %p, element = %p\n", qh->link, qh->element);
+#endif
+       if(!qh->element) {
+               printk("    td 0 = NULL\n");
+               return;
+       }
+
+       for(td = uhci_link_to_td(qh->element); td; 
+           td = uhci_link_to_td(td->link)) {
+               printk("    td %d = %p\n", i++, td);
+               printk("    ");
+               show_td(td);
+       }
+}
+
+int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+       int j;
+
+       for (j = 0; j < UHCI_MAXQH; j++)
+               if (qh == uhci->root_hub->qh + j)
+                       return 1;
+
+       return 0;
+}
+
+static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4",
+                                "interrupt8", "interrupt16", "interrupt32",
+                                "interrupt64", "interrupt128", "interrupt256",
+                                "control", "bulk0", "bulk1", "bulk2", "bulk3",
+                                "unused", "unused"};
+
+void show_queues(struct uhci *uhci)
+{
+       int i;
+       struct uhci_qh *qh;
+
+       for (i = 0; i < UHCI_MAXQH; ++i) {
+               printk("  %s:\n", qh_names[i]);
+#if 0
+               printk("  qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i));
+               show_queue(uhci->root_hub->qh + i);
+#endif
+
+               qh = uhci_link_to_qh(uhci->root_hub->qh[i].link);
+               for (; qh; qh = uhci_link_to_qh(qh->link)) {
+                       if (is_skeleton_qh(uhci, qh))
+                               break;
+
+                       show_queue(qh);
+               }
+       }
+}
+
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
new file mode 100644 (file)
index 0000000..244cdd9
--- /dev/null
@@ -0,0 +1,1195 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * Oh, well. The intel version is the more common by far. As such,
+ * that's the one I care about right now.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/* 4/4/1999 added data toggle for interrupt pipes -keryan */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "uhci.h"
+#include "inits.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+#define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0)
+
+int usb_mouse_init(void);
+int hub_init(void);
+
+static struct wait_queue *uhci_configure = NULL;
+
+/*
+ * Return the result of a TD..
+ */
+static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td)
+{
+       unsigned int status;
+
+       status = (td->status >> 16) & 0xff;
+
+       /* Some debugging code */
+       if (status) {
+               int i = 10;
+               struct uhci_td *tmp = dev->control_td;
+               printk("uhci_td_result() failed with status %d\n", status);
+               show_status(dev->uhci);
+               do {
+                       show_td(tmp);
+                       tmp++;
+                       if (!--i)
+                               break;
+               } while (tmp <= td);
+       }
+       return status;          
+}
+
+/*
+ * Inserts a td into qh list at the top.
+ *
+ * Careful about atomicity: even on UP this
+ * requires a locked access due to the concurrent
+ * DMA engine.
+ *
+ * NOTE! This assumes that first->last is a valid
+ * list of TD's with the proper backpointers set
+ * up and all..
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last)
+{
+       unsigned int link = qh->element;
+       unsigned int new = 4 | virt_to_bus(first);
+
+       for (;;) {
+               unsigned char success;
+
+               last->link = link;
+               first->backptr = &qh->element;
+               asm volatile("lock ; cmpxchg %4,%2 ; sete %0"
+                       :"=q" (success), "=a" (link)
+                       :"m" (qh->element), "1" (link), "r" (new)
+                       :"memory");
+               if (success) {
+                       /* Was there a successor entry? Fix it's backpointer.. */
+                       if ((link & 1) == 0) {
+                               struct uhci_td *next = bus_to_virt(link & ~15);
+                               next->backptr = &last->link;
+                       }
+                       break;
+               }
+       }
+}
+
+static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td)
+{
+       uhci_insert_tds_in_qh(qh, td, td);
+}
+
+static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh)
+{
+       newqh->link = qh->link;
+       qh->link = virt_to_bus(newqh) | 2;
+}
+
+static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh)
+{
+       unsigned int remphys = virt_to_bus(remqh);
+       struct uhci_qh *lqh = qh;
+
+       while ((lqh->link & ~0xF) != remphys) {
+               if (lqh->link & 1)
+                       break;
+
+               lqh = bus_to_virt(lqh->link & ~0xF);
+       }
+
+       if (lqh->link & 1) {
+               printk("couldn't find qh in chain!\n");
+               return;
+       }
+
+       lqh->link = remqh->link;
+}
+
+/*
+ * Removes td from qh if present.
+ *
+ * NOTE! We keep track of both forward and back-pointers,
+ * so this should be trivial, right?
+ *
+ * Wrong. While all TD insert/remove operations are synchronous
+ * on the CPU, the UHCI controller can (and does) play with the
+ * very first forward pointer. So we need to validate the backptr
+ * before we change it, so that we don't by mistake reset the QH
+ * head to something old.
+ */
+static void uhci_remove_td(struct uhci_td *td)
+{
+       unsigned int *backptr = td->backptr;
+       unsigned int link = td->link;
+       unsigned int me;
+
+       if (!backptr)
+               return;
+
+       td->backptr = NULL;
+
+       /*
+        * This is the easy case: the UHCI will never change "td->link",
+        * so we can always just look at that and fix up the backpointer
+        * of any next element..
+        */
+       if (!(link & 1)) {
+               struct uhci_td *next = bus_to_virt(link & ~15);
+               next->backptr = backptr;
+       }
+
+       /*
+        * The nasty case is "backptr->next", which we need to
+        * update to "link" _only_ if "backptr" still points
+        * to us (it may not: maybe backptr is a QH->element
+        * pointer and the UHCI has changed the value).
+        */
+       me = virt_to_bus(td) | (0xe & *backptr);
+       asm volatile("lock ; cmpxchg %0,%1"
+               :
+               :"r" (link), "m" (*backptr), "a" (me)
+               :"memory");
+}
+
+static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev)
+{
+       struct uhci_qh *qh;
+       int inuse;
+
+       qh = dev->qh;
+       for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++)
+               ;
+
+       if (!inuse)
+               return(qh);
+
+       printk("ran out of qh's for dev %p\n", dev);
+       return(NULL);
+}
+
+static void uhci_qh_deallocate(struct uhci_qh *qh)
+{
+       if (qh->element != 1)
+               printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
+
+       qh->element = 1;
+       qh->link = 1;
+
+       clear_bit(0, &qh->inuse);
+}
+
+static struct uhci_td *uhci_td_allocate(struct uhci_device *dev)
+{
+       struct uhci_td *td;
+       int inuse;
+
+       td = dev->td;
+       for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++)
+               ;
+
+       if (!inuse)
+               return(td);
+
+       printk("ran out of td's for dev %p\n", dev);
+       return(NULL);
+}
+
+/*
+ * This MUST only be called when it has been removed from a QH already (or
+ * the QH has been removed from the skeleton
+ */
+static void uhci_td_deallocate(struct uhci_td *td)
+{
+       td->link = 1;
+
+       clear_bit(0, &td->inuse);
+}
+
+/*
+ * UHCI interrupt list operations..
+ */
+static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
+
+static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td, usb_device_irq completed, void *dev_id)
+{
+       unsigned long flags;
+
+       td->completed = completed;
+       td->dev_id = dev_id;
+
+       spin_lock_irqsave(&irqlist_lock, flags);
+       list_add(&td->irq_list, &uhci->interrupt_list);
+       spin_unlock_irqrestore(&irqlist_lock, flags);
+}
+
+static void uhci_remove_irq_list(struct uhci_td *td)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&irqlist_lock, flags);
+       list_del(&td->irq_list);
+       spin_unlock_irqrestore(&irqlist_lock, flags);
+}
+
+/*
+ * Request a interrupt handler..
+ */
+static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+       struct uhci_device *dev = usb_to_uhci(usb_dev);
+       struct uhci_td *td = uhci_td_allocate(dev);
+       struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev);
+
+       unsigned int destination, status;
+
+       /* Destination: pipe destination with INPUT */
+       destination = (pipe & 0x0007ff00)  |  0x69;
+
+       /* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
+       status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
+
+       if(interrupt_qh->element != 1)
+               printk("interrupt_qh->element = 0x%x\n", 
+                      interrupt_qh->element);
+
+       td->link = 1;
+       td->status = status;                    /* In */
+       td->info = destination | (7 << 21);     /* 8 bytes of data */
+       td->buffer = virt_to_bus(dev->data);
+       td->qh = interrupt_qh;
+       interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh;
+
+       uhci_add_irq_list(dev->uhci, td, handler, dev_id);
+
+       uhci_insert_td_in_qh(interrupt_qh, td);
+
+       /* Add it into the skeleton */
+       uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh);
+       return 0;
+}
+
+/*
+ * Control thread operations: we just mark the last TD
+ * in a control thread as an interrupt TD, and wake up
+ * the front-end on completion.
+ *
+ * We need to remove the TD from the lists (both interrupt
+ * list and TD lists) by hand if something bad happens!
+ */
+static struct wait_queue *control_wakeup;
+
+static int uhci_control_completed(int status, void *buffer, void *dev_id)
+{
+       wake_up(&control_wakeup);
+       return 0;                       /* Don't re-instate */
+}
+
+/* td points to the last td in the list, which interrupts on completion */
+static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+{
+       struct wait_queue wait = { current, NULL };
+       struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev);
+       struct uhci_td *curtd;
+
+       current->state = TASK_UNINTERRUPTIBLE;
+       add_wait_queue(&control_wakeup, &wait);
+
+       uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL);
+       
+       /* FIXME: This is kinda kludged */
+       /* Walk the TD list and update the QH pointer */
+       {
+       int maxcount = 100;
+
+       curtd = first;
+       do {
+               curtd->qh = ctrl_qh;
+               if (curtd->link & 1)
+                       break;
+
+               curtd = bus_to_virt(curtd->link & ~0xF);
+               if (!--maxcount) {
+                       printk("runaway tds!\n");
+                       break;
+               }
+       } while (1);
+       }
+
+       uhci_insert_tds_in_qh(ctrl_qh, first, last);
+
+       /* Add it into the skeleton */
+       uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+
+       schedule_timeout(HZ/10);
+
+       remove_wait_queue(&control_wakeup, &wait);
+
+       /* Clean up in case it failed.. */
+       uhci_remove_irq_list(last);
+
+#if 0
+       printk("Looking for tds [%p, %p]\n", dev->control_td, td);
+#endif
+
+       /* Remove it from the skeleton */
+       uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+
+       uhci_qh_deallocate(ctrl_qh);
+
+       return uhci_td_result(dev, last);
+}
+
+/*
+ * Send or receive a control message on a pipe.
+ *
+ * Note that the "pipe" structure is set up to map
+ * easily to the uhci destination fields.
+ *
+ * A control message is built up from three parts:
+ *  - The command itself
+ *  - [ optional ] data phase
+ *  - Status complete phase
+ *
+ * The data phase can be an arbitrary number of TD's
+ * although we currently had better not have more than
+ * 29 TD's here (we have 31 TD's allocated for control
+ * operations, and two of them are used for command and
+ * status).
+ *
+ * 29 TD's is a minimum of 232 bytes worth of control
+ * information, that's just ridiculously high. Most
+ * control messages have just a few bytes of data.
+ */
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+{
+       struct uhci_device *dev = usb_to_uhci(usb_dev);
+       struct uhci_td *first, *td, *prevtd;
+       unsigned long destination, status;
+       int ret;
+
+       if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29)
+               printk("Warning, too much data for a control packet, crashing\n");
+
+       first = td = uhci_td_allocate(dev);
+
+       /* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
+       destination = (pipe & 0x0007ff00) | 0x2D;
+
+       /* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
+       status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
+
+       /*
+        * Build the TD for the control request
+        */
+       td->status = status;                            /* Try forever */
+       td->info = destination | (7 << 21);             /* 8 bytes of data */
+       td->buffer = virt_to_bus(cmd);
+
+       /*
+        * If direction is "send", change the frame from SETUP (0x2D)
+        * to OUT (0xE1). Else change it from SETUP to IN (0x69)
+        */
+       destination ^= (0x2D ^ 0x69);                   /* SETUP -> IN */
+       if (usb_pipeout(pipe))
+               destination ^= (0xE1 ^ 0x69);           /* IN -> OUT */
+
+       prevtd = td;
+       td = uhci_td_allocate(dev);
+       prevtd->link = 4 | virt_to_bus(td);
+
+       /*
+        * Build the DATA TD's
+        */
+       while (len > 0) {
+               /* Build the TD for control status */
+               int pktsze = len;
+               int maxsze = usb_maxpacket(pipe);
+
+               if (pktsze > maxsze)
+                       pktsze = maxsze;
+
+               /* Alternate Data0/1 (start with Data1) */
+               destination ^= 1 << 19;
+       
+               td->status = status;                                    /* Status */
+               td->info = destination | ((pktsze-1) << 21);            /* pktsze bytes of data */
+               td->buffer = virt_to_bus(data);
+               td->backptr = &prevtd->link;
+
+               prevtd = td;
+               td = uhci_td_allocate(dev);
+               prevtd->link = 4 | virt_to_bus(td);                     /* Update previous TD */
+
+               data += maxsze;
+               len -= maxsze;
+       }
+
+       /*
+        * Build the final TD for control status
+        */
+       destination ^= (0xE1 ^ 0x69);                   /* OUT -> IN */
+       destination |= 1 << 19;                         /* End in Data1 */
+
+       td->link = 1;                                   /* Terminate */
+       td->status = status | (1 << 24);                /* IOC */
+       td->info = destination | (0x7ff << 21);         /* 0 bytes of data */
+       td->buffer = 0;
+       td->backptr = &prevtd->link;
+
+       /* Start it up.. */
+       ret = uhci_run_control(dev, first, td);
+
+       {
+               int maxcount = 100;
+               struct uhci_td *curtd = first;
+               unsigned int nextlink;
+
+               do {
+                       nextlink = curtd->link;
+                       uhci_remove_td(curtd);
+                       uhci_td_deallocate(curtd);
+                       if (nextlink & 1)       /* Tail? */
+                               break;
+
+                       curtd = bus_to_virt(nextlink & ~0xF);
+                       if (!--maxcount) {
+                               printk("runaway td's!?\n");
+                               break;
+                       }
+               } while (1);
+       }
+
+       return ret;
+}
+
+static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
+{
+       struct usb_device *usb_dev;
+       struct uhci_device *dev;
+       int i;
+
+       usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
+       if (!usb_dev)
+               return NULL;
+
+       memset(usb_dev, 0, sizeof(*usb_dev));
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               kfree(usb_dev);
+               return NULL;
+       }
+
+       /* Initialize "dev" */
+       memset(dev, 0, sizeof(*dev));
+
+       usb_dev->hcpriv = dev;
+       dev->usb = usb_dev;
+
+       usb_dev->parent = parent;
+
+       if (parent) {
+               usb_dev->bus = parent->bus;
+               dev->uhci = usb_to_uhci(parent)->uhci;
+       }
+
+       /* Reset the QH's and TD's */
+       for (i = 0; i < UHCI_MAXQH; i++) {
+               dev->qh[i].link = 1;
+               dev->qh[i].element = 1;
+               dev->qh[i].inuse = 0;
+       }
+
+       for (i = 0; i < UHCI_MAXTD; i++) {
+               dev->td[i].link = 1;
+               dev->td[i].inuse = 0;
+       }
+
+       return usb_dev;
+}
+
+static int uhci_usb_deallocate(struct usb_device *usb_dev)
+{
+       struct uhci_device *dev = usb_to_uhci(usb_dev);
+       int i;
+
+       /* There are UHCI_MAXTD preallocated tds */
+       for (i = 0; i < UHCI_MAXTD; ++i) {
+               struct uhci_td *td = dev->td + i;
+
+               /* And remove it from the irq list, if it's active */
+               if (td->status & (1 << 23))
+                       uhci_remove_irq_list(td);
+
+               if (td->inuse)
+                       uhci_remove_td(td);
+       }
+
+       /* Remove the td from any queues */
+       for (i = 0; i < UHCI_MAXQH; ++i) {
+               struct uhci_qh *qh = dev->qh + i;
+
+               if (qh->inuse)
+                       uhci_remove_qh(qh->skel, qh);
+       }
+
+       kfree(dev);
+       kfree(usb_dev);
+
+       return 0;
+}
+
+struct usb_operations uhci_device_operations = {
+       uhci_usb_allocate,
+       uhci_usb_deallocate,
+       uhci_control_msg,
+       uhci_request_irq,
+};
+
+/*
+ * This is just incredibly fragile. The timings must be just
+ * right, and they aren't really documented very well.
+ *
+ * Note the short delay between disabling reset and enabling
+ * the port..
+ */
+static void uhci_reset_port(unsigned int port)
+{
+       unsigned short status;
+
+       status = inw(port);
+       outw(status | USBPORTSC_PR, port);              /* reset port */
+       wait_ms(10);
+       outw(status & ~USBPORTSC_PR, port);
+       udelay(5);
+
+       status = inw(port);
+       outw(status | USBPORTSC_PE, port);              /* enable port */
+       wait_ms(10);
+
+       status = inw(port);
+       if(!(status & USBPORTSC_PE)) {
+               outw(status | USBPORTSC_PE, port);      /* one more try at enabling port */
+               wait_ms(50);
+       }
+
+}
+
+
+/*
+ * This gets called if the connect status on the root
+ * hub (and the root hub only) changes.
+ */
+static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned int nr)
+{
+       struct usb_device *usb_dev;
+       struct uhci_device *dev;
+       unsigned short status;
+
+       printk("uhci_connect_change: called for %d\n", nr);
+
+       /*
+        * Even if the status says we're connected,
+        * the fact that the status bits changed may
+        * that we got disconnected and then reconnected.
+        *
+        * So start off by getting rid of any old devices..
+        */
+       usb_disconnect(&uhci->root_hub->usb->children[nr]);
+
+       status = inw(port);
+
+       /* If we have nothing connected, then clear change status and disable the port */
+       status = (status & ~USBPORTSC_PE) | USBPORTSC_PEC;
+       if (!(status & USBPORTSC_CCS)) {
+               outw(status, port);
+               return;
+       }
+
+       /*
+        * Ok, we got a new connection. Allocate a device to it,
+        * and find out what it wants to do..
+        */
+       usb_dev = uhci_usb_allocate(uhci->root_hub->usb);
+       dev = usb_dev->hcpriv;
+
+       dev->uhci = uhci;
+
+       usb_connect(usb_dev);
+
+       uhci->root_hub->usb->children[nr] = usb_dev;
+
+       wait_ms(200); /* wait for powerup */
+       uhci_reset_port(port);
+
+       /* Get speed information */
+       usb_dev->slow = (inw(port) & USBPORTSC_LSDA) ? 1 : 0;
+
+       /*
+        * Ok, all the stuff specific to the root hub has been done.
+        * The rest is generic for any new USB attach, regardless of
+        * hub type.
+        */
+       usb_new_device(usb_dev);
+}
+
+/*
+ * This gets called when the root hub configuration
+ * has changed. Just go through each port, seeing if
+ * there is something interesting happening.
+ */
+static void uhci_check_configuration(struct uhci *uhci)
+{
+       unsigned int io_addr = uhci->io_addr + USBPORTSC1;
+       int maxchild = uhci->root_hub->usb->maxchild;
+       int nr = 0;
+
+       do {
+               unsigned short status = inw(io_addr);
+
+               if (status & USBPORTSC_CSC)
+                       uhci_connect_change(uhci, io_addr, nr);
+
+               nr++; io_addr += 2;
+       } while (nr < maxchild);
+}
+
+static void uhci_interrupt_notify(struct uhci *uhci)
+{
+       struct list_head *head = &uhci->interrupt_list;
+       struct list_head *tmp;
+
+       spin_lock(&irqlist_lock);
+       tmp = head->next;
+       while (tmp != head) {
+               struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
+               struct list_head *next;
+
+               next = tmp->next;
+
+               if (!(td->status & (1 << 23))) {        /* No longer active? */
+                       /* remove from IRQ list */
+                       __list_del(tmp->prev, next);
+                       INIT_LIST_HEAD(tmp);
+                       if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) {
+                               struct uhci_qh *interrupt_qh = td->qh;
+
+                               list_add(&td->irq_list, &uhci->interrupt_list);
+                               td->info ^= 1 << 19; /* toggle between data0 and data1 */
+                               td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */
+
+                               /* Remove then readd? Is that necessary */
+                               uhci_remove_td(td);
+                               uhci_insert_td_in_qh(interrupt_qh, td);
+                       }
+                       /* If completed wants to not reactivate, then it's */
+                       /* responsible for free'ing the TD's and QH's */
+                       /* or another function (such as run_control) */
+               }
+               tmp = next;
+       }
+       spin_unlock(&irqlist_lock);
+}
+
+/*
+ * Check port status - Connect Status Change - for
+ * each of the attached ports (defaults to two ports,
+ * but at least in theory there can be more of them).
+ *
+ * Wake up the configurator if something happened, we
+ * can't really do much at interrupt time.
+ */
+static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr)
+{
+       if (waitqueue_active(&uhci_configure)) {
+               int ports = uhci->root_hub->usb->maxchild;
+               io_addr += USBPORTSC1;
+               do {
+                       if (inw(io_addr) & USBPORTSC_CSC) {
+                               wake_up(&uhci_configure);
+                               return;
+                       }
+                       io_addr += 2;
+               } while (--ports > 0);
+       }
+}
+
+static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
+{
+       struct uhci *uhci = __uhci;
+       unsigned int io_addr = uhci->io_addr;
+       unsigned short status;
+
+       /*
+        * Read the interrupt status, and write it back to clear the interrupt cause
+        */
+       status = inw(io_addr + USBSTS);
+       outw(status, io_addr + USBSTS);
+
+       /* Walk the list of pending TD's to see which ones completed.. */
+       uhci_interrupt_notify(uhci);
+
+       /* Check if there are any events on the root hub.. */
+       uhci_root_hub_events(uhci, io_addr);
+}
+
+/*
+ * We init one packet, and mark it just IOC and _not_
+ * active. Which will result in no actual USB traffic,
+ * but _will_ result in an interrupt every second.
+ *
+ * Which is exactly what we want.
+ */
+static void uhci_init_ticktd(struct uhci *uhci)
+{
+       struct uhci_device *dev = uhci->root_hub;
+       struct uhci_td *td = uhci_td_allocate(dev);
+
+       td->link = 1;
+       td->status = (1 << 24);                                 /* interrupt on completion */
+       td->info = (15 << 21) | 0x7f69;                         /* (ignored) input packet, 16 bytes, device 127 */
+       td->buffer = 0;
+       td->qh = NULL;
+
+       uhci->fl->frame[0] = virt_to_bus(td);
+}
+
+static void reset_hc(struct uhci *uhci)
+{
+       unsigned int io_addr = uhci->io_addr;
+
+       /* Global reset for 50ms */
+       outw(USBCMD_GRESET, io_addr+USBCMD);
+       wait_ms(50);
+       outw(0, io_addr+USBCMD);
+       wait_ms(10);
+}
+
+static void start_hc(struct uhci *uhci)
+{
+       unsigned int io_addr = uhci->io_addr;
+       int timeout = 1000;
+
+       uhci_init_ticktd(uhci);
+
+       /*
+        * Reset the HC - this will force us to get a
+        * new notification of any already connected
+        * ports due to the virtual disconnect that it
+        * implies.
+        */
+       outw(USBCMD_HCRESET, io_addr + USBCMD);
+       while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
+               if (!--timeout) {
+                       printk("USBCMD_HCRESET timed out!\n");
+                       break;
+               }
+       }
+
+       outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+       outw(0, io_addr + USBFRNUM);
+       outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
+
+       /* Run and mark it configured with a 64-byte max packet */
+       outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD);
+}
+
+/*
+ * Allocate a frame list, and four regular queues.
+ *
+ * The hardware doesn't really know any difference
+ * in the queues, but the order does matter for the
+ * protocols higher up. The order is:
+ *
+ *  - any isochronous events handled before any
+ *    of the queues. We don't do that here, because
+ *    we'll create the actual TD entries on demand.
+ *  - The first queue is the "interrupt queue".
+ *  - The second queue is the "control queue".
+ *  - The third queue is "bulk data".
+ *
+ * We could certainly have multiple queues of the same
+ * type, and maybe we should. We could have per-device
+ * queues, for example. We begin small.
+ */
+static struct uhci *alloc_uhci(unsigned int io_addr)
+{
+       int i;
+       struct uhci *uhci;
+       struct usb_bus *bus;
+       struct uhci_device *dev;
+       struct usb_device *usb;
+
+       uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+       if (!uhci)
+               return NULL;
+
+       memset(uhci, 0, sizeof(*uhci));
+
+       uhci->irq = -1;
+       uhci->io_addr = io_addr;
+       INIT_LIST_HEAD(&uhci->interrupt_list);
+
+       /* We need exactly one page (per UHCI specs), how convenient */
+       uhci->fl = (void *)__get_free_page(GFP_KERNEL);
+
+       bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+       if (!bus)
+               return NULL;
+
+       memset(bus, 0, sizeof(*bus));
+
+       uhci->bus = bus;
+       bus->hcpriv = uhci;
+       bus->op = &uhci_device_operations;
+
+       /*
+        * We allocate a 8kB area for the UHCI hub. The area
+        * is described by the uhci_device structure, and basically
+        * contains everything needed for normal operation.
+        *
+        * The first page is the actual device descriptor for the
+        * hub.
+        *
+        * The second page is used for the frame list.
+        */
+       usb = uhci_usb_allocate(NULL);
+       if (!usb)
+               return NULL;
+
+       dev = uhci->root_hub = usb_to_uhci(usb);
+
+       usb->bus = bus;
+
+       /* Initialize the root hub */
+       /* UHCI specs says devices must have 2 ports, but goes on to say */
+       /* they may have more but give no way to determine how many they */
+       /* have, so default to 2 */
+       usb->maxchild = 2;
+       usb_init_root_hub(usb);
+
+       /*
+        * Initialize the queues. They all start out empty,
+        * linked to each other in the proper order.
+        */
+       for (i = 1 ; i < 9; i++) {
+               dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh);
+               dev->qh[i].element = 1;
+       }
+       
+       dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh);
+       dev->skel_control_qh.element = 1;
+
+       dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh);
+       dev->skel_bulk0_qh.element = 1;
+
+       dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh);
+       dev->skel_bulk1_qh.element = 1;
+
+       dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh);
+       dev->skel_bulk2_qh.element = 1;
+
+       dev->skel_bulk3_qh.link = 1;
+       dev->skel_bulk3_qh.element = 1;
+
+       /*
+        * Fill the frame list: make all entries point to
+        * the proper interrupt queue.
+        *
+        * This is probably silly, but it's a simple way to
+        * scatter the interrupt queues in a way that gives
+        * us a reasonable dynamic range for irq latencies.
+        */
+       for (i = 0; i < 1024; i++) {
+               struct uhci_qh * irq = &dev->skel_int2_qh;
+               if (i & 1) {
+                       irq++;
+                       if (i & 2) {
+                               irq++;
+                               if (i & 4) { 
+                                       irq++;
+                                       if (i & 8) { 
+                                               irq++;
+                                               if (i & 16) {
+                                                       irq++;
+                                                       if (i & 32) {
+                                                               irq++;
+                                                               if (i & 64) {
+                                                                       irq++;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+               uhci->fl->frame[i] =  2 | virt_to_bus(irq);
+       }
+
+       return uhci;
+}
+
+
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+       if (uhci->irq >= 0) {
+               free_irq(uhci->irq, uhci);
+               uhci->irq = -1;
+       }
+
+#if 0
+       if (uhci->root_hub) {
+               uhci_usb_deallocate(uhci_to_usb(uhci->root_hub));
+               uhci->root_hub = NULL;
+       }
+#endif
+
+       if (uhci->fl) {
+               free_page((unsigned long)uhci->fl);
+               uhci->fl = NULL;
+       }
+
+       kfree(uhci->bus);
+       kfree(uhci);
+}
+
+static int uhci_control_thread(void * __uhci)
+{
+       struct uhci *uhci = (struct uhci *)__uhci;
+
+       lock_kernel();
+       request_region(uhci->io_addr, 32, "usb-uhci");
+
+       /*
+        * This thread doesn't need any user-level access,
+        * so get rid of all our resources..
+        */
+       printk("uhci_control_thread at %p\n", &uhci_control_thread);
+       exit_mm(current);
+       exit_files(current);
+       exit_fs(current);
+
+       strcpy(current->comm, "uhci-control");
+
+       /*
+        * Ok, all systems are go..
+        */
+       start_hc(uhci);
+       for(;;) {
+               siginfo_t info;
+               int unsigned long signr;
+
+               interruptible_sleep_on(&uhci_configure);
+#ifdef CONFIG_APM
+               if (apm_resume) {
+                       apm_resume = 0;
+                       start_hc(uhci);
+                       continue;
+               }
+#endif
+               uhci_check_configuration(uhci);
+
+               if(signal_pending(current)) {
+                       /* sending SIGUSR1 makes us print out some info */
+                       spin_lock_irq(&current->sigmask_lock);
+                       signr = dequeue_signal(&current->blocked, &info);
+                       spin_unlock_irq(&current->sigmask_lock);
+
+                       if(signr == SIGUSR1) {
+                               printk("UHCI queue dump:\n");
+                               show_queues(uhci);
+                       } else {
+                               break;
+                       }
+               }
+       }
+
+#if 0
+       if(uhci->root_hub)
+               for(i = 0; i < uhci->root_hub->usb->maxchild; i++)
+                       usb_disconnect(uhci->root_hub->usb->children + i);
+#endif
+
+       reset_hc(uhci);
+       release_region(uhci->io_addr, 32);
+
+       release_uhci(uhci);
+       MOD_DEC_USE_COUNT;
+
+       printk("uhci_control_thread exiting\n");
+
+       return 0;
+}      
+
+/*
+ * If we've successfully found a UHCI, now is the time to increment the
+ * module usage count, start the control thread, and return success..
+ */
+static int found_uhci(int irq, unsigned int io_addr)
+{
+       int retval;
+       struct uhci *uhci;
+
+       uhci = alloc_uhci(io_addr);
+       if (!uhci)
+               return -ENOMEM;
+
+       reset_hc(uhci);
+
+       retval = -EBUSY;
+       if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) {
+               int pid;
+
+               MOD_INC_USE_COUNT;
+               uhci->irq = irq;
+               pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+               if (pid >= 0)
+                       return 0;
+
+               MOD_DEC_USE_COUNT;
+               retval = pid;
+       }
+       release_uhci(uhci);
+       return retval;
+}
+
+static int start_uhci(struct pci_dev *dev)
+{
+       int i;
+
+       /* Search for the IO base address.. */
+       for (i = 0; i < 6; i++) {
+               unsigned int io_addr = dev->base_address[i];
+
+               /* IO address? */
+               if (!(io_addr & 1))
+                       continue;
+
+               io_addr &= PCI_BASE_ADDRESS_IO_MASK;
+
+               /* Is it already in use? */
+               if (check_region(io_addr, 32))
+                       break;
+
+               return found_uhci(dev->irq, io_addr);
+       }
+       return -1;
+}
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+       static int down = 0;
+
+       switch (event) {
+       case APM_SYS_SUSPEND:
+       case APM_USER_SUSPEND:
+               if (down) {
+                       printk(KERN_DEBUG "uhci: received extra suspend event\n");
+                       break;
+               }
+               down = 1;
+               break;
+       case APM_NORMAL_RESUME:
+       case APM_CRITICAL_RESUME:
+               if (!down) {
+                       printk(KERN_DEBUG "uhci: received bogus resume event\n");
+                       break;
+               }
+               down = 0;
+               if (waitqueue_active(&uhci_configure)) {
+                       apm_resume = 1;
+                       wake_up(&uhci_configure);
+               }
+               break;
+       }
+       return 0;
+}
+#endif
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+       apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define uhci_init init_module
+
+#endif
+
+int uhci_init(void)
+{
+       int retval;
+       struct pci_dev *dev = NULL;
+       u8 type;
+
+       retval = -ENODEV;
+       for (;;) {
+               dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev);
+               if (!dev)
+                       break;
+               /* Is it UHCI */
+               pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
+               if(type != 0)
+                       continue;
+               /* Ok set it up */
+               retval = start_uhci(dev);
+               if (retval < 0)
+                       continue;
+
+               usb_mouse_init();
+               usb_kbd_init();
+               hub_init();
+#ifdef CONFIG_APM
+               apm_register_callback(&handle_apm_event);
+#endif
+
+               return 0;
+       }
+       return retval;
+}
diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h
new file mode 100644 (file)
index 0000000..0c351f1
--- /dev/null
@@ -0,0 +1,229 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+#include <linux/list.h>
+
+#include "usb.h"
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+/* Command register */
+#define USBCMD         0
+#define   USBCMD_RS            0x0001  /* Run/Stop */
+#define   USBCMD_HCRESET       0x0002  /* Host reset */
+#define   USBCMD_GRESET                0x0004  /* Global reset */
+#define   USBCMD_EGSM          0x0008  /* Global Suspend Mode */
+#define   USBCMD_FGR           0x0010  /* Force Global Resume */
+#define   USBCMD_SWDBG         0x0020  /* SW Debug mode */
+#define   USBCMD_CF            0x0040  /* Config Flag (sw only) */
+#define   USBCMD_MAXP          0x0080  /* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS         2
+#define   USBSTS_USBINT                0x0001  /* Interrupt due to IOC */
+#define   USBSTS_ERROR         0x0002  /* Interrupt due to error */
+#define   USBSTS_RD            0x0004  /* Resume Detect */
+#define   USBSTS_HSE           0x0008  /* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE          0x0010  /* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH           0x0020  /* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR                4
+#define   USBINTR_TIMEOUT      0x0001  /* Timeout/CRC error enable */
+#define   USBINTR_RESUME       0x0002  /* Resume interrupt enable */
+#define   USBINTR_IOC          0x0004  /* Interrupt On Complete enable */
+#define   USBINTR_SP           0x0008  /* Short packet interrupt enable */
+
+#define USBFRNUM       6
+#define USBFLBASEADD   8
+#define USBSOF         12
+
+/* USB port status and control registers */
+#define USBPORTSC1     16
+#define USBPORTSC2     18
+#define   USBPORTSC_CCS                0x0001  /* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC                0x0002  /* Connect Status Change */
+#define   USBPORTSC_PE         0x0004  /* Port Enable */
+#define   USBPORTSC_PEC                0x0008  /* Port Enable Change */
+#define   USBPORTSC_LS         0x0030  /* Line Status */
+#define   USBPORTSC_RD         0x0040  /* Resume Detect */
+#define   USBPORTSC_LSDA       0x0100  /* Low Speed Device Attached */
+#define   USBPORTSC_PR         0x0200  /* Port Reset */
+#define   USBPORTSC_SUSP       0x1000  /* Suspend */
+
+struct uhci_qh {
+       unsigned int link;      /* Next queue */
+       unsigned int element;   /* Queue element pointer */
+       int inuse;              /* Inuse? */
+       struct uhci_qh *skel;   /* Skeleton head */
+} __attribute__((aligned(16)));
+
+struct uhci_framelist {
+       unsigned int frame[1024];
+} __attribute__((aligned(4096)));
+
+/*
+ * The documentation says "4 words for hardware, 4 words for software".
+ *
+ * That's silly, the hardware doesn't care. The hardware only cares that
+ * the hardware words are 16-byte aligned, and we can have any amount of
+ * sw space after the TD entry as far as I can tell.
+ *
+ * But let's just go with the documentation, at least for 32-bit machines.
+ * On 64-bit machines we probably want to take advantage of the fact that
+ * hw doesn't really care about the size of the sw-only area.
+ *
+ * Alas, not anymore, we have more than 4 words of software, woops
+ */
+struct uhci_td {
+       /* Hardware fields */
+       __u32 link;
+       __u32 status;
+       __u32 info;
+       __u32 buffer;
+
+       /* Software fields */
+       struct list_head irq_list;      /* Active interrupt list.. */
+       usb_device_irq completed;       /* Completion handler routine */
+       unsigned int *backptr;          /* Where to remove this from.. */
+       void *dev_id;
+       int inuse;                      /* Inuse? */
+       struct uhci_qh *qh;
+} __attribute__((aligned(32)));
+
+/*
+ * Note the alignment requirements of the entries
+ *
+ * Each UHCI device has pre-allocated QH and TD entries.
+ * You can use more than the pre-allocated ones, but I
+ * don't see you usually needing to.
+ */
+struct uhci;
+
+#define UHCI_MAXTD 32
+
+#define UHCI_MAXQH     16
+
+/* The usb device part must be first! */
+struct uhci_device {
+       struct usb_device       *usb;
+
+       struct uhci             *uhci;
+       struct uhci_qh          qh[UHCI_MAXQH];         /* These are the "common" qh's for each device */
+       struct uhci_td          td[UHCI_MAXTD];
+
+       unsigned long           data[16];
+};
+
+#define uhci_to_usb(uhci)      ((uhci)->usb)
+#define usb_to_uhci(usb)       ((struct uhci_device *)(usb)->hcpriv)
+
+/*
+ * The root hub pre-allocated QH's and TD's have
+ * some special global uses..
+ */
+#define control_td     td              /* Td's 0-30 */
+/* This is only for the root hub's TD list */
+#define tick_td                td[31]
+
+/*
+ * There are various standard queues. We set up several different
+ * queues for each of the three basic queue types: interrupt,
+ * control, and bulk.
+ *
+ *  - There are various different interrupt latencies: ranging from
+ *    every other USB frame (2 ms apart) to every 256 USB frames (ie
+ *    256 ms apart). Make your choice according to how obnoxious you
+ *    want to be on the wire, vs how critical latency is for you.
+ *  - The control list is done every frame.
+ *  - There are 4 bulk lists, so that up to four devices can have a
+ *    bulk list of their own and when run concurrently all four lists
+ *    will be be serviced.
+ *
+ * This is a bit misleading, there are various interrupt latencies, but they
+ * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
+ * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
+ * problem
+ *
+ * In the case of the root hub, these QH's are just head's of qh's. Don't
+ * be scared, it kinda makes sense. Look at this wonderful picture care of
+ * Linus:
+ *
+ *  generic-iso-QH  ->  dev1-iso-QH  ->  generic-irq-QH  ->  dev1-irq-QH  -> ...
+ *       |                       |                  |                   |
+ *      End          dev1-iso-TD1          End            dev1-irq-TD1
+ *                       |
+ *                   dev1-iso-TD2
+ *                       |
+ *                      ....
+ *
+ * This may vary a bit (the UHCI docs don't explicitly say you can put iso
+ * transfers in QH's and all of their pictures don't have that either) but
+ * other than that, that is what we're doing now
+ *
+ * To keep with Linus' nomenclature, this is called the qh skeleton. These
+ * labels (below) are only signficant to the root hub's qh's
+ */
+#define skel_iso_qh            qh[0]
+
+#define skel_int2_qh           qh[1]
+#define skel_int4_qh           qh[2]
+#define skel_int8_qh           qh[3]
+#define skel_int16_qh          qh[4]
+#define skel_int32_qh          qh[5]
+#define skel_int64_qh          qh[6]
+#define skel_int128_qh         qh[7]
+#define skel_int256_qh         qh[8]
+
+#define skel_control_qh                qh[9]
+
+#define skel_bulk0_qh          qh[10]
+#define skel_bulk1_qh          qh[11]
+#define skel_bulk2_qh          qh[12]
+#define skel_bulk3_qh          qh[13]
+
+/*
+ * These are significant to the devices allocation of QH's
+ */
+#if 0
+#define iso_qh                 qh[0]
+#define int_qh                 qh[1]   /* We have 2 "common" interrupt QH's */
+#define control_qh             qh[3]
+#define bulk_qh                        qh[4]   /* We have 4 "common" bulk QH's */
+#define extra_qh               qh[8]   /* The rest, anything goes */
+#endif
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci {
+       int irq;
+       unsigned int io_addr;
+
+       struct usb_bus *bus;
+
+#if 0
+       /* These are "standard" QH's for the entire bus */
+       struct uhci_qh qh[UHCI_MAXQH];
+#endif
+       struct uhci_device *root_hub;           /* Root hub device descriptor.. */
+
+       struct uhci_framelist *fl;              /* Frame list */
+       struct list_head interrupt_list;        /* List of interrupt-active TD's for this uhci */
+};
+
+/* needed for the debugging code */
+struct uhci_td *uhci_link_to_td(unsigned int element);
+
+/* Debugging code */
+void show_td(struct uhci_td * td);
+void show_status(struct uhci *uhci);
+void show_queues(struct uhci *uhci);
+
+#endif
+
diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c
new file mode 100644 (file)
index 0000000..86d08cd
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * debug.c - USB debug helper routines.
+ *
+ * I just want these out of the way where they aren't in your
+ * face, but so that you can still use them..
+ */
+#include <linux/kernel.h>
+
+#include "usb.h"
+
+static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
+{
+       usb_show_endpoint_descriptor(endpoint);
+}
+
+static void usb_show_interface(struct usb_interface_descriptor *interface)
+{
+       int i;
+
+       usb_show_interface_descriptor(interface);
+       for (i = 0 ; i < interface->bNumEndpoints; i++)
+               usb_show_endpoint(interface->endpoint + i);
+}
+
+static void usb_show_config(struct usb_config_descriptor *config)
+{
+       int i;
+
+       usb_show_config_descriptor(config);
+       for (i = 0 ; i < config->bNumInterfaces; i++)
+               usb_show_interface(config->interface + i);
+}
+
+void usb_show_device(struct usb_device *dev)
+{
+       int i;
+
+       usb_show_device_descriptor(&dev->descriptor);
+       for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+               usb_show_config(dev->config + i);
+}
+
+
+/*
+ * Parse and show the different USB descriptors.
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *desc)
+{
+       printk("  USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
+       printk("  Vendor:  %04x\n", desc->idVendor);
+       printk("  Product: %04x\n", desc->idProduct);
+       printk("  Configurations: %d\n", desc->bNumConfigurations);
+
+       printk("  Device Class: %d\n", desc->bDeviceClass);
+       switch (desc->bDeviceClass) {
+       case 0:
+               printk("    Per-interface classes\n");
+               break;
+       case 9:
+               printk("    Hub device class\n");
+               break;
+       case 0xff:
+               printk("    Vendor class\n");
+               break;
+       default:
+               printk("    Unknown class\n");
+       }
+}
+
+void usb_show_config_descriptor(struct usb_config_descriptor * desc)
+{
+       printk("Configuration:\n");
+       printk("  bLength             = %4d%s\n", desc->bLength,
+               desc->bLength == 9 ? "" : " (!!!)");
+       printk("  bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("  wTotalLength        = %04x\n", desc->wTotalLength);
+       printk("  bNumInterfaces      =   %02x\n", desc->bNumInterfaces);
+       printk("  bConfigurationValue =   %02x\n", desc->bConfigurationValue);
+       printk("  iConfiguration      =   %02x\n", desc->iConfiguration);
+       printk("  bmAttributes        =   %02x\n", desc->bmAttributes);
+       printk("  MaxPower            = %4dmA\n", desc->MaxPower * 2);
+}
+
+void usb_show_interface_descriptor(struct usb_interface_descriptor * desc)
+{
+       printk("  Interface:\n");
+       printk("    bLength             = %4d%s\n", desc->bLength,
+               desc->bLength == 9 ? "" : " (!!!)");
+       printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("    bInterfaceNumber    =   %02x\n", desc->bInterfaceNumber);
+       printk("    bAlternateSetting   =   %02x\n", desc->bAlternateSetting);
+       printk("    bNumEndpoints       =   %02x\n", desc->bNumEndpoints);
+       printk("    bInterfaceClass     =   %02x\n", desc->bInterfaceClass);
+       printk("    bInterfaceSubClass  =   %02x\n", desc->bInterfaceSubClass);
+       printk("    bInterfaceProtocol  =   %02x\n", desc->bInterfaceProtocol);
+       printk("    iInterface          =   %02x\n", desc->iInterface);
+}
+
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc)
+{
+       char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
+       printk("    Endpoint:\n");
+       printk("      bLength             = %4d%s\n", desc->bLength,
+               desc->bLength == 7 ? "" : " (!!!)");
+       printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
+       printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,
+               (desc->bEndpointAddress & 0x80) ? "in" : "out");
+       printk("      bmAttributes        =   %02x (%s)\n", desc->bmAttributes,
+               EndpointType[3 & desc->bmAttributes]);
+       printk("      wMaxPacketSize      = %04x\n", desc->wMaxPacketSize);
+       printk("      bInterval           =   %02x\n", desc->bInterval);
+}
+
+void usb_show_hub_descriptor(struct usb_hub_descriptor * desc)
+{
+       int len = 7;
+       unsigned char *ptr = (unsigned char *) desc;
+
+       printk("Interface:");
+       while (len) {
+               printk(" %02x", *ptr);
+               ptr++; len--;
+       }
+       printk("\n");
+}
+
+
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
new file mode 100644 (file)
index 0000000..cc6ed02
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * driver/usb/usb.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ *
+ * NOTE! This is not actually a driver at all, rather this is
+ * just a collection of helper routines that implement the
+ * generic USB things that the real drivers can use..
+ *
+ * Think of this as a "USB library" rather than anything else.
+ * It should be considered a slave, with no callbacks. Callbacks
+ * are evil.
+ */
+
+/*
+ * Table 9-2
+ *
+ * Offset      Field           Size    Value           Desc
+ * 0           bmRequestType   1       Bitmap          D7:     Direction
+ *                                                     0 = Host-to-device
+ *                                                     1 = Device-to-host
+ *                                                     D6..5:  Type
+ *                                                     0 = Standard
+ *                                                     1 = Class
+ *                                                     2 = Vendor
+ *                                                     3 = Reserved
+ *                                                     D4..0:  Recipient
+ *                                                     0 = Device
+ *                                                     1 = Interface
+ *                                                     2 = Endpoint
+ *                                                     3 = Other
+ *                                                     4..31 = Reserved
+ * 1           bRequest        1       Value           Specific request (9-3)
+ * 2           wValue          2       Value           Varies
+ * 4           wIndex          2       Index/Offset    Varies
+ * 6           wLength         2       Count           Bytes for data
+ */
+
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/malloc.h>
+
+#include "usb.h"
+
+/*
+ * We have a per-interface "registered driver" list.
+ */
+static LIST_HEAD(usb_driver_list);
+
+int usb_register(struct usb_driver *new_driver)
+{
+       /* Add it to the list of known drivers */
+       list_add(&new_driver->driver_list, &usb_driver_list);
+
+       /*
+        * We should go through all existing devices, and see if any of
+        * them would be acceptable to the new driver.. Let's do that
+        * in version 2.0.
+        */
+       return 0;
+}
+
+void usb_deregister(struct usb_driver *driver)
+{
+       list_del(&driver->driver_list);
+}
+
+/*
+ * This entrypoint gets called for each new device.
+ *
+ * We now walk the list of registered USB drivers,
+ * looking for one that will accept this device as
+ * his..
+ */
+void usb_device_descriptor(struct usb_device *dev)
+{
+       struct list_head *tmp = usb_driver_list.next;
+
+       while (tmp != &usb_driver_list) {
+               struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+               tmp = tmp->next;
+               if (driver->probe(dev))
+                       continue;
+               dev->driver = driver;
+               return;
+       }
+
+       /*
+        * Ok, no driver accepted the device, so show the info
+        * for debugging..
+        */
+       printk("Unknown new USB device:\n");
+       usb_show_device(dev);
+}
+
+/*
+ * Parse the fairly incomprehensible output of
+ * the USB configuration data, and build up the
+ * USB device database.
+ */
+static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex)
+{
+       int parsed = 0;
+
+       for (;;) {
+               unsigned short n_desc;
+               int n_len, i;
+
+               if (len < descindex)
+                       return -1;
+               n_desc = *(unsigned short *)ptr;
+               if (n_desc == ((desctype << 8) + descindex))
+                       return parsed;
+               printk(
+               "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n",
+                       desctype, descindex,
+                       (n_desc >> 8) & 0xFF, n_desc & 0xFF);
+               n_len = n_desc & 0xff;
+               if (n_len < 2 || n_len > len)
+                       return -1;
+               for (i = 0 ; i < n_len; i++)
+                       printk("   %d %02x\n", i, ptr[i]);
+               len -= n_len;
+               ptr += n_len;
+               parsed += n_len;
+       }
+}
+
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len)
+{
+       int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7);
+
+       if (parsed < 0)
+               return parsed;
+
+       memcpy(endpoint, ptr + parsed, 7);
+       return parsed + 7;
+}
+
+static int usb_parse_interface(struct usb_interface_descriptor *interface, unsigned char *ptr, int len)
+{
+       int i;
+       int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9);
+       int retval;
+
+       if (parsed < 0)
+               return parsed;
+
+       memcpy(interface, ptr + parsed, 9);
+       len -= 9;
+       parsed += 9;
+
+       if (interface->bNumEndpoints > USB_MAXENDPOINTS)
+               return -1;
+
+       for (i = 0; i < interface->bNumEndpoints; i++) {
+               if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) {
+                       parsed += 9;    /* skip over the HID descriptor for now */
+                       len -= 9;
+               }
+               retval = usb_parse_endpoint(interface->endpoint + i, ptr + parsed, len);
+               if (retval < 0) return retval;
+               parsed += retval;
+               len -= retval;
+       }
+       return parsed;
+}
+
+static int usb_parse_config(struct usb_config_descriptor *config, unsigned char *ptr, int len)
+{
+       int i;
+       int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9);
+
+       if (parsed < 0)
+               return parsed;
+
+       memcpy(config, ptr + parsed, 9);
+       len -= 9;
+       parsed += 9;
+
+       if (config->bNumInterfaces > USB_MAXINTERFACES)
+               return -1;
+
+       for (i = 0; i < config->bNumInterfaces; i++) {
+               int retval = usb_parse_interface(config->interface + i, ptr + parsed, len);
+               if (retval < 0)
+                       return retval;
+               parsed += retval;
+               len -= retval;
+       }
+       return parsed;
+}
+
+int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes)
+{
+       int i;
+       unsigned char *ptr = __buf;
+
+       if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
+               return -1;
+
+       for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+               int retval = usb_parse_config(dev->config + i, ptr, bytes);
+               if (retval < 0)
+                       return retval;
+               ptr += retval;
+               bytes += retval;
+       }
+       return 0;
+}
+
+void usb_init_root_hub(struct usb_device *dev)
+{
+       dev->devnum = -1;
+       dev->slow = 0;
+}
+
+/*
+ * Something got disconnected. Get rid of it, and all of its children.
+ */
+void usb_disconnect(struct usb_device **pdev)
+{
+       struct usb_device * dev = *pdev;
+
+       if (dev) {
+               int i;
+
+               *pdev = NULL;
+
+               printk("USB disconnect on device %d\n", dev->devnum);
+
+               if(dev->driver) dev->driver->disconnect(dev);
+
+               /* Free up all the children.. */
+               for (i = 0; i < USB_MAXCHILDREN; i++) {
+                       struct usb_device **child = dev->children + i;
+                       usb_disconnect(child);
+               }
+
+               /* Free up the device itself, including its device number */
+               if (dev->devnum > 0)
+                       clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+               dev->bus->op->deallocate(dev);
+       }
+}
+
+
+/*
+ * Connect a new USB device. This basically just initializes
+ * the USB device information and sets up the topology - it's
+ * up to the low-level driver to reset the port and actually
+ * do the setup (the upper levels don't know how to do that).
+ */
+void usb_connect(struct usb_device *dev)
+{
+       int devnum;
+
+       dev->descriptor.bMaxPacketSize0 = 8;  /* XXX fixed 8 bytes for now */
+
+       devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
+       if (devnum < 128) {
+               set_bit(devnum, dev->bus->devmap.devicemap);
+               dev->devnum = devnum;
+       }
+}
+
+/*
+ * These are the actual routines to send
+ * and receive control messages.
+ */
+int usb_set_address(struct usb_device *dev)
+{
+       devrequest dr;
+
+       dr.requesttype = 0;
+       dr.request = USB_REQ_SET_ADDRESS;
+       dr.value = dev->devnum;
+       dr.index = 0;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0);
+}
+
+int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+{
+       devrequest dr;
+
+       dr.requesttype = 0x80;
+       dr.request = USB_REQ_GET_DESCRIPTOR;
+       dr.value = (type << 8) + index;
+       dr.index = 0;
+       dr.length = size;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+}
+
+int usb_get_device_descriptor(struct usb_device *dev)
+{
+       return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
+}
+
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_HUB | 0x80;
+       dr.request = USB_REQ_GET_DESCRIPTOR;
+       dr.value = (USB_DT_HUB << 8);
+       dr.index = 0;
+       dr.length = size;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size);
+}
+
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_PORT;
+       dr.request = USB_REQ_CLEAR_FEATURE;
+       dr.value = feature;
+       dr.index = port;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_PORT;
+       dr.request = USB_REQ_SET_FEATURE;
+       dr.value = feature;
+       dr.index = port;
+       dr.length = 0;
+
+       return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_HUB | 0x80;
+       dr.request = USB_REQ_GET_STATUS;
+       dr.value = 0;
+       dr.index = 0;
+       dr.length = 4;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
+}
+
+int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_PORT | 0x80;
+       dr.request = USB_REQ_GET_STATUS;
+       dr.value = 0;
+       dr.index = port;
+       dr.length = 4;
+
+       return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
+}
+
+int usb_get_protocol(struct usb_device *dev)
+{
+       unsigned char buf[8];
+       devrequest dr;
+
+       dr.requesttype = USB_RT_HIDD | 0x80;
+       dr.request = USB_REQ_GET_PROTOCOL;
+       dr.value = 0;
+       dr.index = 1;
+       dr.length = 1;
+
+       if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1))
+               return -1;
+
+       return buf[0];
+}
+
+int usb_set_protocol(struct usb_device *dev, int protocol)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_HIDD;
+       dr.request = USB_REQ_SET_PROTOCOL;
+       dr.value = protocol;
+       dr.index = 1;
+       dr.length = 0;
+
+       if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+               return -1;
+
+       return 0;
+}
+
+/* keyboards want a nonzero duration according to HID spec, but
+   mice should use infinity (0) -keryan */
+int usb_set_idle(struct usb_device *dev,  int duration, int report_id)
+{
+       devrequest dr;
+
+       dr.requesttype = USB_RT_HIDD;
+       dr.request = USB_REQ_SET_IDLE;
+       dr.value = (duration << 8) | report_id;
+       dr.index = 1;
+       dr.length = 0;
+
+       if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+               return -1;
+
+       return 0;
+}
+
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+       devrequest dr;
+
+       dr.requesttype = 0;
+       dr.request = USB_REQ_SET_CONFIGURATION;
+       dr.value = configuration;
+       dr.index = 0;
+       dr.length = 0;
+
+       if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+               return -1;
+
+       return 0;
+}
+
+int usb_get_report(struct usb_device *dev)
+{
+       unsigned char buf[8];
+       devrequest dr;
+
+       dr.requesttype = USB_RT_HIDD | 0x80;
+       dr.request = USB_REQ_GET_REPORT;
+       dr.value = 0x100;
+       dr.index = 1;
+       dr.length = 3;
+
+       if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3))
+               return -1;
+
+       return buf[0];
+}
+
+int usb_get_configuration(struct usb_device *dev)
+{
+       unsigned int size;
+       unsigned char buffer[128];
+
+       /* Get the first 8 bytes - guaranteed */
+       if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, 8))
+               return -1;
+
+       /* Get the full buffer */
+       size = *(unsigned short *)(buffer+2);
+       if (size > sizeof(buffer))
+               size = sizeof(buffer);
+
+       if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, size))
+               return -1;
+
+       return usb_parse_configuration(dev, buffer, size);
+}
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ */
+void usb_new_device(struct usb_device *dev)
+{
+       int addr, i;
+
+       printk("USB new device connect, assigned device number %d\n",
+               dev->devnum);
+
+       dev->maxpacketsize = 0;         /* Default to 8 byte max packet size */
+
+       addr = dev->devnum;
+       dev->devnum = 0;
+
+       /* Slow devices */
+       for (i = 0; i < 5; i++) {
+               if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
+                       break;
+
+               printk("get_descriptor failed, waiting\n");
+               wait_ms(200);
+       }
+       if (i == 5) {
+               printk("giving up\n");
+               return;
+       }
+
+#if 0
+       printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
+#endif
+       switch (dev->descriptor.bMaxPacketSize0) {
+               case 8: dev->maxpacketsize = 0; break;
+               case 16: dev->maxpacketsize = 1; break;
+               case 32: dev->maxpacketsize = 2; break;
+               case 64: dev->maxpacketsize = 3; break;
+       }
+#if 0
+       printk("dev->mps: %d\n", dev->maxpacketsize);
+#endif
+
+       dev->devnum = addr;
+
+       if (usb_set_address(dev)) {
+               printk("Unable to set address\n");
+               /* FIXME: We should disable the port */
+               return;
+       }
+
+       wait_ms(10);    /* Let the SET_ADDRESS settle */
+
+       if (usb_get_device_descriptor(dev)) {
+               printk("Unable to get device descriptor\n");
+               return;
+       }
+
+       if (usb_get_configuration(dev)) {
+               printk("Unable to get configuration\n");
+               return;
+       }
+
+#if 0
+       printk("Vendor: %X\n", dev->descriptor.idVendor);
+       printk("Product: %X\n", dev->descriptor.idProduct);
+#endif
+
+       usb_device_descriptor(dev);
+}
+
+int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+       return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
+}
+
diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h
new file mode 100644 (file)
index 0000000..b317acf
--- /dev/null
@@ -0,0 +1,359 @@
+#ifndef __LINUX_USB_H
+#define __LINUX_USB_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+
+static __inline__ void wait_ms(unsigned int ms)
+{
+        current->state = TASK_UNINTERRUPTIBLE;
+        schedule_timeout(1 + ms / 10);
+}
+
+
+typedef struct {
+  unsigned char requesttype;
+  unsigned char request;
+  unsigned short value;
+  unsigned short index;
+  unsigned short length;
+} devrequest;
+
+/*
+ * Class codes
+ */
+#define USB_CLASS_HUB                  9
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+
+#define USB_DT_HUB                     0x29
+#define USB_DT_HID                     0x21
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+/* 0x02 is reserved */
+#define USB_REQ_SET_FEATURE            0x03
+/* 0x04 is reserved */
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+/*
+ * HIDD requests
+ */
+#define USB_REQ_GET_REPORT             0x01
+#define USB_REQ_GET_IDLE               0x02
+#define USB_REQ_GET_PROTOCOL           0x03
+#define USB_REQ_SET_REPORT             0x09
+#define USB_REQ_SET_IDLE               0x0A
+#define USB_REQ_SET_PROTOCOL           0x0B
+
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+
+/*
+ * Request target types.
+ */
+#define USB_RT_DEVICE                  0x00
+#define USB_RT_INTERFACE               0x01
+#define USB_RT_ENDPOINT                        0x02
+
+#define USB_RT_HUB                     (USB_TYPE_CLASS | USB_RECIP_DEVICE)
+#define USB_RT_PORT                    (USB_TYPE_CLASS | USB_RECIP_OTHER)
+
+#define USB_RT_HIDD                    (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+/*
+ * USB device number allocation bitmap. There's one bitmap
+ * per USB tree.
+ */
+struct usb_devmap {
+       unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+};
+
+/*
+ * This is a USB device descriptor.
+ *
+ * USB device information
+ *
+ * Make this MUCH dynamic, right now
+ * it contains enough information for
+ * a USB floppy controller, and nothing
+ * else.
+ *
+ * I'm not proud. I just want this dang
+ * thing to start working.
+ */
+#define USB_MAXCONFIG          1
+#define USB_MAXINTERFACES      3
+#define USB_MAXENDPOINTS       3
+
+struct usb_device_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __u16 idVendor;
+       __u16 idProduct;
+       __u16 bcdDevice;
+       __u8  iManufacturer;
+       __u8  iProduct;
+       __u8  iSerialNumber;
+       __u8  bNumConfigurations;
+};
+
+/* Endpoint descriptor */
+struct usb_endpoint_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bEndpointAddress;
+       __u8  bmAttributes;
+       __u16 wMaxPacketSize;
+       __u8  bInterval;
+};
+
+/* Interface descriptor */
+struct usb_interface_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bInterfaceNumber;
+       __u8  bAlternateSetting;
+       __u8  bNumEndpoints;
+       __u8  bInterfaceClass;
+       __u8  bInterfaceSubClass;
+       __u8  bInterfaceProtocol;
+       __u8  iInterface;
+
+       struct usb_endpoint_descriptor endpoint[USB_MAXENDPOINTS];
+};
+
+/* Configuration descriptor information.. */
+struct usb_config_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u16 wTotalLength;
+       __u8  bNumInterfaces;
+       __u8  bConfigurationValue;
+       __u8  iConfiguration;
+       __u8  bmAttributes;
+       __u8  MaxPower;
+
+       struct usb_interface_descriptor interface[USB_MAXINTERFACES];
+};
+
+/* String descriptor */
+struct usb_string_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+};
+
+/* Hub descriptor */
+struct usb_hub_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bNbrPorts;
+       __u16 wHubCharacteristics;
+       __u8  bPwrOn2PwrGood;
+       __u8  bHubContrCurrent;
+       /* DeviceRemovable and PortPwrCtrlMask want to be variable-length 
+          bitmaps that hold max 256 entries, but for now they're ignored */
+       __u8  filler;
+};
+
+struct usb_device;
+
+struct usb_driver {
+       const char * name;
+       int (*probe)(struct usb_device *);
+       void (*disconnect)(struct usb_device *);
+       struct list_head driver_list;
+};
+
+/*
+ * Pointer to a device endpoint interrupt function -greg
+ */
+typedef int (*usb_device_irq)(int, void *, void *);
+
+struct usb_operations {
+       struct usb_device *(*allocate)(struct usb_device *);
+       int (*deallocate)(struct usb_device *);
+       int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
+       int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+};
+
+/*
+ * Allocated per bus we have
+ */
+struct usb_bus {
+       struct usb_devmap devmap;       /* Device map */
+       struct usb_operations *op;      /* Operations (specific to the HC) */
+       struct usb_device *root_hub;    /* Root hub */
+       void *hcpriv;                   /* Host Controller private data */
+};
+
+
+#define USB_MAXCHILDREN (8)
+
+struct usb_device {
+       int devnum;                                             /* Device number on USB bus */
+       int slow;                                               /* Slow device? */
+       int maxpacketsize;                                      /* Maximum packet size */
+
+       struct usb_bus *bus;                                    /* Bus we're apart of */
+       struct usb_driver *driver;                              /* Driver */
+       struct usb_device_descriptor descriptor;                /* Descriptor */
+       struct usb_config_descriptor config[USB_MAXCONFIG];     /* All of the configs */
+       struct usb_device *parent;
+  
+       /*
+        * Child devices - these can be either new devices
+        * (if this is a hub device), or different instances
+        * of this same device.
+        *
+        * Each instance needs its own set of data structuctures.
+        */
+
+       int maxchild;                   /* Number of ports if hub */
+       struct usb_device *children[USB_MAXCHILDREN];
+
+       void *hcpriv;                   /* Host Controller private data */
+       void *private;                  /* Upper layer private data */
+};
+
+extern int usb_register(struct usb_driver *);
+extern void usb_deregister(struct usb_driver *);
+
+extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+
+extern void usb_init_root_hub(struct usb_device *dev);
+extern void usb_connect(struct usb_device *dev);
+extern void usb_disconnect(struct usb_device **);
+extern void usb_device_descriptor(struct usb_device *dev);
+
+extern int  usb_parse_configuration(struct usb_device *dev, void *buf, int len);
+
+/*
+ * Calling this entity a "pipe" is glorifying it. A USB pipe
+ * is something embarrassingly simple: it basically consists
+ * of the following information:
+ *  - device number (7 bits)
+ *  - endpoint number (4 bits)
+ *  - current Data0/1 state (1 bit)
+ *  - direction (1 bit)
+ *  - speed (1 bit)
+ *  - max packet size (2 bits: 8, 16, 32 or 64)
+ *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
+ *
+ * That's 18 bits. Really. Nothing more. And the USB people have
+ * documented these eighteen bits as some kind of glorious
+ * virtual data structure.
+ *
+ * Let's not fall in that trap. We'll just encode it as a simple
+ * unsigned int. The encoding is:
+ *
+ *  - device:          bits 8-14
+ *  - endpoint:                bits 15-18
+ *  - Data0/1:         bit 19
+ *  - direction:       bit 7           (0 = Host-to-Device, 1 = Device-to-Host)
+ *  - speed:           bit 26          (0 = High, 1 = Low Speed)
+ *  - max size:                bits 0-1        (00 = 8, 01 = 16, 10 = 32, 11 = 64)
+ *  - pipe type:       bits 30-31      (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
+ *
+ * Why? Because it's arbitrary, and whatever encoding we select is really
+ * up to us. This one happens to share a lot of bit positions with the UCHI
+ * specification, so that much of the uhci driver can just mask the bits
+ * appropriately.
+ */
+
+#define usb_maxpacket(pipe)    (8 << ((pipe) & 3))
+#define usb_packetid(pipe)     (((pipe) & 0x80) ? 0x69 : 0xE1)
+
+#define usb_pipedevice(pipe)   (((pipe) >> 8) & 0x7f)
+#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf)
+#define usb_pipedata(pipe)     (((pipe) >> 19) & 1)
+#define usb_pipeout(pipe)      (((pipe) & 0x80) == 0)
+#define usb_pipeslow(pipe)     (((pipe) >> 26) & 1)
+
+#define usb_pipetype(pipe)     (((pipe) >> 30) & 3)
+#define usb_pipeisoc(pipe)     (usb_pipetype((pipe)) == 0)
+#define usb_pipeint(pipe)      (usb_pipetype((pipe)) == 1)
+#define usb_pipecontrol(pipe)  (usb_pipetype((pipe)) == 2)
+#define usb_pipebulk(pipe)     (usb_pipetype((pipe)) == 3)
+
+#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff)
+
+static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
+{
+       return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26) | dev->maxpacketsize;
+}
+
+static inline unsigned int __default_pipe(struct usb_device *dev)
+{
+       return (dev->slow << 26);
+}
+
+/* Create control pipes.. */
+#define usb_sndctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvctrlpipe(dev,endpoint)  ((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_snddefctrl(dev)            ((2 << 30) | __default_pipe(dev))
+#define usb_rcvdefctrl(dev)            ((2 << 30) | __default_pipe(dev) | 0x80)
+
+/* Create .. */
+
+/*
+ * Send and receive control messages..
+ */
+void usb_new_device(struct usb_device *dev);
+int usb_set_address(struct usb_device *dev);
+int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned
+char descindex, void *buf, int size);
+int usb_get_device_descriptor(struct usb_device *dev);
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size);
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
+int usb_set_port_feature(struct usb_device *dev, int port, int feature);
+int usb_get_hub_status(struct usb_device *dev, void *data);
+int usb_get_port_status(struct usb_device *dev, int port, void *data);
+int usb_get_protocol(struct usb_device *dev);
+int usb_set_protocol(struct usb_device *dev, int protocol);
+int usb_set_idle(struct usb_device *dev, int duration, int report_id);
+int usb_set_configuration(struct usb_device *dev, int configuration);
+int usb_get_report(struct usb_device *dev);
+
+/*
+ * Debugging helpers..
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *);
+void usb_show_config_descriptor(struct usb_config_descriptor *);
+void usb_show_interface_descriptor(struct usb_interface_descriptor *);
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
+void usb_show_hub_descriptor(struct usb_hub_descriptor *);
+void usb_show_device(struct usb_device *);
+
+#endif
+
index 12f7f6f6d99a8c908d815428f07bf49b2b1fe72e..ac81954d7b6c3d81e690be7ee46ac7356ad9fca2 100644 (file)
@@ -280,8 +280,6 @@ static int adfs_readdir (struct file *filp, void *dirent, filldir_t filldir)
        unsigned long parent_object_id, dir_object_id;
        int buffers, pos;
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
        sb = inode->i_sb;
 
        if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2)
index 24f0565d92e3ad11f0e624b80d78103ea65ce881..4f6e066845f1df66d2057bd86894a459ee875ba6 100644 (file)
@@ -98,22 +98,22 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name
        return 0;
 }
 
-int adfs_lookup (struct inode *dir, struct dentry *dentry)
+struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry)
 {
        struct inode *inode = NULL;
        struct adfs_idir_entry de;
        unsigned long ino;
 
        if (dentry->d_name.len > ADFS_NAME_LEN)
-               return -ENAMETOOLONG;
+               return ERR_PTR(-ENAMETOOLONG);
 
        if (adfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de)) {
                ino = de.inode_no;
                inode = iget (dir->i_sb, ino);
 
                if (!inode)
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
index 51e45b682be0f39cec3680b9ea875dd760b2ce39..3a1c78ef090194b65981e525b066afa9237e7a83 100644 (file)
@@ -90,9 +90,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
-
        stored = 0;
        dir_bh = NULL;
        fh_bh  = NULL;
index b2ebb98d7f26c61ec69f0bd9fddd03463adc0cf8..48e95180000f6b067d809083fbe7ec623fd1c333 100644 (file)
@@ -201,7 +201,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
        return bh;
 }
 
-int
+struct dentry *
 affs_lookup(struct inode *dir, struct dentry *dentry)
 {
        unsigned long            ino;
@@ -218,11 +218,11 @@ affs_lookup(struct inode *dir, struct dentry *dentry)
                affs_brelse(bh);
                inode = iget(dir->i_sb,ino);
                if (!inode)
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        dentry->d_op = &affs_dentry_operations;
        d_add(dentry,inode);
-       return 0;
+       return NULL;
 }
 
 int
index 63efe9b870257d98061413b9a48f495768e54622..d6944e889d4ff919d98a55dbf9ce66c45ac4917d 100644 (file)
@@ -38,10 +38,10 @@ static int autofs_dir_readdir(struct file *filp,
 /*
  * No entries except for "." and "..", both of which are handled by the VFS layer
  */
-static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
 {
        d_add(dentry, NULL);
-       return 0;
+       return NULL;
 }
 
 static struct file_operations autofs_dir_operations = {
index 396f321318765d847c7f6df0e8578fb654dc3a2f..c860f13ebce21373b7b924ace6859ff84977af31 100644 (file)
@@ -16,7 +16,7 @@
 #include "autofs_i.h"
 
 static int autofs_root_readdir(struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,struct dentry *);
+static struct dentry *autofs_root_lookup(struct inode *,struct dentry *);
 static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
 static int autofs_root_unlink(struct inode *,struct dentry *);
 static int autofs_root_rmdir(struct inode *,struct dentry *);
@@ -209,7 +209,7 @@ static struct dentry_operations autofs_dentry_operations = {
        NULL,                   /* d_compare */
 };
 
-static int autofs_root_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry)
 {
        struct autofs_sb_info *sbi;
        int oz_mode;
@@ -217,11 +217,8 @@ static int autofs_root_lookup(struct inode *dir, struct dentry *dentry)
        DPRINTK(("autofs_root_lookup: name = "));
        autofs_say(dentry->d_name.name,dentry->d_name.len);
 
-       if (!S_ISDIR(dir->i_mode))
-               return -ENOTDIR;
-
        if (dentry->d_name.len > NAME_MAX)
-               return -ENOENT; /* File name too long to exist */
+               return ERR_PTR(-ENOENT);/* File name too long to exist */
 
        sbi = autofs_sbi(dir->i_sb);
 
@@ -253,7 +250,7 @@ static int autofs_root_lookup(struct inode *dir, struct dentry *dentry)
         */
        if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
                if (signal_pending(current))
-                       return -ERESTARTNOINTR;
+                       return ERR_PTR(-ERESTARTNOINTR);
        }
 
        /*
@@ -263,9 +260,9 @@ static int autofs_root_lookup(struct inode *dir, struct dentry *dentry)
         * be OK for the operations we permit from an autofs.
         */
        if ( dentry->d_inode && list_empty(&dentry->d_hash) )
-               return -ENOENT;
+               return ERR_PTR(-ENOENT);
 
-       return 0;
+       return NULL;
 }
 
 static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
index dbbff73d4af4e2749ec8bb6584c3a3582a91f17f..0abf1894940514a53a61ea984001fb90ceec92f9 100644 (file)
@@ -804,6 +804,7 @@ void __brelse(struct buffer_head * buf)
        /* If dirty, mark the time this buffer should be written back. */
        set_writetime(buf, 0);
        refile_buffer(buf);
+       touch_buffer(buf);
 
        if (buf->b_count) {
                buf->b_count--;
@@ -839,7 +840,6 @@ struct buffer_head * bread(kdev_t dev, int block, int size)
        struct buffer_head * bh;
 
        bh = getblk(dev, block, size);
-       touch_buffer(bh);
        if (buffer_uptodate(bh))
                return bh;
        ll_rw_block(READ, 1, &bh);
@@ -876,7 +876,6 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize,
        bh = getblk(dev, block, bufsize);
        index = BUFSIZE_INDEX(bh->b_size);
 
-       touch_buffer(bh);
        if (buffer_uptodate(bh))
                return(bh);   
        else ll_rw_block(READ, 1, &bh);
index b87728d7bbbe50eafdf423b0aea39c63429d2f70..136c817be85f3acd6588bcccc203b3565f16ebcd 100644 (file)
@@ -29,7 +29,7 @@
 /* dir inode-ops */
 static int coda_create(struct inode *dir, struct dentry *new, int mode);
 static int coda_mknod(struct inode *dir, struct dentry *new, int mode, int rdev);
-static int coda_lookup(struct inode *dir, struct dentry *target);
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *target);
 static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, 
                     struct dentry *entry);
 static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
@@ -107,7 +107,7 @@ struct file_operations coda_dir_operations = {
 
 /* inode operations for directories */
 /* acces routines: lookup, readlink, permission */
-static int coda_lookup(struct inode *dir, struct dentry *entry)
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
 {
         struct coda_inode_info *dircnp;
        struct inode *res_inode = NULL;
@@ -125,16 +125,9 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
        if ( length > CODA_MAXNAMLEN ) {
                printk("name too long: lookup, %s (%*s)\n", 
                       coda_f2s(&dircnp->c_fid), length, name);
-               return -ENAMETOOLONG;
+               return ERR_PTR(-ENAMETOOLONG);
        }
 
-
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk("coda_lookup: inode is NULL or not a directory\n");
-               return -ENOTDIR;
-       }
-
-
         CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", 
               name, length, dir->i_ino, coda_f2s(&dircnp->c_fid));
 
@@ -160,11 +153,11 @@ static int coda_lookup(struct inode *dir, struct dentry *entry)
                }
                error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
                if (error)
-                       return error;
+                       return ERR_PTR(error);
        } else if (error != -ENOENT) {
                CDEBUG(D_INODE, "error for %s(%*s)%d\n",
                       coda_f2s(&dircnp->c_fid), length, name, error);
-               return error;
+               return ERR_PTR(error);
        }
        CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
               name, coda_f2s(&resfid), type, error, dropme);
@@ -178,7 +171,7 @@ exit:
                ITOC(res_inode)->c_flags |= C_VATTR;
        }
         EXIT;
-        return 0;
+        return NULL;
 }
 
 
@@ -236,11 +229,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode)
 
        CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode);
 
-        if (!dir || !S_ISDIR(dir->i_mode)) {
-                printk("coda_create: inode is null or not a directory\n");
-                return -ENOENT;
-        }
-
        if (coda_isroot(dir) && coda_iscontrol(name, length))
                return -EPERM;
 
@@ -286,11 +274,6 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev)
 
        CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",name, length, mode, rdev);
 
-        if (!dir || !S_ISDIR(dir->i_mode)) {
-                printk("coda_mknod: inode is null or not a directory\n");
-                return -ENOENT;
-        }
-
        if (coda_isroot(dir) && coda_iscontrol(name, length))
                return -EPERM;
 
@@ -332,11 +315,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode)
        ENTRY;
        coda_vfs_stat.mkdir++;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk("coda_mkdir: inode is NULL or not a directory\n");
-               return -ENOENT;
-       }
-
        if (coda_isroot(dir) && coda_iscontrol(name, len))
                return -EPERM;
 
@@ -490,10 +468,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
        ENTRY;
        coda_vfs_stat.rmdir++;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk("coda_rmdir: inode is NULL or not a directory\n");
-               return -ENOENT;
-       }
         dircnp = ITOC(dir);
 
        if (!list_empty(&de->d_hash))
@@ -572,11 +546,6 @@ int coda_readdir(struct file *file, void *dirent,  filldir_t filldir)
         ENTRY;
        coda_vfs_stat.readdir++;
 
-        if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
-                printk("coda_readdir: inode is NULL or not a directory\n");
-                return -EBADF;
-        }
-
         cnp = ITOC(inode);
         if ( !cnp->c_ovp ) {
                 CDEBUG(D_FILE, "open inode pointer = NULL.\n");
index 279f3d5dd52ccdb5c23ca7c7584a778cd55ae609..aa299f61ed11bacc4b88872a14719b051c0083c1 100644 (file)
@@ -471,8 +471,12 @@ void shrink_dcache_parent(struct dentry * parent)
  */
 void shrink_dcache_memory(int priority, unsigned int gfp_mask)
 {
-       if (gfp_mask & __GFP_IO)
-               prune_dcache(0);
+       if (gfp_mask & __GFP_IO) {
+               int count = 0;
+               if (priority)
+                       count = dentry_stat.nr_unused / priority;
+               prune_dcache(count);
+       }
 }
 
 #define NAME_ALLOC_LEN(len)    ((len+16) & ~15)
index f517367b950fc1c27984908ba8dfe0ea4e5efb6f..84388c763722b69dd1e5e6ca74049d9fe221d22a 100644 (file)
@@ -17,7 +17,7 @@
 #include "devpts_i.h"
 
 static int devpts_root_readdir(struct file *,void *,filldir_t);
-static int devpts_root_lookup(struct inode *,struct dentry *);
+static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
 static int devpts_revalidate(struct dentry *);
 
 static struct file_operations devpts_root_operations = {
@@ -81,9 +81,6 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi
        off_t nr;
        char numbuf[16];
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -ENOTDIR;
-
        nr = filp->f_pos;
 
        switch(nr)
@@ -131,42 +128,39 @@ static int devpts_revalidate(struct dentry * dentry)
        return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode );
 }
 
-static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * dentry)
 {
        struct devpts_sb_info *sbi = SBI(dir->i_sb);
        unsigned int entry;
        int i;
        const char *p;
 
-       if (!S_ISDIR(dir->i_mode))
-               return -ENOTDIR;
-
        dentry->d_inode = NULL; /* Assume failure */
        dentry->d_op    = &devpts_dentry_operations;
 
        if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
                entry = 0;
        } else if ( dentry->d_name.len < 1 ) {
-               return 0;
+               return NULL;
        } else {
                p = dentry->d_name.name;
                if ( *p < '1' || *p > '9' )
-                       return 0;
+                       return NULL;
                entry = *p++ - '0';
 
                for ( i = dentry->d_name.len-1 ; i ; i-- ) {
                        unsigned int nentry = *p++ - '0';
                        if ( nentry > 9 )
-                               return 0;
+                               return NULL;
                        nentry += entry * 10;
                        if (nentry < entry)
-                               return 0;
+                               return NULL;
                        entry = nentry;
                }
        }
 
        if ( entry >= sbi->max_ptys )
-               return 0;
+               return NULL;
 
        dentry->d_inode = sbi->inodes[entry];
        if ( dentry->d_inode )
@@ -174,5 +168,5 @@ static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
        
        d_add(dentry, dentry->d_inode);
 
-       return 0;
+       return NULL;
 }
index 22af5533424490ec1c1e2ae006639b69830197b0..a6753d27682f04890d295c05839199e691a2069c 100644 (file)
@@ -115,8 +115,6 @@ static int ext2_readdir(struct file * filp,
        int err;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
        sb = inode->i_sb;
 
        stored = 0;
index 674d8b6d62fa3ed59ed44bc84fe2195f87d8225c..762ef1df749d067f4836e41a4aa6904ed9b67663 100644 (file)
@@ -168,14 +168,14 @@ failure:
        return NULL;
 }
 
-int ext2_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
 {
        struct inode * inode;
        struct ext2_dir_entry_2 * de;
        struct buffer_head * bh;
 
        if (dentry->d_name.len > EXT2_NAME_LEN)
-               return -ENAMETOOLONG;
+               return ERR_PTR(-ENAMETOOLONG);
 
        bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
        inode = NULL;
@@ -185,10 +185,10 @@ int ext2_lookup(struct inode * dir, struct dentry *dentry)
                inode = iget(dir->i_sb, ino);
 
                if (!inode)
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
index 1c44247a00a5e0227b831614d13b6f404f6af076..b6d6fb4052c3a0150b10876ec14ad70b665021c1 100644 (file)
@@ -9,6 +9,7 @@
  *
  *  VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
  *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
+ *  Plugged buffer overrun in readdir(). AV
  */
 
 #define ASC_LINUX_VERSION(V, P, S)     (((V) * 65536) + ((P) * 256) + (S))
@@ -59,6 +60,7 @@ struct file_operations fat_dir_operations = {
  * characters are a sort of uuencoded 16 bit Unicode value.  This lets
  * us do a full dump and restore of Unicode filenames.  We could get
  * into some trouble with long Unicode names, but ignore that right now.
+ * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
  */
 static int
 uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
@@ -93,6 +95,11 @@ uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
                                *op++ = '?';
                        }
                }
+               /* We have some slack there, so it's OK */
+               if (op>ascii+256) {
+                       op = ascii + 256;
+                       break;
+               }
        }
        *op = 0;
        return (op - ascii);
@@ -138,8 +145,6 @@ int fat_readdirx(
        unsigned char *unicode = NULL;
        struct nls_table *nls = MSDOS_SB(sb)->nls_io;
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
 /* Fake . and .. for the root directory. */
        if (inode->i_ino == MSDOS_ROOT_INO) {
                while (oldpos < 2) {
@@ -186,9 +191,17 @@ int fat_readdirx(
                        id = ds->id;
                        if (id & 0x40) {
                                slots = id & ~0x40;
-                               long_slots = slots;
-                               is_long = 1;
-                               alias_checksum = ds->alias_checksum;
+                               /*
+                                * Dirty, but not dirtier than the original,
+                                * and plugs the hole.
+                                */
+                               if (slots > 20)
+                                       slots = 0;
+                               else {
+                                       long_slots = slots;
+                                       is_long = 1;
+                                       alias_checksum = ds->alias_checksum;
+                               }
                        }
 
                        get_new_entry = 1;
index 39067dd1c8487de11afdb94e5090ec6badf5f27c..339bcb6f601467d7487469089b8f7ee659ba9e18 100644 (file)
@@ -332,7 +332,6 @@ fat_read_super(struct super_block *sb, void *data, int silent)
                fat_brelse (sb, bh);
                goto out_no_bread;
        }
-       set_blocksize(sb->s_dev, blksize);
 
 /*
  * The DOS3 partition size limit is *not* 32M as many people think.  
@@ -423,6 +422,7 @@ fat_read_super(struct super_block *sb, void *data, int silent)
                    || !b->secs_track || !b->heads;
        }
        fat_brelse(sb, bh);
+       set_blocksize(sb->s_dev, blksize);
        /*
                This must be done after the brelse because the bh is a dummy
                allocated by fat_bread (see buffer.c)
index 03fa7f7ae20223a9188bf68c532a16be6b54e3b0..0ab81d9663322750ffac2caae4b19f119b42d663 100644 (file)
@@ -27,7 +27,7 @@
 
 /*================ Forward declarations ================*/
 
-static int cap_lookup(struct inode *, struct dentry *);
+static struct dentry *cap_lookup(struct inode *, struct dentry *);
 static int cap_readdir(struct file *, void *, filldir_t);
 
 /*================ Global variables ================*/
@@ -147,7 +147,7 @@ struct inode_operations hfs_cap_rdir_inode_operations = {
  * inode corresponding to an entry in a directory, given the inode for
  * the directory and the name (and its length) of the entry.
  */
-static int cap_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry)
 {
        ino_t dtype;
        struct hfs_name cname;
@@ -155,10 +155,6 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
        struct hfs_cat_key key;
        struct inode *inode = NULL;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               return -ENOENT;
-       }
-
        dentry->d_op = &hfs_dentry_operations;
        entry = HFS_I(dir)->entry;
        dtype = HFS_ITYPE(dir->i_ino);
@@ -207,7 +203,7 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry)
 
 done:
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
index 4e4e6fcc3d2e8e71c9fb6f18382bb01ed55b38e8..80e9906273511f09cc3474131e4609a7b526811d 100644 (file)
@@ -23,7 +23,7 @@
 
 /*================ Forward declarations ================*/
 
-static int dbl_lookup(struct inode *, struct dentry *);
+static struct dentry *dbl_lookup(struct inode *, struct dentry *);
 static int dbl_readdir(struct file *, void *, filldir_t);
 static int dbl_create(struct inode *, struct dentry *, int);
 static int dbl_mkdir(struct inode *, struct dentry *, int);
@@ -130,17 +130,13 @@ static int is_hdr(struct inode *dir, const char *name, int len)
  * the inode for the directory and the name (and its length) of the
  * entry.
  */
-static int dbl_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry)
 {
        struct hfs_name cname;
        struct hfs_cat_entry *entry;
        struct hfs_cat_key key;
        struct inode *inode = NULL;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               return -ENOENT;
-       }
-
        dentry->d_op = &hfs_dentry_operations;
        entry = HFS_I(dir)->entry;
        
@@ -173,7 +169,7 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry)
        
 done:
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
index a4078e891ab74107605df18bdd27f16f516eeef4..5cff9d8142631e7b407155bd44ec1cf7a72e7eb0 100644 (file)
@@ -29,7 +29,7 @@
 
 /*================ Forward declarations ================*/
 
-static int nat_lookup(struct inode *, struct dentry *);
+static struct dentry *nat_lookup(struct inode *, struct dentry *);
 static int nat_readdir(struct file *, void *, filldir_t);
 static int nat_rmdir(struct inode *, struct dentry *);
 static int nat_hdr_unlink(struct inode *, struct dentry *);
@@ -136,7 +136,7 @@ struct inode_operations hfs_nat_hdir_inode_operations = {
  * the inode corresponding to an entry in a directory, given the inode
  * for the directory and the name (and its length) of the entry.
  */
-static int nat_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry)
 {
        ino_t dtype;
        struct hfs_name cname;
@@ -144,10 +144,6 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
        struct hfs_cat_key key;
        struct inode *inode = NULL;
 
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               return -ENOENT;
-       }
-
        dentry->d_op = &hfs_dentry_operations;
        entry = HFS_I(dir)->entry;
        dtype = HFS_ITYPE(dir->i_ino);
@@ -199,7 +195,7 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry)
 
 done:
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
index feafa2861cadcf60448363277efbdfb6291bb9c6..cb1d0215be8a10732e5d04dd75cbe04b9b650e9f 100644 (file)
@@ -192,7 +192,7 @@ static ssize_t hpfs_dir_read(struct file *filp, char *buf,
                             size_t count, loff_t *ppos);
 static int hpfs_readdir(struct file *filp,
                        void *dirent, filldir_t filldir);
-static int hpfs_lookup(struct inode *, struct dentry *);
+static struct dentry *hpfs_lookup(struct inode *, struct dentry *);
 
 static const struct file_operations hpfs_dir_ops =
 {
@@ -1119,7 +1119,7 @@ static secno bplus_lookup(struct inode *inode, struct bplus_header *b,
  * the boondocks.)
  */
 
-static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
 {
        const char *name = dentry->d_name.name;
        int len = dentry->d_name.len;
@@ -1129,14 +1129,6 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
        int retval;
        struct quad_buffer_head qbh;
 
-       /* In case of madness */
-
-       retval = -ENOTDIR;
-       if (dir == 0)
-               goto out;
-       if (!S_ISDIR(dir->i_mode))
-               goto out;
-
        /*
         * Read in the directory entry. "." is there under the name ^A^A .
         * Always read the dir even for . and .. in case we need the dates.
@@ -1208,7 +1200,7 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
        brelse4(&qbh);
 
       out:
-       return retval;
+       return ERR_PTR(retval);
 }
 
 /*
@@ -1374,11 +1366,6 @@ static int hpfs_readdir(struct file *filp, void * dirent,
        long old_pos;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       if (inode == 0
-           || inode->i_sb == 0
-           || !S_ISDIR(inode->i_mode))
-               return -EBADF;
-
        tempname = (char *) __get_free_page(GFP_KERNEL);
        if (!tempname)
                return -ENOMEM;
index 3eab050e6c9058eb72be31b33034e2e10cc9d994..930e18826b12d35d77f9deff89c45f57a2b293ba 100644 (file)
@@ -359,10 +359,8 @@ static int free_inodes(void)
                found = 1;
        }
 
-       if (found) {
+       if (found)
                dispose_list(freeable);
-               found = 1;      /* silly compiler */
-       }
 
        return found;
 }
@@ -750,7 +748,7 @@ int bmap(struct inode * inode, int block)
  * Initialize the hash tables and default
  * value for max inodes
  */
-#define MAX_INODE (12288)
+#define MAX_INODE (16384)
 
 void __init inode_init(void)
 {
index a57f9680c63752daa7ccd7fac7c7b2a6d4b0d2b2..23ca159c75a293d5511afcd024b8b1e1c2ddbb27 100644 (file)
@@ -295,9 +295,6 @@ static int isofs_readdir(struct file *filp,
        struct iso_directory_record * tmpde;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
-
        tmpname = (char *) __get_free_page(GFP_KERNEL);
        if (!tmpname)
                return -ENOMEM;
index 364698dc28de7fadd2ac4c7702956038a1ee34ad..e265a7304784f009ae3d27b9ec451a766ea282a8 100644 (file)
@@ -228,7 +228,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
        return retval;
 }
 
-int isofs_lookup(struct inode * dir, struct dentry * dentry)
+struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry)
 {
        unsigned long ino;
        struct buffer_head * bh;
@@ -237,12 +237,6 @@ int isofs_lookup(struct inode * dir, struct dentry * dentry)
 #ifdef DEBUG
        printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
 #endif
-       if (!dir)
-               return -ENOENT;
-
-       if (!S_ISDIR(dir->i_mode))
-               return -ENOENT;
-
        dentry->d_op = dir->i_sb->s_root->d_op;
 
        bh = isofs_find_entry(dir, dentry, &ino);
@@ -253,8 +247,8 @@ int isofs_lookup(struct inode * dir, struct dentry * dentry)
 
                inode = iget(dir->i_sb,ino);
                if (!inode)
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
index d7db754ffdfc5057ca7eb3c3e0e8ef6e85952a9e..187925903b5ae8cd076776bfd213c46f5dbaf76b 100644 (file)
@@ -68,8 +68,6 @@ static int minix_readdir(struct file * filp,
        struct minix_sb_info * info;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
-               return -EBADF;
        info = &inode->i_sb->u.minix_sb;
        if (filp->f_pos & (info->s_dirsize - 1))
                return -EBADF;
index 382a869b1cf56ddb969df0d3c242780658f62668..60032292c3cb076aeb72d8e5fe45aadc830ca0bd 100644 (file)
@@ -38,14 +38,13 @@ static void minix_delete_inode(struct inode *inode)
        minix_free_inode(inode);
 }
 
-static void minix_commit_super (struct super_block * sb,
-                              struct minix_super_block * ms)
+static void minix_commit_super(struct super_block * sb)
 {
        mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
        sb->s_dirt = 0;
 }
 
-static void minix_write_super (struct super_block * sb)
+static void minix_write_super(struct super_block * sb)
 {
        struct minix_super_block * ms;
 
@@ -54,7 +53,7 @@ static void minix_write_super (struct super_block * sb)
 
                if (ms->s_state & MINIX_VALID_FS)
                        ms->s_state &= ~MINIX_VALID_FS;
-               minix_commit_super (sb, ms);
+               minix_commit_super(sb);
        }
        sb->s_dirt = 0;
 }
@@ -106,7 +105,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
                ms->s_state = sb->u.minix_sb.s_mount_state;
                mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
                sb->s_dirt = 1;
-               minix_commit_super (sb, ms);
+               minix_commit_super(sb);
        }
        else {
                /* Mount a partition which is read-only, read-write. */
index 3bf0f22dc48c875ac10026d9d67107fcf234d105..e26967d615c5c5e8d465a4d538abf56c35768700 100644 (file)
@@ -116,7 +116,7 @@ struct dentry_operations minix_dentry_operations = {
        0               /* compare */
 };
 
-int minix_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
 {
        struct inode * inode = NULL;
        struct minix_dir_entry * de;
@@ -132,10 +132,10 @@ int minix_lookup(struct inode * dir, struct dentry *dentry)
                inode = iget(dir->i_sb, ino);
  
                if (!inode)
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
@@ -221,8 +221,6 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode)
        struct buffer_head * bh;
        struct minix_dir_entry * de;
 
-       if (!dir)
-               return -ENOENT;
        inode = minix_new_inode(dir);
        if (!inode)
                return -ENOSPC;
@@ -251,8 +249,6 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev)
        struct buffer_head * bh;
        struct minix_dir_entry * de;
 
-       if (!dir)
-               return -ENOENT;
        bh = minix_find_entry(dir, dentry->d_name.name,
                              dentry->d_name.len, &de);
        if (bh) {
@@ -298,8 +294,6 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode)
        struct minix_dir_entry * de;
        struct minix_sb_info * info;
 
-       if (!dir || !dir->i_sb)
-               return -EINVAL;
        info = &dir->i_sb->u.minix_sb;
        bh = minix_find_entry(dir, dentry->d_name.name,
                              dentry->d_name.len, &de);
index a364faf2117fdfa87c44f4de8b391f5797db3fc8..dc9faa9a15a9ed69a401c9f2cc6863d361a97337 100644 (file)
@@ -250,7 +250,7 @@ out_fail:
 
 
 /***** Get inode using directory and name */
-int msdos_lookup(struct inode *dir,struct dentry *dentry)
+struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode = NULL;
@@ -292,7 +292,7 @@ add:
        d_add(dentry, inode);
        res = 0;
 out:
-       return res;
+       return ERR_PTR(res);
 }
 
 
index 21de93da4ad85d03e112a98605e8c02c6863b183..512fc9be5c0868386afb3213597b1fff42842c5c 100644 (file)
@@ -263,12 +263,11 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name)
                struct dentry * dentry = d_alloc(parent, name);
                result = ERR_PTR(-ENOMEM);
                if (dentry) {
-                       int error = dir->i_op->lookup(dir, dentry);
-                       result = dentry;
-                       if (error) {
+                       result = dir->i_op->lookup(dir, dentry);
+                       if (result)
                                dput(dentry);
-                               result = ERR_PTR(error);
-                       }
+                       else
+                               result = dentry;
                }
        }
        up(&dir->i_sem);
index 7a284742e3f132b25340ffc785e952a53ed1ff72..5648f6725553e9e0f2b5e1c08d5bd433ee982c27 100644 (file)
@@ -50,7 +50,7 @@ static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *);
 static int ncp_readdir(struct file *, void *, filldir_t);
 
 static int ncp_create(struct inode *, struct dentry *, int);
-static int ncp_lookup(struct inode *, struct dentry *);
+static struct dentry *ncp_lookup(struct inode *, struct dentry *);
 static int ncp_unlink(struct inode *, struct dentry *);
 static int ncp_mkdir(struct inode *, struct dentry *, int);
 static int ncp_rmdir(struct inode *, struct dentry *);
@@ -440,11 +440,6 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir)
        DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
                 inode->i_ino, c_ino);
 
-       result = -EBADF;
-       if (!inode || !S_ISDIR(inode->i_mode)) {
-               printk(KERN_WARNING "ncp_readdir: inode is NULL or not a directory\n");
-               goto out;
-       }
        result = -EIO;
        if (!ncp_conn_valid(server))
                goto out;
@@ -744,7 +739,7 @@ out:
        return result;
 }
 
-static int ncp_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
 {
        struct ncp_server *server;
        struct inode *inode = NULL;
@@ -754,11 +749,6 @@ static int ncp_lookup(struct inode *dir, struct dentry *dentry)
        struct ncpfs_inode_info finfo;
        __u8 __name[dentry->d_name.len + 1];
 
-       error =  -ENOENT;
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk(KERN_WARNING "ncp_lookup: inode is NULL or not a directory.\n");
-               goto finished;
-       }
        server = NCP_SERVER(dir);
 
        error = -EIO;
@@ -831,7 +821,7 @@ dentry->d_parent->d_name.name, __name, res);
                if (res != 0) {
                        goto add_entry;
                } else vol2io(server, finfo.nw_info.i.entryName,
-                             ncp_preserve_entry_case(dir,
+                             !ncp_preserve_entry_case(dir,
                              finfo.nw_info.i.NSCreator));
        }
 
@@ -854,7 +844,7 @@ finished:
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
 #endif
-       return error;
+       return ERR_PTR(error);
 }
 
 /*
@@ -897,10 +887,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode,
 printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 #endif
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk(KERN_WARNING "ncp_create_new: inode is NULL or not a directory\n");
-               return -ENOENT;
-       }
        error = -EIO;
        if (!ncp_conn_valid(NCP_SERVER(dir)))
                goto out;
@@ -940,11 +926,6 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 
        DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
-       error = -ENOTDIR;
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk(KERN_WARNING "ncp_mkdir: inode is NULL or not a directory\n");
-               goto out;
-       }
        error = -EIO;
        if (!ncp_conn_valid(NCP_SERVER(dir)))
                goto out;
@@ -971,13 +952,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
 
        DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
-       
-       error = -ENOENT;
-       if (!dir || !S_ISDIR(dir->i_mode))
-       {
-               printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n");
-               goto out;
-       }
 
        error = -EIO;
        if (!ncp_conn_valid(NCP_SERVER(dir)))
@@ -1030,11 +1004,6 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
        DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
        
-       error = -ENOTDIR;
-       if (!dir || !S_ISDIR(dir->i_mode)) {
-               printk(KERN_WARNING "ncp_unlink: inode is NULL or not a directory\n");
-               goto out;
-       }
        error = -EIO;
        if (!ncp_conn_valid(NCP_SERVER(dir)))
                goto out;
@@ -1102,15 +1071,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
 
-       error = -ENOTDIR;
-       if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
-               printk(KERN_WARNING "ncp_rename: old inode is NULL or not a directory\n");
-               goto out;
-       }
-       if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
-               printk(KERN_WARNING "ncp_rename: new inode is NULL or not a directory\n");
-               goto out;
-       }
        error = -EIO;
        if (!ncp_conn_valid(NCP_SERVER(old_dir)))
                goto out;
index 5f06f787d1600ac307238cdd0e0a5217327cf359..4bc541f9a9a0f1d30cbfc06c48f679b8ddcf1a29 100644 (file)
@@ -51,10 +51,9 @@ struct nfs_dirent {
 
 static int nfs_safe_remove(struct dentry *);
 
-static int nfs_dir_open(struct inode *, struct file *);
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
 static int nfs_readdir(struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, struct dentry *);
+static struct dentry *nfs_lookup(struct inode *, struct dentry *);
 static int nfs_create(struct inode *, struct dentry *, int);
 static int nfs_mkdir(struct inode *, struct dentry *, int);
 static int nfs_rmdir(struct inode *, struct dentry *);
@@ -73,7 +72,7 @@ static struct file_operations nfs_dir_operations = {
        NULL,                   /* select - default */
        NULL,                   /* ioctl - default */
        NULL,                   /* mmap */
-       nfs_dir_open,           /* open - revalidate */
+       NULL,                   /* no special open is needed */
        NULL,                   /* flush */
        NULL,                   /* no special release code */
        NULL                    /* fsync */
@@ -102,16 +101,6 @@ struct inode_operations nfs_dir_inode_operations = {
        nfs_revalidate,         /* revalidate */
 };
 
-static int
-nfs_dir_open(struct inode *dir, struct file *file)
-{
-       struct dentry *dentry = file->f_dentry;
-
-       dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n",
-               dentry->d_parent->d_name.name, dentry->d_name.name);
-       return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-}
-
 static ssize_t
 nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
 {
@@ -147,11 +136,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 
        dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n",
                dentry->d_parent->d_name.name, dentry->d_name.name);
-       result = -EBADF;
-       if (!inode || !S_ISDIR(inode->i_mode)) {
-               printk("nfs_readdir: inode is NULL or not a directory\n");
-               goto out;
-       }
 
        result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
        if (result < 0)
@@ -397,7 +381,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
 {
        struct dentry * parent = dentry->d_parent;
        struct inode * inode = dentry->d_inode;
-       unsigned long time = jiffies - dentry->d_time;
        int error;
        struct nfs_fh fhandle;
        struct nfs_fattr fattr;
@@ -406,31 +389,36 @@ static int nfs_lookup_revalidate(struct dentry * dentry)
         * If we don't have an inode, let's just assume
         * a 5-second "live" time for negative dentries.
         */
-       if (!inode) {
-               if (time < NFS_REVALIDATE_INTERVAL)
-                       goto out_valid;
-               goto out_bad;
-       }
+       if (!inode)
+               goto do_lookup;
 
        if (is_bad_inode(inode)) {
-#ifdef NFS_PARANOIA
-printk("nfs_lookup_validate: %s/%s has dud inode\n",
-parent->d_name.name, dentry->d_name.name);
-#endif
+               dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
+                       parent->d_name.name, dentry->d_name.name);
                goto out_bad;
        }
 
-       if (time < NFS_ATTRTIMEO(inode))
+       if (_nfs_revalidate_inode(NFS_DSERVER(dentry), dentry))
+               goto out_bad;
+
+       if (time_before(jiffies,dentry->d_time+NFS_ATTRTIMEO(inode)))
                goto out_valid;
 
        if (IS_ROOT(dentry))
                goto out_valid;
 
+do_lookup:
        /*
         * Do a new lookup and check the dentry attributes.
         */
        error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), 
                                dentry->d_name.name, &fhandle, &fattr);
+       if (dentry->d_inode == NULL) {
+               if (error == -ENOENT &&
+                   time_before(jiffies,dentry->d_time+NFS_REVALIDATE_INTERVAL))
+                       goto out_valid;
+               goto out_bad;
+       }
        if (error)
                goto out_bad;
 
@@ -440,7 +428,7 @@ parent->d_name.name, dentry->d_name.name);
 
        /* Filehandle matches? */
        if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
-               if (dentry->d_count < 2 || nfs_revalidate(dentry))
+               if (dentry->d_count < 2)
                        goto out_bad;
        }
 
@@ -451,6 +439,10 @@ parent->d_name.name, dentry->d_name.name);
 out_valid:
        return 1;
 out_bad:
+       if (dentry->d_parent->d_inode)
+               nfs_invalidate_dircache(dentry->d_parent->d_inode);
+       if (inode && S_ISDIR(inode->i_mode))
+               nfs_invalidate_dircache(inode);
        return 0;
 }
 
@@ -535,7 +527,7 @@ static void show_dentry(struct list_head * dlist)
 }
 #endif
 
-static int nfs_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
        struct inode *inode;
        int error;
@@ -581,7 +573,7 @@ show_dentry(&inode->i_dentry);
                }
        }
 out:
-       return error;
+       return ERR_PTR(error);
 }
 
 /*
@@ -766,7 +758,7 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
 {
        struct qstr    sqstr;
        struct dentry *sdentry;
-       int error;
+       struct dentry *res;
 
        sqstr.name = silly;
        sqstr.len  = slen;
@@ -776,10 +768,10 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen)
                sdentry = d_alloc(parent, &sqstr);
                if (sdentry == NULL)
                        return ERR_PTR(-ENOMEM);
-               error = nfs_lookup(parent->d_inode, sdentry);
-               if (error) {
+               res = nfs_lookup(parent->d_inode, sdentry);
+               if (res) {
                        dput(sdentry);
-                       return ERR_PTR(error);
+                       return res;
                }
        }
        return sdentry;
index 5d3262271e1e5add323ed9b70936ac852f4c515e..c5dc24b834132e5d9013e6817fe34c08c870c82c 100644 (file)
@@ -37,7 +37,6 @@ static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *);
 static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
 static int  nfs_file_flush(struct file *);
 static int  nfs_fsync(struct file *, struct dentry *dentry);
-static int  nfs_file_open(struct inode *inode, struct file *filp);
 
 static struct file_operations nfs_file_operations = {
        NULL,                   /* lseek - default */
@@ -47,7 +46,7 @@ static struct file_operations nfs_file_operations = {
        NULL,                   /* select - default */
        NULL,                   /* ioctl - default */
        nfs_file_mmap,          /* mmap */
-       nfs_file_open,          /* open */
+       NULL,                   /* no special open is needed */
        nfs_file_flush,         /* flush */
        NULL,                   /* release */
        nfs_fsync,              /* fsync */
@@ -105,19 +104,6 @@ nfs_file_flush(struct file *file)
        return status;
 }
 
-/*
- * Open the file.
- * Just checks the cache is synchronized.
- */
-static int
-nfs_file_open(struct inode *inode, struct file *filp)
-{
-       struct dentry *dentry = filp->f_dentry;
-
-       return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-}
-
-
 static ssize_t
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
index 0b832e1a56ed9cc7fc841a1685f6f54a1856e5d2..5efe7d898844d349340928d386a5ba2e6e2067d7 100644 (file)
@@ -37,6 +37,8 @@
 #define NFS_PARANOIA 1
 
 static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static void nfs_zap_caches(struct inode *);
+static void nfs_invalidate_inode(struct inode *);
 
 static void nfs_read_inode(struct inode *);
 static void nfs_put_inode(struct inode *);
@@ -393,25 +395,61 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
  * could cause file corruption. But since the dentry
  * count is 0 and all pending IO for a dentry has been
  * flushed when the count went to 0, we're safe here.
+ * Also returns the number of unhashed dentries
  */
-void nfs_free_dentries(struct inode *inode)
+static int
+nfs_free_dentries(struct inode *inode)
 {
        struct list_head *tmp, *head = &inode->i_dentry;
+       int unhashed;
 
 restart:
        tmp = head;
+       unhashed = 0;
        while ((tmp = tmp->next) != head) {
                struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-printk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-dentry->d_count, !list_empty(&dentry->d_hash));
+               dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
+                       dentry->d_parent->d_name.name, dentry->d_name.name,
+                       dentry->d_count, !list_empty(&dentry->d_hash));
                if (!dentry->d_count) {
                        dget(dentry);
                        d_drop(dentry);
                        dput(dentry);
                        goto restart;
                }
+               if (!list_empty(&dentry->d_hash))
+                       unhashed++;
        }
+       return unhashed;
+}
+
+/*
+ * Invalidate the local caches
+ */
+static void
+nfs_zap_caches(struct inode *inode)
+{
+       NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+       NFS_CACHEINV(inode);
+
+       if (S_ISDIR(inode->i_mode))
+               nfs_invalidate_dircache(inode);
+       else
+               invalidate_inode_pages(inode);
+}
+
+/*
+ * Invalidate, but do not unhash, the inode
+ */
+static void
+nfs_invalidate_inode(struct inode *inode)
+{
+       umode_t save_mode = inode->i_mode;
+
+       make_bad_inode(inode);
+       inode->i_mode = save_mode;
+       nfs_inval(inode);
+       nfs_zap_caches(inode);
 }
 
 /*
@@ -513,7 +551,7 @@ static struct inode *
 __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
 {
        struct inode *inode;
-       int max_count;
+       int max_count, stale_inode, unhashed = 0;
 
 retry:
        inode = iget(sb, fattr->fileid);
@@ -532,27 +570,30 @@ retry:
         * as the inode may have become a different object.
         * (We can probably handle modes changes here, too.)
         */
+       stale_inode = inode->i_mode &&
+                     ((fattr->mode ^ inode->i_mode) & S_IFMT);
+       stale_inode |= inode->i_count && inode->i_count == unhashed;
        max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
-       if (inode->i_count > max_count) {
-printk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
-inode->i_ino, inode->i_count, inode->i_nlink);
-               nfs_free_dentries(inode);
-               if (inode->i_count > max_count) {
-printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-inode->i_ino, inode->i_count);
+       if (stale_inode || inode->i_count > max_count + unhashed) {
+               dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
+                       inode->i_ino, inode->i_count, inode->i_nlink);
+               unhashed = nfs_free_dentries(inode);
+               if (stale_inode || inode->i_count > max_count + unhashed) {
+                       printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+                               inode->i_ino, inode->i_count);
                        if (!list_empty(&inode->i_dentry)) {
                                struct dentry *dentry;
                                dentry = list_entry(inode->i_dentry.next,
                                                 struct dentry, d_alias);
-printk("__nfs_fhget: killing %s/%s filehandle\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-                               memset(dentry->d_fsdata, 0, 
+                               printk("__nfs_fhget: killing %s/%s filehandle\n",
+                                       dentry->d_parent->d_name.name,
+                                       dentry->d_name.name);
+                               memset(dentry->d_fsdata, 0,
                                        sizeof(struct nfs_fh));
-                       } else
-                               printk("NFS: inode %ld busy, no aliases?\n",
-                                       inode->i_ino);
-                       make_bad_inode(inode);
+                       }
                        remove_inode_hash(inode);
+                       nfs_invalidate_inode(inode);
+                       unhashed = 0;
                }
                iput(inode);
                goto retry;
@@ -673,10 +714,9 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
                int error;
                u32 *fh;
                struct nfs_fh fhandle;
-#ifdef NFS_PARANOIA
-printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
-#endif
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
+                       dentry->d_parent->d_name.name,
+                       dentry->d_name.name, inode->i_ino, status);
                if (status != -ESTALE)
                        goto out;
                /*
@@ -684,26 +724,25 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
                 * and find out what the filehandle should be.
                 */
                fh = (u32 *) NFS_FH(dentry);
-               printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
+               dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
                        fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
                error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), 
                                        dentry->d_name.name, &fhandle, &fattr);
                if (error) {
-                       printk("NFS: lookup failed, error=%d\n", error);
+                       dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
                        goto out;
                }
                fh = (u32 *) &fhandle;
-               printk("            %08x%08x%08x%08x%08x%08x%08x%08x\n",
+               dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
                        fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
                goto out;
        }
 
        status = nfs_refresh_inode(inode, &fattr);
        if (status) {
-#ifdef NFS_PARANOIA
-printk("nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
-#endif
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
+                       dentry->d_parent->d_name.name,
+                       dentry->d_name.name, inode->i_ino, status);
                goto out;
        }
        dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
@@ -809,29 +848,18 @@ out_changed:
 printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
 inode->i_ino, inode->i_mode, fattr->mode);
 #endif
-       fattr->mode = inode->i_mode; /* save mode */
-       make_bad_inode(inode);
-       nfs_inval(inode);
-       inode->i_mode = fattr->mode; /* restore mode */
        /*
         * No need to worry about unhashing the dentry, as the
         * lookup validation will know that the inode is bad.
-        * (But we fall through to invalidate the caches.)
         */
+       nfs_invalidate_inode(inode);
+       goto out;
 
 out_invalid:
-       /*
-        * Invalidate the local caches
-        */
 #ifdef NFS_DEBUG_VERBOSE
 printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
 #endif
-       if (!S_ISDIR(inode->i_mode))
-               invalidate_inode_pages(inode);
-       else
-               nfs_invalidate_dircache(inode);
-       NFS_CACHEINV(inode);
-       NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+       nfs_zap_caches(inode);
        goto out;
 }
 
index c38214bae7302e4392d29a7f08a267a8e2c87ba8..f34de38d30ade2f58e9b9b64ea7f8b5f62518254 100644 (file)
@@ -215,7 +215,6 @@ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir)
 
        ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n",
               (unsigned)dir->i_ino,(unsigned int)dir->i_mode);
-       if(!dir || (dir->i_ino==0) || !S_ISDIR(dir->i_mode))return -EBADF;
 
        ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n",
               (unsigned)filp->f_pos,dir->i_count);
@@ -373,7 +372,7 @@ static int parse_options(ntfs_volume* vol,char *opt)
        return 0;
 }
                        
-static int ntfs_lookup(struct inode *dir, struct dentry *d)
+static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
 {
        struct inode *res=0;
        char *item=0;
@@ -385,10 +384,10 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d)
        error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name,
                             d->d_name.len,&walk.name,&walk.namelen);
        if(error)
-               return error;
+               return ERR_PTR(-error);
        item=ntfs_malloc(ITEM_SIZE);
        if( !item )
-               return ENOMEM;
+               return ERR_PTR(-ENOMEM);
        /* ntfs_getdir will place the directory entry into item,
           and the first long long is the MFT record number */
        walk.type=BY_NAME;
@@ -402,7 +401,7 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d)
        ntfs_free(item);
        ntfs_free(walk.name);
        /* Always return success, the dcache will handle negative entries. */
-       return 0;
+       return NULL;
 }
 
 static struct file_operations ntfs_file_operations_nommap = {
@@ -829,7 +828,7 @@ static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize)
 
        error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks );
        if( error )
-               return error;
+               return -error;
        fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
        fs.f_bavail=fs.f_bfree;
 
index fd975ffbb30b847c5302f96a14d18aa84333f991..7fcc86754b11c44221a8130813622f2dc4ad0a77 100644 (file)
@@ -150,6 +150,8 @@ ntfs_extend_mft(ntfs_volume *vol)
        ntfs_insert_fixups(buf,vol->blocksize);
        io.param=buf;
        io.size=vol->mft_recordsize;
+       io.fn_put = ntfs_put;
+       io.fn_get = ntfs_get;
        error=ntfs_write_attr(vol->mft_ino,vol->at_data,0,
                              (rcount-1)*vol->mft_recordsize,&io);
        if(error)return error;
index 8db99f7f4d80edd28f41422bb4ee14d706ab4034..1defdbae1195e8522d54e57d4351e80782cbeb8a 100644 (file)
@@ -19,7 +19,7 @@
 #include <asm/uaccess.h>
 
 static int proc_readfd(struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *, struct dentry *);
+static struct dentry *proc_lookupfd(struct inode *, struct dentry *);
 
 static struct file_operations proc_fd_operations = {
        NULL,                   /* lseek - default */
@@ -67,7 +67,7 @@ struct inode_operations proc_fd_inode_operations = {
  *
  * Thus just return -ENOENT instead.
  */
-static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
 {
        unsigned int ino, pid, fd, c;
        struct task_struct * p;
@@ -77,13 +77,11 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
        int len, err;
 
        err = -ENOENT;
-       if (!dir)
-               goto out;
        ino = dir->i_ino;
        pid = ino >> 16;
        ino &= 0x0000ffff;
 
-       if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
+       if (!pid || ino != PROC_PID_FD)
                goto out;
 
        fd = 0;
@@ -121,10 +119,10 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
        if (inode) {
                dentry->d_op = &proc_dentry_operations;
                d_add(dentry, inode);
-               err = 0;
+               return NULL;
        }
 out:
-       return err;
+       return ERR_PTR(err);
 }
 
 #define NUMBUF 10
@@ -137,10 +135,6 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
        int retval;
        char buf[NUMBUF];
 
-       retval = -EBADF;
-       if (!inode || !S_ISDIR(inode->i_mode))
-               goto out;
-
        retval = 0;
        ino = inode->i_ino;
        pid = ino >> 16;
index 2c2c84784e4c013cd0187ce24da21d34303cfe8e..09844e156ba9ccadf734b11dc6c12c115fc6d7ef 100644 (file)
@@ -842,7 +842,6 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld
        struct openpromfs_dev *d;
        char buffer2[64];
        
-       if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR;
        ino = inode->i_ino;
        i = filp->f_pos;
        switch (i) {
index e28338ab4336054b45097272a0bb139dceb52d69..2c4fbe8dc77558f4c5784e972e2fd349a70b069b 100644 (file)
@@ -28,7 +28,7 @@
 #define FIRST_PROCESS_ENTRY 256
 
 static int proc_root_readdir(struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,struct dentry *);
+static struct dentry *proc_root_lookup(struct inode *,struct dentry *);
 static int proc_unlink(struct inode *, struct dentry *);
 
 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
@@ -769,16 +769,12 @@ struct dentry_operations proc_dentry_operations =
  * Don't create negative dentries here, return -ENOENT by hand
  * instead.
  */
-int proc_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
 {
        struct inode *inode;
        struct proc_dir_entry * de;
        int error;
 
-       error = -ENOTDIR;
-       if (!dir || !S_ISDIR(dir->i_mode))
-               goto out;
-
        error = -ENOENT;
        inode = NULL;
        de = (struct proc_dir_entry *) dir->u.generic_ip;
@@ -800,13 +796,12 @@ int proc_lookup(struct inode * dir, struct dentry *dentry)
        if (inode) {
                dentry->d_op = &proc_dentry_operations;
                d_add(dentry, inode);
-               error = 0;
+               return NULL;
        }
-out:
-       return error;
+       return ERR_PTR(error);
 }
 
-static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
 {
        unsigned int pid, c;
        struct task_struct *p;
@@ -826,7 +821,7 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
        }
 
        if (!proc_lookup(dir, dentry))
-               return 0;
+               return NULL;
        
        pid = 0;
        name = dentry->d_name.name;
@@ -853,13 +848,13 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
                unsigned long ino = (pid << 16) + PROC_PID_INO;
                inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
                if (!inode)
-                       return -EINVAL;
+                       return ERR_PTR(-EINVAL);
                inode->i_flags|=S_IMMUTABLE;
        }
 
        dentry->d_op = &proc_dentry_operations;
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
@@ -879,8 +874,6 @@ int proc_readdir(struct file * filp,
        int i;
        struct inode *inode = filp->f_dentry->d_inode;
 
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -ENOTDIR;
        ino = inode->i_ino;
        de = (struct proc_dir_entry *) inode->u.generic_ip;
        if (!de)
index 119930667393b76fa0e43f69ba0422603a40eef1..029fd9061b13b890664b5cf7a2cf4ded5c9e516e 100644 (file)
@@ -35,9 +35,6 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
        blknum = inode->u.qnx4_i.i_first_xtnt.xtnt_blk - 1 +
            ((filp->f_pos >> 6) >> 3);
 
-       if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
-               return -EBADF;
-       }
        QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
        QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
        QNX4DEBUG(("BlkNum              = %ld\n", (long) blknum));
index 267ecb1107d6969048ea6ae6b76928e7a56717d8..7765bbb9b75fe3a357b751fadca32dd29a9796d3 100644 (file)
@@ -108,7 +108,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir,
        return NULL;
 }
 
-int qnx4_lookup(struct inode *dir, struct dentry *dentry)
+struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry)
 {
        int ino;
        struct qnx4_inode_entry *de;
@@ -116,17 +116,10 @@ int qnx4_lookup(struct inode *dir, struct dentry *dentry)
        struct buffer_head *bh;
        const char *name = dentry->d_name.name;
        int len = dentry->d_name.len;
-       struct inode *foundinode;
+       struct inode *foundinode = NULL;
 
-       if (!dir) {
-               return -EBADF;
-       }
-       if (!S_ISDIR(dir->i_mode)) {
-               return -EBADF;
-       }
-       if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) {
-               return -ENOENT;
-       }
+       if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
+               goto out;
        /* The entry is linked, let's get the real info */
        if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
                lnk = (struct qnx4_link_info *) de;
@@ -137,11 +130,12 @@ int qnx4_lookup(struct inode *dir, struct dentry *dentry)
 
        if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
                QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
-               return -EACCES;
+               return ERR_PTR(-EACCES);
        }
+out:
        d_add(dentry, foundinode);
 
-       return 0;
+       return NULL;
 }
 
 #ifdef CONFIG_QNX4FS_RW
index 211563b1c9633fac1f047e2069148474fd0cc2f3..fd374842eeaff2b952277bca04a3ed3007b31dbc 100644 (file)
@@ -267,9 +267,6 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        int stored = 0;
        char fsname[ROMFS_MAXFN];       /* XXX dynamic? */
 
-       if (!i || !S_ISDIR(i->i_mode))
-               return -EBADF;
-
        maxoff = i->i_sb->u.romfs_sb.s_maxsize;
 
        offset = filp->f_pos;
@@ -312,7 +309,7 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
        }
 }
 
-static int
+static struct dentry *
 romfs_lookup(struct inode *dir, struct dentry *dentry)
 {
        unsigned long offset, maxoff;
@@ -323,10 +320,6 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
        const char *name;               /* got from dentry */
        int len;
 
-       res = -EBADF;
-       if (!dir || !S_ISDIR(dir->i_mode))
-               goto out;
-
        res = 0;                        /* instead of ENOENT */
        offset = dir->i_ino & ROMFH_MASK;
        if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
@@ -379,7 +372,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry)
        }
 
 out:
-       return res;
+       return ERR_PTR(res);
 }
 
 /*
index 370d0ea6e5b93541d50690e5208112f372c41a4b..b6d0364fc6caeef4d7baa4e394e468cdc8933850 100644 (file)
@@ -22,7 +22,7 @@ static ssize_t smb_dir_read(struct file *, char *, size_t, loff_t *);
 static int smb_readdir(struct file *, void *, filldir_t);
 static int smb_dir_open(struct inode *, struct file *);
 
-static int smb_lookup(struct inode *, struct dentry *);
+static struct dentry *smb_lookup(struct inode *, struct dentry *);
 static int smb_create(struct inode *, struct dentry *, int);
 static int smb_mkdir(struct inode *, struct dentry *, int);
 static int smb_rmdir(struct inode *, struct dentry *);
@@ -324,7 +324,7 @@ smb_renew_times(struct dentry * dentry)
        }
 }
 
-static int
+static struct dentry *
 smb_lookup(struct inode *dir, struct dentry *dentry)
 {
        struct smb_fattr finfo;
@@ -360,7 +360,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error);
                }
        }
 out:
-       return error;
+       return ERR_PTR(error);
 }
 
 /*
index 9a1acc19e69006ec82881162d2014150dd859cf3..a28a7ba8e9aeab944c2d0095dc641f0b83fca712 100644 (file)
@@ -69,14 +69,12 @@ struct inode_operations sysv_dir_inode_operations = {
 static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
        struct inode *inode = filp->f_dentry->d_inode;
-       struct super_block * sb;
+       struct super_block * sb = inode->i_sb;
        unsigned int offset,i;
        struct buffer_head * bh;
        char* bh_data;
        struct sysv_dir_entry * de, sde;
 
-       if (!inode || !(sb = inode->i_sb) || !S_ISDIR(inode->i_mode))
-               return -EBADF;
        if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE)
                return -EBADF;
        while (filp->f_pos < inode->i_size) {
index a06ee181c879ee91a68fe726f33832424075af72..38aebe9a9b80b7952051cb02a1ad53b20bd0bea2 100644 (file)
@@ -103,17 +103,12 @@ static struct buffer_head * sysv_find_entry(struct inode * dir,
        return NULL;
 }
 
-int sysv_lookup(struct inode * dir, struct dentry * dentry)
+struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
 {
        struct inode * inode = NULL;
        struct sysv_dir_entry * de;
        struct buffer_head * bh;
 
-       if (!dir)
-               return -ENOENT;
-       if (!S_ISDIR(dir->i_mode)) {
-               return -ENOENT;
-       }
        bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
 
        if (bh) {
@@ -122,10 +117,10 @@ int sysv_lookup(struct inode * dir, struct dentry * dentry)
                inode = iget(dir->i_sb, ino);
        
                if (!inode) 
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        d_add(dentry, inode);
-       return 0;
+       return NULL;
 }
 
 /*
@@ -209,8 +204,6 @@ int sysv_create(struct inode * dir, struct dentry * dentry, int mode)
        struct buffer_head * bh;
        struct sysv_dir_entry * de;
 
-       if (!dir)
-               return -ENOENT;
        inode = sysv_new_inode(dir);
        if (!inode) 
                return -ENOSPC;
@@ -239,8 +232,6 @@ int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev)
        struct buffer_head * bh;
        struct sysv_dir_entry * de;
 
-       if (!dir)
-               return -ENOENT;
        bh = sysv_find_entry(dir, dentry->d_name.name,
                             dentry->d_name.len, &de);
        if (bh) {
@@ -286,8 +277,6 @@ int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode)
        struct buffer_head * bh, *dir_block;
        struct sysv_dir_entry * de;
 
-       if (!dir)
-               return -EINVAL;
        bh = sysv_find_entry(dir, dentry->d_name.name,
                               dentry->d_name.len, &de);
        if (bh) {
index 24810fe486294e9ebf701e992f5c26e0c23d0279..6a79c4a5e96f1cfa565a609443fa195b97d15c08 100644 (file)
@@ -43,13 +43,6 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
        int de_reclen;
        unsigned flags, swab;
 
-
-       /* Isn't that already done in the upper layer???
-        * the VFS layer really needs some explicit documentation!
-        */
-       if (!inode || !S_ISDIR(inode->i_mode))
-               return -EBADF;
-
        sb = inode->i_sb;
        swab = sb->u.ufs_sb.s_swab;
        flags = sb->u.ufs_sb.s_flags;
index 0ad0b9201dc7bb013ad1e7808f9a0e81f70ed108..a30b187d390a5c8e9d71930821ff8df4182dbc9c 100644 (file)
@@ -185,7 +185,7 @@ failed:
        return NULL;
 }
 
-int ufs_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry)
 {
        struct super_block * sb;
        struct inode * inode;
@@ -199,7 +199,7 @@ int ufs_lookup(struct inode * dir, struct dentry *dentry)
        swab = sb->u.ufs_sb.s_swab;
        
        if (dentry->d_name.len > UFS_MAXNAMLEN)
-               return -ENAMETOOLONG;
+               return ERR_PTR(-ENAMETOOLONG);
 
        bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
        inode = NULL;
@@ -208,11 +208,11 @@ int ufs_lookup(struct inode * dir, struct dentry *dentry)
                brelse (bh);
                inode = iget(sb, ino);
                if (!inode) 
-                       return -EACCES;
+                       return ERR_PTR(-EACCES);
        }
        d_add(dentry, inode);
        UFSD(("EXIT\n"))
-       return 0;
+       return NULL;
 }
 
 /*
index e5e1723638f1df83f8e751133d13978add31db06..07a12a6a4b5c6036680f6a2a8079d7268fd01b50 100644 (file)
@@ -210,8 +210,8 @@ filp->f_dentry->d_name.name, entry.name);
                /*
                 * Do a real lookup on the short name.
                 */
-               dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname,
-                                                info.fake.len, 1);
+               dret = umsdos_covered(filp->f_dentry, info.fake.fname,
+                                                info.fake.len);
                ret = PTR_ERR(dret);
                if (IS_ERR(dret))
                        break;
@@ -459,7 +459,7 @@ int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
  * entry from the EMD file, and return ENOENT.
  */
 
-int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
+struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
 {                              
        struct dentry *dret = NULL;
        struct inode *inode;
@@ -500,8 +500,7 @@ Printk (("lookup %.*s pos %lu ret %d len %d ",
 info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
 
        /* do a real lookup to get the short name ... */
-       dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
-                                       info.fake.len, 1);
+       dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
        ret = PTR_ERR(dret);
        if (IS_ERR(dret)) {
 printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n", 
@@ -563,7 +562,7 @@ out_dput:
        dput(dret);
 out:
        umsdos_endlookup (dir);
-       return ret;
+       return ERR_PTR(ret);
 
 out_remove:
        printk(KERN_WARNING "UMSDOS:  entry %s/%s out of sync, erased\n",
@@ -581,19 +580,19 @@ out_remove:
  * Called by VFS; should fill dentry->d_inode via d_add.
  */
 
-int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
+struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
 {
-       int ret;
+       struct dentry *ret;
 
        ret = umsdos_lookup_x (dir, dentry, 0);
 
        /* Create negative dentry if not found. */
-       if (ret == -ENOENT) {
+       if (ret == ERR_PTR(-ENOENT)) {
                Printk ((KERN_DEBUG 
                        "UMSDOS_lookup: converting -ENOENT to negative\n"));
                d_add (dentry, NULL);
                dentry->d_op = &umsdos_dentry_operations;
-               ret = 0;
+               ret = NULL;
        }
        return ret;
 }
@@ -601,7 +600,6 @@ int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
 struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
 {
        struct dentry *result, *dentry;
-       int error;
        struct qstr qstr;
 
        qstr.name = name;
@@ -610,19 +608,18 @@ struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
        result = ERR_PTR(-ENOMEM);
        dentry = d_alloc(parent, &qstr);
        if (dentry) {
-               result = dentry;
                /* XXXXXXXXXXXXXXXXXXX Race alert! */
-               error = UMSDOS_rlookup(parent->d_inode, result);
-               d_drop(result);
-               if (error)
+               result = UMSDOS_rlookup(parent->d_inode, dentry);
+               d_drop(dentry);
+               if (result)
                        goto out_fail;
+               return dentry;
        }
 out:
        return result;
 
 out_fail:
-       dput(result);
-       result = ERR_PTR(error);
+       dput(dentry);
        goto out;
 }
 
@@ -636,7 +633,6 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
                                        int real)
 {
        struct dentry *result, *dentry;
-       int error;
        struct qstr qstr;
 
        qstr.name = name;
@@ -647,20 +643,19 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
                result = ERR_PTR(-ENOMEM);
                dentry = d_alloc(parent, &qstr);
                if (dentry) {
-                       result = dentry;
-                       error = real ?
-                               UMSDOS_rlookup(parent->d_inode, result) :
-                               UMSDOS_lookup(parent->d_inode, result);
-                       if (error)
+                       result = real ?
+                               UMSDOS_rlookup(parent->d_inode, dentry) :
+                               UMSDOS_lookup(parent->d_inode, dentry);
+                       if (result)
                                goto out_fail;
+                       return dentry;
                }
        }
 out:
        return result;
 
 out_fail:
-       dput(result);
-       result = ERR_PTR(error);
+       dput(dentry);
        goto out;
 }
 
index 3303da1ba932e876d2787d831a79f2d8c286ae1d..444e9ffae2cde57f30ab5320dea5f427934d5720 100644 (file)
@@ -175,18 +175,6 @@ void umsdos_endlookup (struct inode *dir)
 
 #endif
 
-/*
- * Check whether we can delete from the directory.
- */
-static int is_sticky(struct inode *dir, int uid)
-{
-       return !((dir->i_mode & S_ISVTX) == 0 || 
-               current->fsuid == uid ||
-               current->fsuid == dir->i_uid ||
-               capable (CAP_FOWNER));
-}
-
-
 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
                                int errcod)
 {
@@ -696,9 +684,8 @@ Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
 
        /* Do a real lookup to get the short name dentry */
-       temp = umsdos_lookup_dentry(olddentry->d_parent,
-                                       old_info.fake.fname, 
-                                       old_info.fake.len, 1);
+       temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
+                                       old_info.fake.len);
        ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out_unlock;
@@ -784,16 +771,11 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
                goto out;
 
        /* lookup the short name dentry */
-       temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len, 1);
+       temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
        ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out_remove;
 
-       /* Keep the short name dentry anonymous */ 
-       if (temp != dentry)
-               d_drop(temp);
-
        /* Make sure the short name doesn't exist */
        ret = -EEXIST;
        if (temp->d_inode) {
@@ -812,16 +794,9 @@ dentry->d_parent->d_name.name, info.fake.fname);
        inode = temp->d_inode;
        down(&inode->i_sem);
 
-       /*
-        * Note! The long and short name might be the same,
-        * so check first before doing the instantiate ...
-        */
-       if (dentry != temp) {
-if (dentry->d_inode)
-printk("umsdos_mkdir: dentry not negative!\n");
-               inode->i_count++;
-               d_instantiate(dentry, inode);
-       }
+       inode->i_count++;
+       d_instantiate(dentry, inode);
+
        /* N.B. this should have an option to create the EMD ... */
        umsdos_lookup_patch_new(dentry, &info);
 
@@ -921,20 +896,10 @@ demd->d_parent->d_name.name, demd->d_name.name, err);
        umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
        /* Call findentry to complete the mangling */
        umsdos_findentry (dentry->d_parent, &info, 2);
-       temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len, 1);
+       temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
        ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out;
-       /*
-        * If the short name is an alias, dput() it now;
-        * otherwise d_drop() it to keep it anonymous.
-        */
-       if (temp == dentry)
-               dput(temp);
-       else
-               d_drop(temp);
-
        /*
         * Attempt to remove the msdos name.
         */
@@ -951,8 +916,7 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
 
        /* dput() temp if we didn't do it above */
 out_dput:
-       if (temp != dentry)
-               dput(temp);
+       dput(temp);
 
 out:
        Printk (("umsdos_rmdir %d\n", ret));
@@ -999,14 +963,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret);
 
 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
 
-       ret = -EPERM;
-       /* check sticky bit */
-       if (is_sticky(dir, info.entry.uid)) {
-printk("umsdos_unlink: %s/%s is sticky\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-               goto out_unlock;
-       }
-
        /*
         * Note! If this is a hardlink and the names are aliased,
         * the short-name lookup will return the hardlink dentry.
@@ -1018,8 +974,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
        }
 
        /* Do a real lookup to get the short name dentry */
-       temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len, 1);
+       temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
        ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out_unlock;
@@ -1031,13 +986,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                link = umsdos_solve_hlink(dget(temp));
        }
 
-       /*
-        * If the short and long names are aliased,
-        * dput() it now so the dentry isn't busy.
-        */
-       if (temp == dentry)
-               dput(temp);
-
        /* Delete the EMD entry */
        ret = umsdos_delentry (dentry->d_parent, &info, 0);
        if (ret && ret != -ENOENT) {
@@ -1046,7 +994,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                goto out_dput;
        }
 
-       ret = msdos_unlink_umsdos (dir, temp);
+       ret = msdos_unlink(dir, temp);
 #ifdef UMSDOS_PARANOIA
 if (ret)
 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
@@ -1055,12 +1003,9 @@ temp->d_parent->d_name.name, temp->d_name.name, ret);
 
        /* dput() temp if we didn't do it above */
 out_dput:
-       if (temp != dentry) {
-               d_drop(temp);
-               dput(temp);
-               if (!ret)
-                       d_delete (dentry);
-       }
+       dput(temp);
+       if (!ret)
+               d_delete (dentry);
 
 out_unlock:
        umsdos_unlockcreate (dir);
index 10ff145b7c6657e3b1ec1fb630b3ebaf265e7123..3f5d109533a0906a26b6169d85a43ae95d0d7f5e 100644 (file)
@@ -79,9 +79,9 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir)
  * In the real root directory (c:\), the directory ..
  * is the pseudo root (c:\linux).
  */
-int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
+struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
 {
-       int ret;
+       struct dentry *ret;
 
        if (saved_root && dir == saved_root->d_inode && !nopseudo &&
            dentry->d_name.len == UMSDOS_PSDROOT_LEN &&
@@ -91,15 +91,16 @@ int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
                 * /linux won't show
                 */
                 
-               ret = -ENOENT;
+               ret = ERR_PTR(-ENOENT);
                goto out;
        }
 
        ret = msdos_lookup (dir, dentry);
        if (ret) {
                printk(KERN_WARNING
-                       "umsdos_rlookup_x: %s/%s failed, ret=%d\n",
-                       dentry->d_parent->d_name.name, dentry->d_name.name,ret);
+                       "umsdos_rlookup_x: %s/%s failed, ret=%ld\n",
+                       dentry->d_parent->d_name.name, dentry->d_name.name,
+                       PTR_ERR(ret));
                goto out;
        }
        if (dentry->d_inode) {
@@ -119,7 +120,7 @@ out:
 }
 
 
-int UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
+struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
 {
        return umsdos_rlookup_x (dir, dentry, 0);
 }
index 347aced2dc14fbbe8240bad14ca1a1bb09dda50f..25a11251b95f7831b149536d0ec9e219bb9a5ec9 100644 (file)
@@ -1140,11 +1140,30 @@ cleanup:
        return res;
 }
 
-int vfat_lookup(struct inode *dir,struct dentry *dentry)
+/* Find a hashed dentry for inode; NULL if there are none */
+static struct dentry *find_alias(struct inode *inode)
+{
+       struct list_head *head, *next, *tmp;
+       struct dentry *alias;
+
+       head = &inode->i_dentry;
+       next = inode->i_dentry.next;
+       while (next != head) {
+               tmp = next;
+               next = tmp->next;
+               alias = list_entry(tmp, struct dentry, d_alias);
+               if (!list_empty(&alias->d_hash))
+                       return dget(alias);
+       }
+       return NULL;
+}
+
+struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
 {
        int res;
        struct vfat_slot_info sinfo;
        struct inode *result;
+       struct dentry *alias;
        int table;
        
        PRINTK2(("vfat_lookup: name=%s, len=%d\n", 
@@ -1161,7 +1180,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
        }
        PRINTK3(("vfat_lookup 4.5\n"));
        if (!(result = iget(dir->i_sb,sinfo.ino)))
-               return -EACCES;
+               return ERR_PTR(-EACCES);
        PRINTK3(("vfat_lookup 5\n"));
        if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
                iput(result);
@@ -1169,6 +1188,15 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry)
                table++;
                goto error;
        }
+       alias = find_alias(result);
+       if (alias) {
+               if (d_invalidate(alias)==0)
+                       dput(alias);
+               else {
+                       iput(result);
+                       return alias;
+               }
+       }
        PRINTK3(("vfat_lookup 6\n"));
 error:
        dentry->d_op = &vfat_dentry_ops[table];
@@ -1397,28 +1425,6 @@ static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
        return 0;
 }
 
-/* Drop all aliases */
-static void drop_aliases(struct dentry *dentry)
-{
-       struct list_head *head, *next, *tmp;
-       struct dentry *alias;
-
-       PRINTK1(("drop_replace_inodes: dentry=%p, inode=%p\n", dentry, inode));
-       head = &dentry->d_inode->i_dentry;
-       if (dentry->d_inode) {
-               next = dentry->d_inode->i_dentry.next;
-               while (next != head) {
-                       tmp = next;
-                       next = tmp->next;
-                       alias = list_entry(tmp, struct dentry, d_alias);
-                       if (alias == dentry)
-                               continue;
-
-                       d_drop(alias);
-               }
-       }
-}
-
 static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
 {
        int res;
@@ -1430,12 +1436,6 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
        if (res >= 0 && sinfo.total_slots > 0) {
                if (!list_empty(&dentry->d_hash))
                        return -EBUSY;
-               /* Take care of aliases */
-               if (dentry->d_inode->i_count > 1) {
-                       shrink_dcache_parent(dentry->d_parent);
-                       if (dentry->d_inode->i_count > 1)
-                               return -EBUSY;
-               }
                res = vfat_empty(dentry->d_inode);
                if (res)
                        return res;
@@ -1535,10 +1535,8 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry)
 
        PRINTK1(("vfat_unlink: dentry=%p, inode=%p\n", dentry, dentry->d_inode));
        res = vfat_unlinkx (dir,dentry,1);
-       if (res >= 0) {
-               drop_aliases(dentry);
+       if (res >= 0)
                d_delete(dentry);
-       }
        return res;
 }
 
@@ -1561,7 +1559,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
        loff_t old_offset,new_offset,old_longname_offset;
        int old_slots,old_ino,new_ino,dotdot_ino;
        struct inode *old_inode, *new_inode, *dotdot_inode;
-       struct dentry *walk;
        int res, is_dir, i;
        int locked = 0;
        struct vfat_slot_info sinfo;
@@ -1589,16 +1586,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
        old_inode = old_dentry->d_inode;
        is_dir = S_ISDIR(old_inode->i_mode);
 
-       if (is_dir) {
-               /* We can't use is_subdir() here. Even now. Arrgh. */
-               for (walk=new_dentry;walk!=walk->d_parent;walk=walk->d_parent) {
-                       if (walk->d_inode != old_dentry->d_inode)
-                               continue;
-                       res = -EINVAL;
-                       goto rename_done;
-               }
-       }
-
        fat_lock_creation(); locked = 1;
 
        if (new_dentry->d_inode) {
@@ -1620,25 +1607,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
                }
 
                if (is_dir) {
-                       /*
-                        * Target is a directory. No other owners will
-                        * be tolerated.
-                        */
-                       res = -EBUSY;
-                       /*
-                        * OK, let's try to get rid of other dentries.
-                        * No need to do it if i_count is 1.
-                        */
-                       if (new_inode->i_count>1) {
-                               shrink_dcache_parent(new_dentry->d_parent);
-                               if (new_inode->i_count>1)
-                                       goto rename_done;
-                       }
                        res = vfat_empty(new_inode);
                        if (res)
                                goto rename_done;
-               } else {
-                       drop_aliases(new_dentry);
                }
                res = vfat_remove_entry(new_dir,&sinfo,new_inode);
                if (res)
index 34390e362a24389465942f9c282a2574ba31dc03..e62205f37b8656ea4f436c665c30f2707240cc02 100644 (file)
@@ -18,7 +18,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode         pckbd_setkeycode
 #define kbd_getkeycode         pckbd_getkeycode
-#define kbd_pretranslate       pckbd_pretranslate
 #define kbd_translate          pckbd_translate
 #define kbd_unexpected_up      pckbd_unexpected_up
 #define kbd_leds               pckbd_leds
index 0e7cc71d457c2d70a1342bc6eaa169d910a1cc2d..30f1372eac53b670215efdd6246d136beba70aaa 100644 (file)
@@ -53,24 +53,31 @@ extern inline void down(struct semaphore * sem)
           it's return address in $28.  The pv is loaded as usual.
           The gp is clobbered (in the module case) as usual.  */
 
+       /* This little bit of silliness is to get the GP loaded for
+          a function that ordinarily wouldn't.  Otherwise we could
+          have it done by the macro directly, which can be optimized
+          the linker.  */
+       register void *pv __asm__("$27") = __down_failed;
+       
        __asm__ __volatile__ (
                "/* semaphore down operation */\n"
-               "1:     ldl_l   $27,%0\n"
-               "       subl    $27,1,$27\n"
-               "       mov     $27,$28\n"
-               "       stl_c   $28,%0\n"
+               "1:     ldl_l   $24,%1\n"
+               "       subl    $24,1,$24\n"
+               "       mov     $24,$28\n"
+               "       stl_c   $28,%1\n"
                "       beq     $28,2f\n"
-               "       blt     $27,3f\n"
+               "       blt     $24,3f\n"
                "4:     mb\n"
                ".section .text2,\"ax\"\n"
                "2:     br      1b\n"
-               "3:     lda     $24,%0\n"
-               "       jsr     $28,__down_failed\n"
+               "3:     lda     $24,%1\n"
+               "       jsr     $28,($27),__down_failed\n"
                "       ldgp    $29,0($28)\n"
                "       br      4b\n"
                ".previous"
-               : : "m"(sem->count)
-               : "$24", "$27", "$28", "memory");
+               : "=r"(pv)
+               : "m"(sem->count), "r"(pv)
+               : "$24", "$28", "memory");
 }
 
 extern inline int down_interruptible(struct semaphore * sem)
@@ -81,27 +88,28 @@ extern inline int down_interruptible(struct semaphore * sem)
           value is in $24.  */
 
        register int ret __asm__("$24");
+       register void *pv __asm__("$27") = __down_failed_interruptible;
 
        __asm__ __volatile__ (
                "/* semaphore down interruptible operation */\n"
-               "1:     ldl_l   $27,%1\n"
-               "       subl    $27,1,$27\n"
-               "       mov     $27,$28\n"
-               "       stl_c   $28,%1\n"
+               "1:     ldl_l   $24,%2\n"
+               "       subl    $24,1,$24\n"
+               "       mov     $24,$28\n"
+               "       stl_c   $28,%2\n"
                "       beq     $28,2f\n"
-               "       blt     $27,3f\n"
+               "       blt     $24,3f\n"
                "       mov     $31,%0\n"
                "4:     mb\n"
                ".section .text2,\"ax\"\n"
                "2:     br      1b\n"
-               "3:     lda     $24,%1\n"
-               "       jsr     $28,__down_failed_interruptible\n"
+               "3:     lda     $24,%2\n"
+               "       jsr     $28,($27),__down_failed_interruptible\n"
                "       ldgp    $29,0($28)\n"
                "       br      4b\n"
                ".previous"
-               : "=r"(ret)
-               : "m"(sem->count)
-               : "$27", "$28", "memory");
+               : "=r"(ret), "=r"(pv)
+               : "m"(sem->count), "r"(pv)
+               : "$28", "memory");
 
        return ret;
 }
@@ -171,26 +179,29 @@ extern inline void up(struct semaphore * sem)
           it's return address in $28.  The pv is loaded as usual.
           The gp is clobbered (in the module case) as usual.  */
 
+       register void *pv __asm__("$27") = __up_wakeup;
+
        __asm__ __volatile__ (
                "/* semaphore up operation */\n"
                "       mb\n"
-               "1:     ldl_l   $27,%0\n"
-               "       addl    $27,1,$27\n"
-               "       mov     $27,$28\n"
-               "       stl_c   $28,%0\n"
+               "1:     ldl_l   $24,%1\n"
+               "       addl    $24,1,$24\n"
+               "       mov     $24,$28\n"
+               "       stl_c   $28,%1\n"
                "       beq     $28,2f\n"
                "       mb\n"
                "       ble     $27,3f\n"
                "4:\n"
                ".section .text2,\"ax\"\n"
                "2:     br      1b\n"
-               "3:     lda     $24,%0\n"
-               "       jsr     $28,__up_wakeup\n"
+               "3:     lda     $24,%1\n"
+               "       jsr     $28,($27),__up_wakeup\n"
                "       ldgp    $29,0($28)\n"
                "       br      4b\n"
                ".previous"
-               : : "m"(sem->count)
-               : "$24", "$27", "$28", "memory");
+               : "=r"(pv)
+               : "m"(sem->count), "r"(pv)
+               : "$24", "$28", "memory");
 }
 
 #endif
index f44914e3e36a058757b7b075249679b8d1954929..f615339f8856878c6d16b14f79c3c954e35165d9 100644 (file)
@@ -160,7 +160,7 @@ struct __large_struct { unsigned long buf[100]; };
                : "=r"(__gu_val), "=r"(__gu_err)        \
                : "m"(__m(addr)), "1"(__gu_err))
 
-#ifdef __HAVE_CPU_BWX
+#ifdef __alpha_bwx__
 /* Those lucky bastards with ev56 and later CPUs can do byte/word moves.  */
 
 #define __get_user_16(addr)                            \
@@ -274,7 +274,7 @@ __asm__ __volatile__("1: stl %r2,%1\n"                              \
                : "=r"(__pu_err)                                \
                : "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
 
-#ifdef __HAVE_CPU_BWX
+#ifdef __alpha_bwx__
 /* Those lucky bastards with ev56 and later CPUs can do byte/word moves.  */
 
 #define __put_user_16(x,addr)                                  \
@@ -363,15 +363,21 @@ extern void __copy_user(void);
 extern inline long
 __copy_tofrom_user_nocheck(void *to, const void *from, long len)
 {
+       /* This little bit of silliness is to get the GP loaded for
+          a function that ordinarily wouldn't.  Otherwise we could
+          have it done by the macro directly, which can be optimized
+          the linker.  */
+       register void * pv __asm__("$27") = __copy_user;
+
        register void * __cu_to __asm__("$6") = to;
        register const void * __cu_from __asm__("$7") = from;
        register long __cu_len __asm__("$0") = len;
 
        __asm__ __volatile__(
-               "jsr $28,__copy_user"
-               : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
-               : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
-               : "$1","$2","$3","$4","$5","$27","$28","memory");
+               "jsr $28,(%3),__copy_user\n\tldgp $29,0($28)"
+               : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to), "=r"(pv)
+               : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), "3"(pv)
+               : "$1","$2","$3","$4","$5","$28","memory");
 
        return __cu_len;
 }
@@ -380,14 +386,17 @@ extern inline long
 __copy_tofrom_user(void *to, const void *from, long len, const void *validate)
 {
        if (__access_ok((long)validate, len, get_fs())) {
+               register void * pv __asm__("$27") = __copy_user;
                register void * __cu_to __asm__("$6") = to;
                register const void * __cu_from __asm__("$7") = from;
                register long __cu_len __asm__("$0") = len;
                __asm__ __volatile__(
-                       "jsr $28,__copy_user"
-                       : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
-                       : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
-                       : "$1","$2","$3","$4","$5","$27","$28","memory");
+                       "jsr $28,(%3),__copy_user\n\tldgp $29,0($28)"
+                       : "=r"(__cu_len), "=r"(__cu_from), "=r"(__cu_to),
+                         "=r" (pv)
+                       : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), 
+                         "3" (pv)
+                       : "$1","$2","$3","$4","$5","$28","memory");
                len = __cu_len;
        }
        return len;
@@ -423,13 +432,19 @@ extern void __do_clear_user(void);
 extern inline long
 __clear_user(void *to, long len)
 {
+       /* This little bit of silliness is to get the GP loaded for
+          a function that ordinarily wouldn't.  Otherwise we could
+          have it done by the macro directly, which can be optimized
+          the linker.  */
+       register void * pv __asm__("$27") = __do_clear_user;
+
        register void * __cl_to __asm__("$6") = to;
        register long __cl_len __asm__("$0") = len;
        __asm__ __volatile__(
-               "jsr $28,__do_clear_user"
-               : "=r"(__cl_len), "=r"(__cl_to)
-               : "0"(__cl_len), "1"(__cl_to)
-               : "$1","$2","$3","$4","$5","$27","$28","memory");
+               "jsr $28,(%2),__do_clear_user\n\tldgp $29,0($28)"
+               : "=r"(__cl_len), "=r"(__cl_to), "=r"(pv)
+               : "0"(__cl_len), "1"(__cl_to), "2"(pv)
+               : "$1","$2","$3","$4","$5","$28","memory");
        return __cl_len;
 }
 
@@ -437,13 +452,14 @@ extern inline long
 clear_user(void *to, long len)
 {
        if (__access_ok((long)to, len, get_fs())) {
+               register void * pv __asm__("$27") = __do_clear_user;
                register void * __cl_to __asm__("$6") = to;
                register long __cl_len __asm__("$0") = len;
                __asm__ __volatile__(
-                       "jsr $28,__do_clear_user"
-                       : "=r"(__cl_len), "=r"(__cl_to)
-                       : "0"(__cl_len), "1"(__cl_to)
-                       : "$1","$2","$3","$4","$5","$27","$28","memory");
+                       "jsr $28,(%2),__do_clear_user\n\tldgp $29,0($28)"
+                       : "=r"(__cl_len), "=r"(__cl_to), "=r"(pv)
+                       : "0"(__cl_len), "1"(__cl_to), "2"(pv)
+                       : "$1","$2","$3","$4","$5","$28","memory");
                len = __cl_len;
        }
        return len;
index 388014703703a5998232de6ed0343279d6bc3cb9..4962defb5a2bcb4aff83035efaab6815266eae04 100644 (file)
@@ -19,11 +19,6 @@ extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES];
 #define kbd_setkeycode(sc,kc)          (-EINVAL)
 #define kbd_getkeycode(sc)             (-EINVAL)
 
-/* Prototype: int kbd_pretranslate(scancode, raw_mode)
- * Returns  : 0 to ignore scancode
- */
-#define kbd_pretranslate(sc,rm)        (1)
-
 /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
  * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
  *            set to 0200 if scancode indicates release
index ad6eb0e5a5726fadf4ae5ea34750c4cbd50cc975..a5ccd590236d1f97fd89bacd28309217bb823129 100644 (file)
@@ -19,7 +19,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -29,7 +28,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode                 pckbd_setkeycode
 #define kbd_getkeycode                 pckbd_getkeycode
-#define kbd_pretranslate               pckbd_pretranslate
 #define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
                pckbd_translate(sc & 0x7f, kcp, rm);})
 
@@ -50,11 +48,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
 #define kbd_setkeycode(sc,kc)          (-EINVAL)
 #define kbd_getkeycode(sc)             (-EINVAL)
 
-/* Prototype: int kbd_pretranslate(scancode, raw_mode)
- * Returns  : 0 to ignore scancode
- */
-#define kbd_pretranslate(sc,rm)                (1)
-
 /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
  * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
  *            set to 0200 if scancode indicates release
index 6c04cf07495d2bd3b2a7b364529ff78a25cbef3a..d0d1667a68f0f706bd3bcc3af11003e1bb91aca4 100644 (file)
@@ -10,7 +10,6 @@
 
 #define NR_SCANCODES 128
 
-extern int ps2kbd_pretranslate(unsigned char scancode);
 extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
 extern void ps2kbd_leds(unsigned char leds);
 extern void ps2kbd_init_hw(void);
@@ -19,11 +18,6 @@ extern unsigned char ps2kbd_sysrq_xlate[NR_SCANCODES];
 #define kbd_setkeycode(sc,kc)          (-EINVAL)
 #define kbd_getkeycode(sc)             (-EINVAL)
 
-/* Prototype: int kbd_pretranslate(scancode, raw_mode)
- * Returns  : 0 to ignore scancode
- */
-#define kbd_pretranslate(sc,rm)                ps2kbd_pretranslate(sc)
-
 /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
  * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
  *            set to 0200 if scancode indicates release
index 2fa371ff972851c3a7e18568c2e5d9eb58346413..ad2007d7e87bdfeaf99c5a47d584e57a9a7889fa 100644 (file)
@@ -14,7 +14,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -24,7 +23,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode                 pckbd_setkeycode
 #define kbd_getkeycode                 pckbd_getkeycode
-#define kbd_pretranslate               pckbd_pretranslate
 #define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
                pckbd_translate(sc & 0x7f, kcp, rm);})
 
index 103bc0417b15e7f77ed31590bdcdbaed79d82fd6..f5f7471424ec28f4f7891e622f1a3bb9f2943bf9 100644 (file)
@@ -18,7 +18,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode         pckbd_setkeycode
 #define kbd_getkeycode         pckbd_getkeycode
-#define kbd_pretranslate       pckbd_pretranslate
 #define kbd_translate          pckbd_translate
 #define kbd_unexpected_up      pckbd_unexpected_up
 #define kbd_leds               pckbd_leds
index eccadf2e35b6b0231a3b7b4b6afbd26e4a2ff5b4..d14dd3ed5eeb73d79da55a2234a0ab5f5af8419f 100644 (file)
@@ -27,11 +27,6 @@ static __inline__ int kbd_getkeycode(unsigned int scancode)
     return scancode > 127 ? -EINVAL : scancode;
 }
 
-static __inline__ int kbd_pretranslate(unsigned char scancode, char raw_mode)
-{
-    return 1;
-}
-
 static __inline__ int kbd_translate(unsigned char scancode,
                                    unsigned char *keycode, char raw_mode)
 {
index 00ed32f06d5cbd9115721fea84e934c977aabd8b..5d04572814a01a450b7ad0822741af2e5c9b2076 100644 (file)
@@ -19,7 +19,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -29,7 +28,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
 
 #define kbd_setkeycode         pckbd_setkeycode
 #define kbd_getkeycode         pckbd_getkeycode
-#define kbd_pretranslate       pckbd_pretranslate
 #define kbd_translate          pckbd_translate
 #define kbd_unexpected_up      pckbd_unexpected_up
 #define kbd_leds               pckbd_leds
index cc9262059409143432b4caa6330addcc5b0cff74..28a5a67617736dd1423a48964799dd65d55eaffb 100644 (file)
@@ -28,7 +28,6 @@
 
 extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern int mackbd_unexpected_up(unsigned char keycode);
@@ -37,7 +36,6 @@ extern void mackbd_init_hw(void);
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
                           char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -84,23 +82,6 @@ static inline int kbd_getkeycode(unsigned int x)
                return mackbd_getkeycode(x);
 }
 
-static inline int kbd_pretranslate(unsigned char x,char y)
-{
-       if ( is_prep || (_machine == _MACH_mbx) )
-               return pckbd_pretranslate(x,y);
-       else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-               return pckbd_pretranslate(x,y);
-#else
-               if ( adb_hardware == ADB_NONE )
-                       return pckbd_pretranslate(x,y);
-               else
-                       return mackbd_pretranslate(x,y);
-#endif
-       else
-               return mackbd_pretranslate(x,y);
-}
-
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
                     char raw_mode)
 {
index 9dd63c3cb90d78cc91f4c5dbf6f06531966f2860..9821385fab8c33063085849a70801b37e9e8baec 100644 (file)
@@ -18,7 +18,6 @@
 
 extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pcikbd_getkeycode(unsigned int scancode);
-extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
                            char raw_mode);
 extern char pcikbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@ extern unsigned char pcikbd_sysrq_xlate[128];
 
 #define kbd_setkeycode                 pcikbd_setkeycode
 #define kbd_getkeycode                 pcikbd_getkeycode
-#define kbd_pretranslate               pcikbd_pretranslate
 #define kbd_translate                  pcikbd_translate
 #define kbd_unexpected_up              pcikbd_unexpected_up
 #define kbd_leds                       pcikbd_leds
index 1bc97d59792bc7ea875a3825d203b3b15ab6e7c8..d7b5bc400d904a90dcca74317c615d061280fea5 100644 (file)
@@ -18,7 +18,6 @@
 
 extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pcikbd_getkeycode(unsigned int scancode);
-extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
                            char raw_mode);
 extern char pcikbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@ extern unsigned char pcikbd_sysrq_xlate[128];
 
 #define kbd_setkeycode                 pcikbd_setkeycode
 #define kbd_getkeycode                 pcikbd_getkeycode
-#define kbd_pretranslate               pcikbd_pretranslate
 #define kbd_translate                  pcikbd_translate
 #define kbd_unexpected_up              pcikbd_unexpected_up
 #define kbd_leds                       pcikbd_leds
index fe4e79e4b0827e36b46aa9953dd674107e9af6ef..f6ed2d3b1e7c6ce49426a6c360aaa649231d3b12 100644 (file)
@@ -155,7 +155,7 @@ extern void adfs_read_inode (struct inode *inode);
 extern int adfs_map_lookup (struct super_block *sb, int frag_id, int offset);
 
 /* namei.c */
-extern int adfs_lookup (struct inode *dir, struct dentry *dentry);
+extern struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry);
 
 /* super.c */
 extern int init_adfs_fs (void);
index 6361a82a1ceef5fc978cf990fc857348efeb3cd4..342ac2648c305785ed06961d608f3a5d576711e9 100644 (file)
@@ -60,7 +60,7 @@ extern void   affs_make_zones(struct super_block *sb);
 /* namei.c */
 
 extern int     affs_hash_name(const unsigned char *name, int len, int intl, int hashsize);
-extern int     affs_lookup(struct inode *dir, struct dentry *dentry);
+extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry);
 extern int     affs_unlink(struct inode *dir, struct dentry *dentry);
 extern int     affs_create(struct inode *dir, struct dentry *dentry, int mode);
 extern int     affs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
index 96b1d19557e47441aadcc1464c3dd6a256a561d3..b1352dc021df6ef98fbf3d8a19881e863e9dbcbf 100644 (file)
@@ -572,7 +572,7 @@ extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
 
 /* namei.c */
 extern void ext2_release (struct inode *, struct file *);
-extern int ext2_lookup (struct inode *, struct dentry *);
+extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
 extern int ext2_create (struct inode *,struct dentry *,int);
 extern int ext2_mkdir (struct inode *,struct dentry *,int);
 extern int ext2_rmdir (struct inode *,struct dentry *);
index d4bb4ae7882d6cd8f8486fd89debeee6853f2141..f084ca0366b17e79a352d3f4b8a38e864f402a7b 100644 (file)
@@ -31,6 +31,7 @@
 #define FB_TYPE_PLANES                 1       /* Non interleaved planes */
 #define FB_TYPE_INTERLEAVED_PLANES     2       /* Interleaved planes   */
 #define FB_TYPE_TEXT                   3       /* Text/attributes      */
+#define FB_TYPE_VGA_PLANES             4       /* EGA/VGA planes       */
 
 #define FB_AUX_TEXT_MDA                0       /* Monochrome text */
 #define FB_AUX_TEXT_CGA                1       /* CGA/EGA/VGA Color text */
@@ -297,7 +298,7 @@ struct display {
 
 struct fb_info {
    char modename[40];                  /* default video mode */
-   int node;
+   kdev_t node;
    int flags;
 #define FBINFO_FLAG_MODULE     1       /* Low-level driver is a module */
    struct fb_ops *fbops;
index b6ecebbbe2da4e41f1194f560722a7ee7ddd68c6..4d658c33eb9e081c7f835c2f04d0f0760f8ec152 100644 (file)
@@ -254,18 +254,8 @@ static inline int buffer_protected(struct buffer_head * bh)
        return test_bit(BH_Protected, &bh->b_state);
 }
 
-/*
- * Deprecated - we don't keep per-buffer reference flags
- * any more.
- *
- * We _could_ try to update the page reference, but that
- * doesn't seem to really be worth it either. If we did,
- * it would look something like this:
- *
- *     #define buffer_page(bh)         (mem_map + MAP_NR((bh)->b_data))
- *     #define touch_buffer(bh)        set_bit(PG_referenced, &buffer_page(bh)->flags)
- */
-#define touch_buffer(bh)       do { } while (0)
+#define buffer_page(bh)                (mem_map + MAP_NR((bh)->b_data))
+#define touch_buffer(bh)       set_bit(PG_referenced, &buffer_page(bh)->flags)
 
 #include <linux/pipe_fs_i.h>
 #include <linux/minix_fs_i.h>
@@ -607,7 +597,7 @@ struct file_operations {
 struct inode_operations {
        struct file_operations * default_file_ops;
        int (*create) (struct inode *,struct dentry *,int);
-       int (*lookup) (struct inode *,struct dentry *);
+       struct dentry * (*lookup) (struct inode *,struct dentry *);
        int (*link) (struct dentry *,struct inode *,struct dentry *);
        int (*unlink) (struct inode *,struct dentry *);
        int (*symlink) (struct inode *,struct dentry *,const char *);
diff --git a/include/linux/irda.h b/include/linux/irda.h
new file mode 100644 (file)
index 0000000..275d82f
--- /dev/null
@@ -0,0 +1,120 @@
+/*********************************************************************
+ *                
+ * Filename:      irda.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Mon Mar  8 14:06:12 1999
+ * Modified at:   Mon Mar 22 14:14:54 1999
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *      
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *     
+ ********************************************************************/
+
+#ifndef KERNEL_IRDA_H
+#define KERNEL_IRDA_H
+
+/* Hint bit positions for first hint byte */
+#define HINT_PNP         0x01
+#define HINT_PDA         0x02
+#define HINT_COMPUTER    0x04
+#define HINT_PRINTER     0x08
+#define HINT_MODEM       0x10
+#define HINT_FAX         0x20
+#define HINT_LAN         0x40
+#define HINT_EXTENSION   0x80
+
+/* Hint bit positions for second hint byte (first extension byte) */
+#define HINT_TELEPHONY   0x01
+#define HINT_FILE_SERVER 0x02
+#define HINT_COMM        0x04
+#define HINT_MESSAGE     0x08
+#define HINT_HTTP        0x10
+#define HINT_OBEX        0x20
+
+/* IrLMP character code values */
+#define CS_ASCII       0x00
+#define        CS_ISO_8859_1  0x01
+#define        CS_ISO_8859_2  0x02
+#define        CS_ISO_8859_3  0x03
+#define        CS_ISO_8859_4  0x04
+#define        CS_ISO_8859_5  0x05
+#define        CS_ISO_8859_6  0x06
+#define        CS_ISO_8859_7  0x07
+#define        CS_ISO_8859_8  0x08
+#define        CS_ISO_8859_9  0x09
+#define CS_UNICODE     0xff
+
+#define SOL_IRLMP      266 /* Same as SOL_IRDA for now */
+#define SOL_IRTTP      266 /* Same as SOL_IRDA for now */
+
+#define IRLMP_ENUMDEVICES        1
+#define IRLMP_IAS_SET            2
+#define IRLMP_IAS_QUERY          3
+#define IRLMP_DISCOVERY_MASK_SET 4
+
+#define IRTTP_QOS_SET            5
+#define IRTTP_QOS_GET            6
+#define IRTTP_MAX_SDU_SIZE       7
+
+#define IAS_MAX_STRING           256
+#define IAS_MAX_OCTET_STRING     1024
+#define IAS_MAX_CLASSNAME        64
+#define IAS_MAX_ATTRIBNAME       256
+
+#define LSAP_ANY                 0xff
+
+struct sockaddr_irda {
+       sa_family_t   sir_family;   /* AF_IRDA */
+       unsigned char sir_lsap_sel; /* LSAP/TSAP selector */
+       unsigned int  sir_addr;     /* Device address */
+       char          sir_name[25]; /* Usually <service>:IrDA:TinyTP */
+};
+
+struct irda_device_info {
+       unsigned int  saddr;       /* Address of remote device */
+       unsigned int  daddr;       /* Link where it was discovered */
+       char          info[22];     /* Description */
+       unsigned char charset;      /* Charset used for description */
+       unsigned char hints[2];     /* Hint bits */
+};
+
+struct irda_device_list {
+       unsigned int len;
+       struct irda_device_info dev[0];
+};
+
+struct irda_ias_set {
+       char irda_class_name[IAS_MAX_CLASSNAME];
+       char irda_attrib_name[IAS_MAX_ATTRIBNAME];
+       unsigned int irda_attrib_type;
+       union {
+               unsigned int irda_attrib_int;
+               struct {
+                       unsigned short len;
+                       u_char OctetSeq[IAS_MAX_OCTET_STRING];
+               } irda_attrib_octet_seq;
+               struct {
+                       unsigned char len;
+                       unsigned char charset;
+                       unsigned char string[IAS_MAX_STRING];
+               } irda_attrib_string;
+       } attribute;
+};
+
+#endif /* KERNEL_IRDA_H */
+
+
+
+
index 30a14b169ac5c2df2e1c9062883c736405f78e11..0fcb4b822498accedc21bf6e1704ee4f6c04957c 100644 (file)
@@ -189,7 +189,7 @@ int get_acorn_filename(struct iso_directory_record *, char *, struct inode *);
 
 extern int isofs_open(struct inode * inode, struct file * filp);
 extern void isofs_release(struct inode * inode, struct file * filp);
-extern int isofs_lookup(struct inode * dir, struct dentry *);
+extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *);
 extern unsigned long isofs_count_free_inodes(struct super_block *sb);
 extern int isofs_new_block(int dev);
 extern int isofs_free_block(int dev, int block);
index d83f9ea8ac71f539c4b34c26688c28bece2328bb..02ebf8ec8c55b7a749dbff3824213d3bcad8f297 100644 (file)
@@ -7,6 +7,6 @@
 
 extern struct pt_regs *kbd_pt_regs;
 
-void handle_scancode(unsigned char scancode);
+void handle_scancode(unsigned char scancode, int down);
 
 #endif /* _KBD_LL_H */
index 3a06359468c76d17d56ef8bc4227205a00a194ad..4682ee56e49c8ca62fcbea883650b779e8c1c7f1 100644 (file)
@@ -89,7 +89,7 @@ struct minix_dir_entry {
 
 #ifdef __KERNEL__
 
-extern int minix_lookup(struct inode * dir, struct dentry *dentry);
+extern struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry);
 extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
 extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
 extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
index ab699c4edb533d4286682c67deb12fe2b5abcb66..7e27f1ac66df34f4e4c93832a3538f39cf42a356 100644 (file)
@@ -271,7 +271,7 @@ extern struct super_block *msdos_read_super(struct super_block *sb,void *data, i
 
 /* msdos.c - these are for Umsdos */
 extern void msdos_read_inode(struct inode *inode);
-extern int msdos_lookup(struct inode *dir,struct dentry *);
+extern struct dentry *msdos_lookup(struct inode *dir,struct dentry *);
 extern int msdos_create(struct inode *dir,struct dentry *dentry,int mode);
 extern int msdos_rmdir(struct inode *dir,struct dentry *dentry);
 extern int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode);
@@ -312,7 +312,7 @@ extern void vfat_put_super(struct super_block *sb);
 extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
                                           int silent);
 extern void vfat_read_inode(struct inode *inode);
-extern int vfat_lookup(struct inode *dir,struct dentry *);
+extern struct dentry *vfat_lookup(struct inode *dir,struct dentry *);
 
 /* vfat/vfatfs_syms.c */
 extern struct file_system_type vfat_fs_type;
index 21ed45afc14096b09157569035517951fa007e1c..c8b5731df72e67b1fe787cd4439cdb114e255e9a 100644 (file)
@@ -382,7 +382,7 @@ extern int proc_match(int, const char *,struct proc_dir_entry *);
  * of the /proc/<pid> subdirectories.
  */
 extern int proc_readdir(struct file *, void *, filldir_t);
-extern int proc_lookup(struct inode *, struct dentry *);
+extern struct dentry *proc_lookup(struct inode *, struct dentry *);
 
 struct openpromfs_dev {
        struct openpromfs_dev *next;
index eb2b3dc0829972c5dea68af89f0b3b0b49c59835..c5a010394a9152bb35ca8676a4100ad7c6b920be 100644 (file)
@@ -95,7 +95,7 @@ struct qnx4_super_block {
 #define QNX4DEBUG(X) (void) 0
 #endif
 
-extern int qnx4_lookup(struct inode *dir, struct dentry *dentry);
+extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
 extern unsigned long qnx4_count_free_inodes(struct super_block *sb);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 
index 9b615ac1be10a1599279530284daf0103d637c71..db74f03be22e681d6b0b1ce6d7d456f41cd4b86e 100644 (file)
@@ -56,9 +56,15 @@ enum
        CTL_PROC=4,             /* Process info */
        CTL_FS=5,               /* Filesystems */
        CTL_DEBUG=6,            /* Debugging */
-       CTL_DEV=7               /* Devices */
+       CTL_DEV=7,              /* Devices */
+       CTL_BUS=8               /* Buses */
 };
 
+/* CTL_BUS names: */
+enum
+{
+       BUS_ISA=1               /* ISA */
+};
 
 /* CTL_KERN names: */
 enum
@@ -133,9 +139,17 @@ enum
        NET_IPV6=12,
        NET_X25=13,
        NET_TR=14,
-       NET_DECNET=15
+       NET_DECNET=15,
+       NET_ECONET=16
 };
 
+/* /proc/sys/bus/isa */
+enum
+{
+       BUS_ISA_MEM_BASE=1,
+       BUS_ISA_PORT_BASE=2,
+       BUS_ISA_PORT_SHIFT=3
+};
 
 /* /proc/sys/net/core */
 enum
index 7c8016886b29517a50cb205d23244f58286a6a02..49d9d24f163d51f1a350bb4bd6f75334587283ea 100644 (file)
@@ -367,7 +367,7 @@ sv_bread (struct super_block *sb, kdev_t dev, unsigned int block)
  * Function prototypes
  */
 
-extern int sysv_lookup(struct inode * dir, struct dentry * dentry);
+extern struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry);
 extern int sysv_create(struct inode * dir, struct dentry * dentry, int mode);
 extern int sysv_mkdir(struct inode * dir, struct dentry * dentry, int mode);
 extern int sysv_rmdir(struct inode * dir, struct dentry * dentry);
index d15d578b1e790c0f96f1b57309a3c2fb56eef2f8..e36ceba9e9ea2ae60d4ee9e8e188bd7b98c3b421 100644 (file)
@@ -540,7 +540,7 @@ extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
 extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
 
 /* namei.c */
-extern int ufs_lookup (struct inode *, struct dentry *);
+extern struct dentry *ufs_lookup (struct inode *, struct dentry *);
 extern int ufs_mkdir(struct inode *, struct dentry *, int);
 extern int ufs_rmdir (struct inode *, struct dentry *);
 extern int ufs_unlink (struct inode *, struct dentry *);
index e244069303bba5d300827fbc073fb4e59e0b9b96..de436f0e8ff3be712a1df8b4d098302039873247 100644 (file)
@@ -9,8 +9,8 @@ int  dummy_dir_read ( struct file *filp,
 char * umsdos_d_path(struct dentry *, char *, int);
 void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *);
 int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry);
-int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo);
-int UMSDOS_lookup(struct inode *, struct dentry *);
+struct dentry *umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo);
+struct dentry *UMSDOS_lookup(struct inode *, struct dentry *);
 struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int);
 struct dentry *umsdos_covered(struct dentry *, char *, int);
 
@@ -106,8 +106,8 @@ int UMSDOS_rename (struct inode *old_dir,
                   struct dentry *new_dentry);
 
 /* rdir.c 22/03/95 03.31.42 */
-int umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
-int UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
+struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
+struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
 
 /* symlink.c 23/01/95 03.38.30 */
 
index b81d92f9881a98bb266215029fa9e4bf7f6992bc..d3c59fff5a67a8e85a4494a3a72fd260f0ddc626 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :   6       18.2.99
+ * Version :   7       23.4.99
  *
  * Authors :   Jean Tourrilhes - HPLB - <jt@hplb.hpl.hp.com>
  */
  *
  * V5 to V6
  * --------
- *     - 802.11 support
+ *     - 802.11 support (ESSID ioctls)
+ *
+ * V6 to V7
+ * --------
+ *     - define IW_ESSID_MAX_SIZE and IW_MAX_AP
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
 /* As the ESSID is a string up to 32 bytes long, it doesn't fit within the
  * 'iwreq' structure, so we need to use the 'data' member to point to a
  * string in user space, like it is done for RANGE...
+ * The "flags" member indicate if the ESSID is active or not.
  */
 
 /* ------------------------- IOCTL STUFF ------------------------- */
 /* Maximum of address that you may set with SPY */
 #define IW_MAX_SPY             8
 
+/* Maximum of address that you may get in the
+   list of access points in range */
+#define IW_MAX_AP              8
+
+/* Maximum size of the ESSID string */
+#define IW_ESSID_MAX_SIZE      32
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -278,7 +290,7 @@ struct      iwreq
                        caddr_t pointer;        /* Pointer to the data
                                                 * (in user space) */
                        __u16   length;         /* fields or byte size */
-                       __u16   flags;          /* Unused */
+                       __u16   flags;          /* Optional params */
                }       data;
        }       u;
 };
index 99e4704b49d72df92b7cd248c12a8153a066ca1c..15e254b33feb291c270a325d71900d4199973d0c 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 16:53:53 1999
- * Modified at:   Tue Apr  6 20:44:35 1999
+ * Modified at:   Thu Apr 22 11:04:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -37,6 +37,7 @@
 #include <net/irda/irqueue.h>
 
 #define DISCOVERY_EXPIRE_TIMEOUT 6*HZ
+#define DISCOVERY_DEFAULT_SLOTS  0
 
 /*
  * The DISCOVERY structure is used for both discovery requests and responses
index e2b2ae507c5750333823b1d0cfadb721dad77199..cd1c41f86818ec711db4395d1f634bf4a5e49f01 100644 (file)
 #include <net/irda/irmod.h> 
 
 typedef enum {
-       COMM_DISCOVERY,
         COMM_IDLE,
+
+       COMM_DISCOVERY_WAIT,
+       COMM_QUERYPARAM_WAIT,
+       COMM_QUERYLSAP_WAIT,
+
        COMM_WAITI,
        COMM_WAITR,
        COMM_CONN,
@@ -53,6 +57,12 @@ typedef enum {
        IRCOMM_DATA_REQUEST,
        LMP_DATA_INDICATION,
        IRCOMM_CONTROL_REQUEST,
+       
+       DISCOVERY_INDICATION,
+       GOT_PARAMETERS,
+       GOT_LSAPSEL,
+       QUERYIAS_ERROR,
+
 } IRCOMM_EVENT;
 
 typedef enum {
@@ -172,6 +182,9 @@ struct ircomm_cb{
 
        __u32 daddr;        /* Device address of the peer device */ 
        __u32 saddr;
+       __u32 skey;
+       __u32 ckey;
+       int                 queryias_lock;
        int                 ias_type;
        int disconnect_priority; /* P_NORMAL or P_HIGH. see irttp.h */
        struct notify_t notify;     /* container of callbacks */
@@ -206,6 +219,7 @@ struct ircomm_cb{
        __u8 peer_port_type;
 
        __u8 servicetype;    
+       __u8 peer_servicetype;    
        __u8 data_format;   
        __u8 peer_data_format;   
        __u8 flow_ctrl;
@@ -241,8 +255,7 @@ struct ircomm_cb{
 
 
 
-int  ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype); 
-void ircomm_connect_request(struct ircomm_cb *self);
+void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype);
 void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
                             __u32 maxsdusize);
 void ircomm_disconnect_request(struct ircomm_cb *self,
index d51e159f5b246ac5f256e3f1c23875a02522b247..35c15fadc27237a1f57f641d4650501f40abc567 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Tue Apr  6 20:31:08 1999
+ * Modified at:   Wed Apr 21 17:49:00 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
 #define ALIGN __attribute__((aligned))
 #define PACK __attribute__((packed))
 
-/* use 0 for production, 1 for verification, >2 for debug */
+
 #ifdef CONFIG_IRDA_DEBUG
 
 extern __u32 irda_debug;
 
-#define IRDA_DEBUG 0
+/* use 0 for production, 1 for verification, >2 for debug */
+#define IRDA_DEBUG_LEVEL 0
 
-#define DEBUG(n, args...) if (irda_debug >= (n)) printk( KERN_DEBUG args)
+#define DEBUG(n, args...) if (irda_debug >= (n)) printk(KERN_DEBUG args)
 #define ASSERT(expr, func) \
 if(!(expr)) { \
         printk( "Assertion failed! %s,%s,%s,line=%d\n",\
@@ -61,6 +62,12 @@ if(!(expr)) { \
 #define ASSERT(expr, func)
 #endif /* CONFIG_IRDA_DEBUG */
 
+#define WARNING(args...) printk(KERN_WARNING args)
+#define MESSAGE(args...) printk(KERN_INFO args)
+#define ERROR(args...)   printk(KERN_ERR args)
+
+#define MSECS_TO_JIFFIES(ms) (ms*HZ/1000)
+
 /*
  *  Magic numbers used by Linux/IR. Random numbers which must be unique to 
  *  give the best protection
@@ -112,6 +119,8 @@ struct irda_sock {
 
        int nslots;           /* Number of slots to use for discovery */
 
+       int errno;
+
        struct sock *sk;
        struct wait_queue *ias_wait;       /* Wait for LM-IAS answer */
 
index 3f61a4e71b29236053bfb434a4618176e84f907c..a3dcf2d6e78ffb15886d92cb7705f123177a8bd4 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Haris Zukanovic <haris@stud.cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Wed Apr  7 17:17:16 1999
+ * Modified at:   Tue Apr 20 11:06:28 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Haris Zukanovic, <haris@stud.cs.uit.no>
 #include <net/irda/irda.h>
 #include <net/irda/qos.h>
 #include <net/irda/irqueue.h>
+#include <net/irda/irlap_frame.h>
 
 /* Some non-standard interface flags (should not conflict with any in if.h) */
-#define IFF_SIR        0x01 /* Supports SIR speeds */
-#define IFF_MIR        0x02 /* Supports MIR speeds */
-#define IFF_FIR        0x04 /* Supports FIR speeds */
-#define IFF_PIO        0x08 /* Supports PIO transfer of data */
-#define IFF_DMA                0x10 /* Supports DMA transfer of data */
-#define IFF_SHM         0x20 /* Supports shared memory data transfers */
-#define IFF_DONGLE      0x40 /* Interface has a dongle attached */
+#define IFF_SIR        0x0001 /* Supports SIR speeds */
+#define IFF_MIR        0x0002 /* Supports MIR speeds */
+#define IFF_FIR        0x0004 /* Supports FIR speeds */
+#define IFF_VFIR        0x0008 /* Supports VFIR speeds */
+#define IFF_PIO        0x0010 /* Supports PIO transfer of data */
+#define IFF_DMA                0x0020 /* Supports DMA transfer of data */
+#define IFF_SHM         0x0040 /* Supports shared memory data transfers */
+#define IFF_DONGLE      0x0080 /* Interface has a dongle attached */
+#define IFF_AIR         0x0100 /* Supports A(dvanced)IR standards */
 
 #define IO_XMIT 0x01
 #define IO_RECV 0x02
@@ -65,18 +68,17 @@ struct chipio_t {
        int dongle_id;        /* Dongle or transceiver currently used */
 };
 
-/* Buffer specific info */
+/* IO buffer specific info (inspired by struct sk_buff) */
 struct iobuff_t {
        int state;            /* Receiving state (transmit state not used) */
        int in_frame;         /* True if receiving frame */
 
-       __u8 *data;           /* the buffer */
-       __u8 *head;           /* start of data in buffer */
+       __u8 *head;           /* start of buffer */
+       __u8 *data;           /* start of data in buffer */
        __u8 *tail;           /* end of data in buffer */
 
-       int offset;           /* Usually data + offset = head */
-       int len;              /* currently used bytes in buffer */
-       int truesize;         /* total size of the data area */
+       int len;              /* length of data */
+       int truesize;         /* total size of buffer */
        __u16 fcs;
 
        int flags;            /* Allocation flags (GFP_KERNEL | GFP_DMA ) */
@@ -89,7 +91,7 @@ struct iobuff_t {
  * stuff from IrDA port implementations.
  */
 struct irda_device {
-       QUEUE q; /* Must be first */
+       QUEUE q;               /* Must be first */
 
         int  magic;           /* Our magic bullet */
        char name[16];         /* Name of device "irda0" */
@@ -109,18 +111,18 @@ struct irda_device {
        struct iobuff_t tx_buff;
        struct iobuff_t rx_buff;
 
-       int xbofs;
-       int media_busy;
        /* spinlock_t lock; */ /* For serializing operations */
        
        /* Media busy stuff */
+       int media_busy;
        struct timer_list media_busy_timer;
 
-       /* Driver specific implementation */
+       /* Callbacks for driver specific implementation */
         void (*change_speed)(struct irda_device *driver, int baud);
-       int (*is_receiving)(struct irda_device *);     /* receiving? */
+       int  (*is_receiving)(struct irda_device *);    /* receiving? */
        /* int (*is_tbusy)(struct irda_device *); */   /* transmitting? */
        void (*wait_until_sent)(struct irda_device *);
+       void (*set_caddr)(struct irda_device *);      /* Set connection addr */
 };
 
 extern hashbin_t *irda_device;
@@ -143,8 +145,28 @@ int irda_device_txqueue_empty(struct irda_device *self);
 
 int irda_device_setup(struct device *dev);
 
-inline unsigned short irda_get_mtt(struct sk_buff *skb);
-
 void setup_dma(int channel, char *buffer, int count, int mode);
 
+/*
+ * Function irda_get_mtt (skb)
+ *
+ *    Utility function for getting the minimum turnaround time out of 
+ *    the skb, where it has been hidden in the cb field.
+ */
+inline static __u16 irda_get_mtt(struct sk_buff *skb)
+{
+       __u16 mtt;
+
+       if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
+               mtt = 10000;
+       else
+               mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt;
+
+       ASSERT(mtt <= 10000, return 10000;);
+       
+       return mtt;
+}
+
 #endif
+
+
index 470a9477be5a7d730980269b954d8e2ffeaebf35..071ed8561b0c4ea225e0e12f03d20686f9fca716 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Mon Mar 22 13:15:04 1999
+ * Modified at:   Wed Apr 21 16:37:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
 #define IAS_SUCCESS        0
 #define IAS_CLASS_UNKNOWN  1
 #define IAS_ATTRIB_UNKNOWN 2
+#define IAS_DISCONNECT     10
 
-typedef void (*CONFIRM_CALLBACK)( __u16 obj_id, struct ias_value *value,
-                                 void *priv);
+typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id, 
+                                struct ias_value *value, void *priv);
 
 struct iriap_cb {
        QUEUE queue; /* Must be first */
diff --git a/include/net/irda/irkbd.h b/include/net/irda/irkbd.h
deleted file mode 100644 (file)
index 819df24..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irkbd.h
- * Version:       0.2
- * Description:   IrDA Keyboard/Mouse driver (Tekram IR-660)
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Mon Mar  1 00:24:19 1999
- * Modified at:   Thu Mar 11 14:54:00 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- *      
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IRKBD_H
-#define IRKBD_H
-
-/* Some commands */
-#define IRKBD_CMD_INIT_KBD   0xfe
-#define IRKBD_CMD_INIT_MOUSE 0xff
-#define IRKBD_CMD_ENABLE     0x41
-#define IRKBD_CMD_LED        0x31
-#define IRKBD_CMD_KDB_SPEED  0x33
-
-/* Some responses */
-#define IRKBD_RSP_KBDOK      0x11
-#define IRKBD_RSP_KBDERR     0x12
-#define IRKBD_RSP_MSOK       0x21
-#define IRKBD_RSP_MSERR      0x22
-#define IRKBD_RSP_LEDOK      0x31
-#define IRKBD_RSP_KBDSPEEDOK 0x33
-#define IRKBD_RSP_RSPN41     0x41
-
-#define IRKBD_RATE       2 /* Polling rate, should be 15 ms */
-#define IRKBD_TIMEOUT  100 /* 1000 ms */
-
-#define SUBFRAME_MASK     0xc0
-#define SUBFRAME_MOUSE    0x80
-#define SUBFRAME_KEYBOARD 0x40
-#define SUBFRAME_RESPONSE 0x00
-
-#define IRKBD_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
-
-#define IRKBD_BUF_SIZE 4096 /* Must be power of 2! */
-
-enum {
-       IRKBD_IDLE,       /* Not connected */
-       IRKBD_INIT_KBD,   /* Initializing keyboard */
-       IRKBD_INIT_MOUSE, /* Initializing mouse */
-       IRKBD_POLLING,    /* Polling device */
-};
-
-/* Main structure */
-struct irkbd_cb {
-       struct miscdevice dev;
-       char devname[9];    /* name of the registered device */
-       int state;
-
-       int count;          /* Open count */
-
-       __u32 saddr;        /* my local address */
-       __u32 daddr;        /* peer address */
-
-       struct tsap_cb *tsap;           
-       __u8 dtsap_sel;     /* remote TSAP address */
-       __u8 stsap_sel;     /* local TSAP address */
-
-       struct timer_list watchdog_timer;
-
-       LOCAL_FLOW tx_flow;
-       LOCAL_FLOW rx_flow;
-
-       __u8 scancodes[IRKBD_BUF_SIZE]; /* Buffer for mouse events */
-       int head;
-       int tail;
-
-       struct wait_queue *read_wait;
-       struct fasync_struct *async;
-};
-
-#endif /* IRKBD_H */
index a2d65155712da2ee6e70f5b3d3ef60157fe5dfee..62ea6157a7085e88e37200538988f7bdc9e50881 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Feb 25 21:05:53 1999
+ * Modified at:   Thu Apr 22 14:13:34 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -30,6 +30,7 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 
+#include <net/irda/irias_object.h>
 #include <net/irda/irlan_event.h>
 
 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
@@ -38,7 +39,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr);
 
 void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
 
-void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb);
-void irlan_client_get_value_confirm( __u16 obj_id, struct ias_value *value
-                                    void *priv);
+void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb);
+void irlan_client_get_value_confirm(int result, __u16 obj_id
+                                   struct ias_value *value, void *priv);
 #endif
index f3103628e4c70e2dd52392898ff75dac27b2a76c..35d83096faf55907a468b02fc6b0da13727373ab 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Tue Apr  6 16:19:41 1999
+ * Modified at:   Thu Apr 22 14:30:37 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -121,7 +121,6 @@ struct irlan_client_cb {
        int broadcast_open;
 
        struct timer_list kick_timer;
-       int start_new_provider;
 };
 
 /*
@@ -183,6 +182,10 @@ struct irlan_cb {
 
 struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev);
 void irlan_close(struct irlan_cb *self);
+void irlan_close_tsaps(struct irlan_cb *self);
+void irlan_mod_inc_use_count(void);
+void irlan_mod_dec_use_count(void);
+
 int  irlan_register_netdev(struct irlan_cb *self);
 void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel);
 void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout);
@@ -204,7 +207,7 @@ int irlan_insert_string_param(struct sk_buff *skb, char *param, char *value);
 int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value, 
                             __u16 value_len);
 
-int irlan_get_param(__u8 *buf, char *name, char *value, __u16 *len);
+int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len);
 void print_ret_code(__u8 code);
 
 extern hashbin_t *irlan;
index 257a719f460396397133ebfdc999f231557ab186..6ad33ee48982e7c86969a19687a0471668cd1e72 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:36:58 1998
- * Modified at:   Mon Mar 22 12:57:11 1999
+ * Modified at:   Thu Apr 22 14:09:37 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -25,6 +25,9 @@
 #ifndef IRLAN_ETH_H
 #define IRLAN_ETH_H
 
+int  irlan_eth_init(struct device *dev);
+int  irlan_eth_open(struct device *dev);
+int  irlan_eth_close(struct device *dev);
 int  irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb);
 int  irlan_eth_xmit(struct sk_buff *skb, struct device *dev);
 
index 05b6736173eaeaffe766385608498342c7c4bd8e..aafbf9141245192ae45f5522e268c12bf05c3c99 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Mon Mar  8 15:32:35 1999
+ * Modified at:   Thu Apr 22 14:29:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -46,12 +46,12 @@ void irlan_provider_connect_indication(void *instance, void *sap,
 void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *);
 
 int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb);
-int irlan_provider_extract_params(struct irlan_cb *self, int cmd,
-                                 struct sk_buff *skb);
+int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
+                                struct sk_buff *skb);
 
 void irlan_provider_send_reply(struct irlan_cb *self, int command, 
                               int ret_code);
-void irlan_provider_open_ctrl_tsap( struct irlan_cb *self);
+int irlan_provider_open_ctrl_tsap(struct irlan_cb *self);
 
 #endif
 
index 1de71bfd118be2da7cda3a599062713d2a4b6976..f3b26110f646efbc3114ab7128c13548a0575540 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Mar 26 15:15:17 1999
+ * Modified at:   Fri Apr 23 09:51:15 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -219,12 +219,12 @@ int irlap_validate_ns_received( struct irlap_cb *, int ns);
 
 int  irlap_generate_rand_time_slot( int S, int s);
 void irlap_initiate_connection_state( struct irlap_cb *);
-void irlap_flush_all_queues( struct irlap_cb *);
-void irlap_change_speed( struct irlap_cb *, int);
-void irlap_wait_min_turn_around( struct irlap_cb *, struct qos_info *);
+void irlap_flush_all_queues(struct irlap_cb *);
+void irlap_change_speed(struct irlap_cb *, int);
+void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *);
 
-void irlap_init_qos_capabilities( struct irlap_cb *, struct qos_info *);
-void irlap_apply_default_connection_parameters( struct irlap_cb *self);
-void irlap_apply_connection_parameters( struct irlap_cb *, struct qos_info *);
+void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
+void irlap_apply_default_connection_parameters(struct irlap_cb *self);
+void irlap_apply_connection_parameters(struct irlap_cb *, struct qos_info *);
 
 #endif
index 7db0825f7d76c71506e132ece351920a1690abd2..7425b41b4cf42936cb2b2eccecbdb915d19d97c8 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Fri Mar 26 14:10:53 1999
+ * Modified at:   Fri Apr 23 09:33:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -117,8 +117,6 @@ struct irlap_skb_cb {
        int vr;    /* next frame to receive */
 };
 
-__inline__ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb);
-
 void irlap_send_discovery_xid_frame( struct irlap_cb *, int S, __u8 s, 
                                     __u8 command, discovery_t *discovery);
 void irlap_send_snrm_frame( struct irlap_cb *, struct qos_info *);
index b5c9daae41c8d5cc258bcbf25833b93ba982996a..31785883a584b6c92947f9c749403e46bb64a2d8 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Tue Apr  6 20:05:14 1999
+ * Modified at:   Fri Apr 23 09:15:07 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -202,12 +202,12 @@ int irlmp_update_client(__u32 handle, __u16 hint_mask,
 void irlmp_register_link(struct irlap_cb *, __u32 saddr, struct notify_t *);
 void irlmp_unregister_link(__u32 saddr);
 
-int  irlmp_connect_request( struct lsap_cb *, __u8 dlsap_sel, 
-                           __u32 saddr, __u32 daddr,
-                           struct qos_info *, struct sk_buff *);
-void irlmp_connect_indication( struct lsap_cb *self, struct sk_buff *skb);
-void irlmp_connect_response( struct lsap_cb *, struct sk_buff *);
-void irlmp_connect_confirm( struct lsap_cb *, struct sk_buff *);
+int  irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, 
+                          __u32 saddr, __u32 daddr,
+                          struct qos_info *, struct sk_buff *);
+void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb);
+void irlmp_connect_response(struct lsap_cb *, struct sk_buff *);
+void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *);
 struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance);
 
 void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, 
@@ -219,17 +219,17 @@ void irlmp_discovery_request(int nslots);
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
 
-void irlmp_data_request( struct lsap_cb *, struct sk_buff *);
-void irlmp_udata_request( struct lsap_cb *, struct sk_buff *);
-void irlmp_data_indication( struct lsap_cb *, struct sk_buff *);
-void irlmp_udata_indication( struct lsap_cb *, struct sk_buff *);
+void irlmp_data_request(struct lsap_cb *, struct sk_buff *);
+inline void irlmp_udata_request(struct lsap_cb *, struct sk_buff *);
+inline void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
+inline void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *);
 
 void irlmp_status_request(void);
-void irlmp_status_indication( LINK_STATUS link, LOCK_STATUS lock);
+void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock);
 
-int  irlmp_slsap_inuse( __u8 slsap);
+int  irlmp_slsap_inuse(__u8 slsap);
 __u8 irlmp_find_free_slsap(void);
-LM_REASON irlmp_convert_lap_reason( LAP_REASON);
+LM_REASON irlmp_convert_lap_reason(LAP_REASON);
 
 __u32 irlmp_get_saddr(struct lsap_cb *self);
 __u32 irlmp_get_daddr(struct lsap_cb *self);
index cd0807dd2a846f1646f05c72355804c74edf4a35..ab3178885e82a8ff6fda65081978122463949378 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Mon Jan 11 15:58:16 1999
+ * Modified at:   Wed Apr 21 16:46:26 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>
@@ -34,7 +34,7 @@
  * if it's static, it doesn't go in here.
  */
 
-void irlpt_client_get_value_confirm(__u16 obj_id, 
+void irlpt_client_get_value_confirm(int result, __u16 obj_id, 
                                    struct ias_value *value, 
                                    void *priv);
 void irlpt_client_connect_indication( void *instance, 
index 4605b1b7799ae655adc780b8f6c4a00aa1f00ce2..651e87dbcca0626118b8ea94829602fa7540a0c1 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:58:52 1997
- * Modified at:   Tue Mar 16 22:27:41 1999
+ * Modified at:   Fri Apr  9 11:13:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -101,7 +101,22 @@ struct irda_cb {
 int irmod_init_module(void);
 void irmod_cleanup_module(void);
 
-inline int irda_lock(int *lock);
+/*
+ * Function irda_lock (lock)
+ *
+ *    Lock variable. Returns false if the lock is already set.
+ *    
+ */
+static inline int irda_lock(int *lock) 
+{
+       if (test_and_set_bit( 0, (void *) lock))  {
+               DEBUG(3, __FUNCTION__ 
+                     "(), Trying to lock, already locked variable!\n");
+               return FALSE;
+        }  
+       return TRUE;
+}
+
 inline int irda_unlock(int *lock);
 
 void irda_notify_init(struct notify_t *notify);
diff --git a/include/net/irda/irobex.h b/include/net/irda/irobex.h
deleted file mode 100644 (file)
index 0a5adcf..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irobex.h
- * Version:       0.8
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Jul  4 22:43:57 1998
- * Modified at:   Thu Mar 11 16:11:54 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
- *      
- *     This program is free software; you can redistribute it and/or 
- *     modify it under the terms of the GNU General Public License as 
- *     published by the Free Software Foundation; either version 2 of 
- *     the License, or (at your option) any later version.
- *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IROBEX_H
-#define IROBEX_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/miscdevice.h>
-
-#include <net/irda/timer.h>
-#include <net/irda/qos.h>
-#include <net/irda/irmod.h>
-
-#define LOW_THRESHOLD      4
-#define HIGH_THRESHOLD     8
-#define IROBEX_MAX_QUEUE  12
-
-/* Small structure to be used by the IOCTL call */
-struct irobex_ioc_t {
-     __u32 daddr;
-};
-
-#define IROBEX_IOC_MAGIC 'k'
-
-#define IROBEX_IOCSCONNECT    _IOW(IROBEX_IOC_MAGIC, 1, 4)
-#define IROBEX_IOCSDISCONNECT _IOW(IROBEX_IOC_MAGIC, 2, 4)
-#define IROBEX_IOC_MAXNR 2
-
-#define IROBEX_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
-
-typedef enum {
-       OBEX_IDLE,       /* Doing nothing */
-       OBEX_DISCOVER,   /* Trying to discovery remote device */
-       OBEX_QUERY,      /* Querying remote LM-IAS */
-       OBEX_CONN,       /* Trying to connect to remote device */
-       OBEX_DATA,       /* Data transfer ready */
-} OBEX_STATE;
-
-struct irobex_cb {
-       QUEUE queue;        /* Must be first! */
-
-        int magic;          /* magic used to detect corruption of the struct */
-
-       OBEX_STATE state;   /* Current state */
-
-       __u32 saddr;        /* my local address */
-       __u32 daddr;        /* peer address */
-       unsigned long time_discovered;
-
-       __u32 ckey;           /* IrLMP client handle */
-       __u32 skey;           /* IrLMP service handle */
-
-        char devname[9];    /* name of the registered device */
-       struct tsap_cb *tsap;
-       int eof;
-
-       __u8 dtsap_sel;         /* remote TSAP address */
-       __u8 stsap_sel;         /* local TSAP address */
-
-       int irlap_data_size;
-
-       struct miscdevice dev;
-
-       int count;                /* open count */
-
-       struct sk_buff_head rx_queue; /* Receive queue */
-
-       struct wait_queue *read_wait;
-       struct wait_queue *write_wait;
-
-       struct fasync_struct *async;
-
-       struct timer_list watchdog_timer;
-
-       LOCAL_FLOW tx_flow;
-       LOCAL_FLOW rx_flow;
-};
-
-int irobex_init(void);
-
-void irobex_watchdog_timer_expired( unsigned long data);
-
-inline void irobex_start_watchdog_timer( struct irobex_cb *self, int timeout) 
-{
-       irda_start_timer( &self->watchdog_timer, timeout, (unsigned long) self,
-                         irobex_watchdog_timer_expired);
-}
-
-extern struct irobex_cb *irobex;
-
-#endif
index 78fab8a88447c053d97b3d67a8607be4473232a0..aec1d57dc15738e09be0a111bbf7158a2ec255d0 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon Mar 22 13:17:30 1999
+ * Modified at:   Sat Apr 10 10:19:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -93,7 +93,7 @@ struct tsap_cb {
        __u32 rx_max_sdu_size; /* Max receive user data size */
 
        int tx_sdu_busy;       /* TxSdu.busy */
-       int tx_max_sdu_size;   /* Max transmit user data size */
+       __u32 tx_max_sdu_size; /* Max transmit user data size */
 
        int close_pend;        /* Close, but disconnect_pend */
        int disconnect_pend;   /* Disconnect, but still data to send */
index 81d01003ffd7a6a8224b83420c83041fc91332c9..5128e512bd1150b4ac4164079ab3016c8ba52363 100644 (file)
@@ -184,6 +184,7 @@ extern void eata2x_setup(char *str, int *ints);
 extern void u14_34f_setup(char *str, int *ints);
 extern void fdomain_setup(char *str, int *ints);
 extern void ibmmca_scsi_setup(char *str, int *ints);
+extern void fd_mcs_setup(char *str, int *ints);
 extern void in2000_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
 extern void sym53c416_setup(char *str, int *ints);
@@ -709,6 +710,9 @@ static struct kernel_param cooked_params[] __initdata = {
 #ifdef CONFIG_SCSI_IBMMCA
         { "ibmmcascsi=", ibmmca_scsi_setup },
 #endif
+#ifdef CONFIG_SCSI_FD_MCS
+       { "fd_mcs=", fd_mcs_setup },
+#endif
 #if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP)
         { "tmscsim=", dc390_setup },
 #endif
index a8f77970efb055d5d6f5eb8e64e8f04c8af5f02b..9047eaa49108bf1df0534f39edf5231b98e2917a 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/trdevice.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/net.h>
 #include <linux/proc_fs.h>
@@ -68,6 +67,8 @@ struct rif_cache_s {
  
 rif_cache rif_table[RIF_TABLE_SIZE]={ NULL, };
 
+static spinlock_t rif_lock = SPIN_LOCK_UNLOCKED;
+
 #define RIF_TIMEOUT 60*10*HZ
 #define RIF_CHECK_INTERVAL 60*HZ
 
@@ -230,6 +231,9 @@ static void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct devic
        unsigned int hash;
        rif_cache entry;
        unsigned char *olddata;
+       unsigned long flags;
+       
+       spin_lock_irqsave(&rif_lock, flags);
 
        /*
         *      Broadcasts are single route as stated in RFC 1042 
@@ -298,6 +302,8 @@ printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0],
        else 
                slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
        olddata = skb->data;
+       spin_unlock_irqrestore(&rif_lock, flags);
+
        skb_pull(skb, slack);
        memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack);
 }
@@ -312,7 +318,11 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct device *dev)
        int i;
        unsigned int hash, rii_p = 0;
        rif_cache entry;
+       unsigned long flags;
+
 
+       spin_lock_irqsave(&rif_lock, flags);
+       
        /*
         *      Firstly see if the entry exists
         */
@@ -350,6 +360,7 @@ printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
                if(!entry) 
                {
                        printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
+                       spin_unlock_irqrestore(&rif_lock, flags);
                        return;
                }
 
@@ -391,6 +402,7 @@ printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
                    }                                         
                entry->last_used=jiffies;               
        }
+       spin_unlock_irqrestore(&rif_lock, flags);
 }
 
 /*
@@ -402,9 +414,8 @@ static void rif_check_expire(unsigned long dummy)
        int i;
        unsigned long now=jiffies,flags;
 
-       save_flags(flags);
-       cli();
-
+       spin_lock_irqsave(&rif_lock, flags);
+       
        for(i=0; i < RIF_TABLE_SIZE;i++) 
        {
                rif_cache entry, *pentry=rif_table+i;   
@@ -422,7 +433,8 @@ static void rif_check_expire(unsigned long dummy)
                                pentry=&entry->next;
                }
        }
-       restore_flags(flags);
+       
+       spin_unlock_irqrestore(&rif_lock, flags);
 
        /*
         *      Reset the timer
index 180701ad2463e86cf745c7adff82fb785e0eed87..6dd1180248717c7ff94630836889f02927f400bc 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Wed Apr  7 17:32:27 1999
+ * Modified at:   Thu Apr 22 12:08:04 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
  * 
@@ -39,6 +39,7 @@
 #include <net/irda/iriap.h>
 #include <net/irda/irias_object.h>
 #include <net/irda/irttp.h>
+#include <net/irda/discovery.h>
 
 extern int  irda_init(void);
 extern void irda_cleanup(void);
@@ -237,8 +238,8 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
  *    Got answer from remote LM-IAS
  *
  */
-static void irda_get_value_confirm(__u16 obj_id, struct ias_value *value
-                                  void *priv)
+static void irda_get_value_confirm(int result, __u16 obj_id
+                                  struct ias_value *value, void *priv)
 {
        struct irda_sock *self;
        
@@ -251,11 +252,14 @@ static void irda_get_value_confirm(__u16 obj_id, struct ias_value *value,
                return;
 
        /* Check if request succeeded */
-       if (!value) {
+       if (result != IAS_SUCCESS) {
                DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
 
+               self->errno = result;
+
                /* Wake up any processes waiting for result */
                wake_up_interruptible(&self->ias_wait);
+
                return;
        }
 
@@ -673,7 +677,7 @@ static int irda_create(struct socket *sock, int protocol)
        self->mask = 0xffff;
        self->rx_flow = self->tx_flow = FLOW_START;
        self->max_sdu_size_rx = SAR_DISABLE; /* Default value */
-       self->nslots = 6; /* Default for now */
+       self->nslots = DISCOVERY_DEFAULT_SLOTS;
 
        /* Notify that we are using the irda module, so nobody removes it */
        irda_mod_inc_use_count();
@@ -857,6 +861,12 @@ static int irda_recvmsg(struct socket *sock, struct msghdr *msg, int size,
        return copied;
 }
 
+/*
+ * Function irda_shutdown (sk, how)
+ *
+ *    
+ *
+ */
 static int irda_shutdown( struct socket *sk, int how)
 {
        DEBUG( 0, __FUNCTION__ "()\n");
@@ -866,6 +876,12 @@ static int irda_shutdown( struct socket *sk, int how)
 }
 
 
+/*
+ * Function irda_poll (file, sock, wait)
+ *
+ *    
+ *
+ */
 unsigned int irda_poll(struct file *file, struct socket *sock, 
                       struct poll_table_struct *wait)
 {
index f6561db8b301bbb17160d0a7a01f6fbe6ea6d95b..22def3a1e89cf10f781dca998435988ce0e7de04 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 15:33:50 1999
- * Modified at:   Tue Apr  6 20:26:46 1999
+ * Modified at:   Sun Apr 11 00:41:58 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -46,7 +46,7 @@ void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery)
 {
        discovery_t *old;
 
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        /* Check if we have discovered this device before */
        old = hashbin_remove(cachelog, discovery->daddr, NULL);
@@ -67,7 +67,7 @@ void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log)
 {
        discovery_t *discovery;
 
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        /*
         *  If log is missing this means that IrLAP was unable to perform the
@@ -100,7 +100,7 @@ void irlmp_expire_discoveries(hashbin_t *log, int saddr, int force)
 {
        discovery_t *discovery, *curr;
 
-       DEBUG(3, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
        discovery = (discovery_t *) hashbin_get_first(log);
        while (discovery != NULL) {
index 5796ced173abaf35a9171a8958d2abceab11e911..c7e805242b83585b4fcb0e629fc952b0076c20b4 100644 (file)
 
 #include <net/irda/ircomm_common.h>
 
-static char *revision_date = "Tue Mar  2 02:03:58 1999";
+static char *revision_date = "Sun Apr 18 00:40:19 1999";
 
 
-static void ircomm_state_discovery(struct ircomm_cb *self,
-                                  IRCOMM_EVENT event, struct sk_buff *skb );
 static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, 
                               struct sk_buff *skb );
+
+static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+                                       struct sk_buff *skb );
+
+static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+                                        struct sk_buff *skb );
+
+static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+                                       struct sk_buff *skb );
+
 static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event, 
                                struct sk_buff *skb );
 static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event, 
@@ -63,13 +71,14 @@ static void ircomm_tx_controlchannel(struct ircomm_cb *self );
 static int ircomm_proc_read(char *buf, char **start, off_t offset,
                            int len, int unused);
 
+static void start_discovering(struct ircomm_cb *self);
 static void query_lsapsel(struct ircomm_cb * self);
-static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value, 
-                                    void *priv);
+static void query_parameters(struct ircomm_cb *self);
+static void queryias_done(struct ircomm_cb *self);
+static void ircomm_getvalue_confirm(int result, __u16 obj_id, 
+                                   struct ias_value *value, void *priv);
 
 
-static __u32 ckey;
-static __u32 skey;
 struct ircomm_cb *discovering_instance;
 
 /*
@@ -86,8 +95,12 @@ MODULE_PARM(ircomm_cs, "i");
 
 
 static char *ircommstate[] = {
-       "DISCOVERY",
        "IDLE",
+
+       "DISCOVERY_WAIT",
+       "QUERYPARAM_WAIT",
+       "QUERYLSAP_WAIT",
+
        "WAITI",
        "WAITR",
        "CONN",
@@ -126,6 +139,11 @@ static char *ircommevent[] = {
        "IRCOMM_DATA_REQUEST",
        "LMP_DATA_INDICATION",
        "IRCOMM_CONTROL_REQUEST",
+
+       "DISCOVERY_INDICATION",
+       "GOT_PARAMETERS",
+       "GOT_LSAPSEL",
+       "QUERYIAS_ERROR",
 };
 
 #ifdef CONFIG_PROC_FS
@@ -141,8 +159,12 @@ struct proc_dir_entry proc_ircomm = {
 static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
                        struct sk_buff *skb) = 
 {
-       ircomm_state_discovery,
        ircomm_state_idle,
+
+       ircomm_state_discoverywait,
+       ircomm_state_queryparamwait,
+       ircomm_state_querylsapwait,
+
        ircomm_state_waiti,
        ircomm_state_waitr,
        ircomm_state_conn,
@@ -376,6 +398,146 @@ static void ircomm_accept_flow_indication( void *instance, void *sap,
 
 }
 
+
+/*
+ * ircomm_discovery_indication()
+ *    Remote device is discovered, try query the remote IAS to see which
+ *    device it is, and which services it has.
+ */
+
+static void ircomm_discovery_indication(discovery_t *discovery)
+{
+       struct ircomm_cb *self;
+
+       self = discovering_instance;
+       if(self == NULL)
+               return;
+       ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+       self->daddr = discovery->daddr;
+       self->saddr = discovery->saddr;
+
+       DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
+
+       ircomm_do_event(self, DISCOVERY_INDICATION, NULL);
+       return;
+}
+
+/*
+ * ircomm_getvalue_confirm()
+ * handler for iriap_getvaluebyclass_request() 
+ */
+static void ircomm_getvalue_confirm(int result, __u16 obj_id, 
+                                   struct ias_value *value, void *priv)
+{
+       struct ircomm_cb *self = (struct ircomm_cb *) priv;
+       struct sk_buff *skb= NULL;
+       __u8 *frame;
+       __u8 servicetype = 0 ;
+       ASSERT( self != NULL, return;);
+       ASSERT( self->magic == IRCOMM_MAGIC, return;);
+
+       /* Check if request succeeded */
+       if (result != IAS_SUCCESS) {
+               DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
+               ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+               return;
+       }
+
+       DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
+
+       self->ias_type = value->type;
+       switch(value->type){
+       case IAS_OCT_SEQ:
+               
+               DEBUG(4, __FUNCTION__"():got octet sequence:\n");
+#if 0
+               {
+                       int i;
+                       for ( i=0;i<value->len;i++)
+                               printk("%02x",
+                                      (__u8)(*(value->t.oct_seq + i)));
+                       printk("\n");
+               }
+#endif
+               skb = dev_alloc_skb((value->len) + 2);
+               ASSERT(skb != NULL, ircomm_do_event(self, QUERYIAS_ERROR, NULL);return;);
+               frame = skb_put(skb,2);
+               /* MSB first */
+               frame[0] = ( value->len >> 8 ) & 0xff;
+               frame[1] = value->len & 0xff;
+               
+               frame = skb_put(skb,value->len);
+               memcpy(frame, value->t.oct_seq, value->len);
+               ircomm_parse_tuples(self, skb, IAS_PARAM);
+               kfree_skb(skb);
+
+               /* 
+                * check if servicetype we want is available 
+                */
+
+               DEBUG(0,__FUNCTION__"():peer capability is:\n");
+               DEBUG(0,"3wire raw: %s\n",
+                     ((self->peer_servicetype & THREE_WIRE_RAW) ? "yes":"no"));
+               DEBUG(0,"3wire    : %s\n",
+                     ((self->peer_servicetype & THREE_WIRE) ? "yes":"no"));
+               DEBUG(0,"9wire    : %s\n",
+                     ((self->peer_servicetype & NINE_WIRE) ? "yes":"no"));
+               DEBUG(0,"IEEE1284 : %s\n",
+                     ((self->peer_servicetype & CENTRONICS) ? "yes":"no"));
+
+               self->servicetype &= self->peer_servicetype;
+               if(!(self->servicetype)){
+                       DEBUG(0,__FUNCTION__"(): servicetype mismatch!\n");
+                       ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+                       break;
+               }
+
+               /*
+                * then choose better one 
+                */
+               if(self->servicetype & THREE_WIRE_RAW)
+                       servicetype = THREE_WIRE_RAW;
+               if(self->servicetype & THREE_WIRE)
+                       servicetype = THREE_WIRE;
+               if(self->servicetype & NINE_WIRE)
+                       servicetype = NINE_WIRE;
+               if(self->servicetype & CENTRONICS)
+                       servicetype = CENTRONICS;
+
+               self->servicetype = servicetype;
+
+               /* enter next state */
+               ircomm_do_event(self, GOT_PARAMETERS, NULL);
+               break;
+
+       case IAS_INTEGER:
+               /* LsapSel seems to be sent to me */    
+               DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
+
+               if ( value->t.integer == -1){
+                       DEBUG( 0, __FUNCTION__"():invalid value!\n");
+                       ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+                       return;
+               }
+               self->dlsap = value->t.integer;
+               ircomm_do_event(self, GOT_LSAPSEL, NULL);
+               break;
+
+       case IAS_MISSING:
+               DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
+               ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+               break;
+   
+       default:
+               DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
+               ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+               break;
+       }
+}
+
+
+
 /* 
  * ----------------------------------------------------------------------
  * Impl. of actions (descrived in section 7.4 of the reference)
@@ -583,19 +745,6 @@ static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state)
 }
 
 
-/* 
- * we currently need dummy (discovering) state for debugging,
- * which state is not defined in the reference.
- */
-
-static void ircomm_state_discovery( struct ircomm_cb *self,
-                                   IRCOMM_EVENT event, struct sk_buff *skb )
-{
-       printk(KERN_ERR __FUNCTION__"():why call me? something is wrong..\n");
-       if(skb)
-               dev_kfree_skb( skb);
-}
-
 
 /*
  * ircomm_state_idle
@@ -607,8 +756,11 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
        switch(event){
        case IRCOMM_CONNECT_REQUEST:
 
-               ircomm_next_state(self, COMM_WAITI);
-               issue_connect_request( self, skb );
+               /* ircomm_next_state(self, COMM_WAITI); */
+               /* issue_connect_request( self, skb ); */
+
+               ircomm_next_state(self, COMM_DISCOVERY_WAIT);
+               start_discovering(self);
                break;
                
        case TTP_CONNECT_INDICATION:
@@ -630,6 +782,121 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event,
        }
 }
 
+/*
+ * ircomm_state_discoverywait
+ */
+static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+                                      struct sk_buff *skb )
+{
+       switch(event){
+
+       case TTP_CONNECT_INDICATION:
+
+               ircomm_next_state(self, COMM_WAITR);
+               queryias_done(self);
+               connect_indication( self, self->qos, skb);
+               break;
+
+       case DISCOVERY_INDICATION:
+               ircomm_next_state(self, COMM_QUERYPARAM_WAIT);
+               query_parameters(self);
+               break;
+
+       case IRCOMM_DISCONNECT_REQUEST:
+               ircomm_next_state(self, COMM_IDLE);
+               queryias_done(self);
+               break;
+
+       case QUERYIAS_ERROR:
+               ircomm_next_state(self, COMM_IDLE);
+               disconnect_indication(self, NULL);
+               queryias_done(self);
+               break;
+
+       default:
+               DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+                     event, ircommevent[event]);
+       }
+}
+
+/*
+ * ircomm_state_queryparamwait
+ */
+
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+                                       struct sk_buff *skb )
+{
+       switch(event){
+
+       case TTP_CONNECT_INDICATION:
+
+               ircomm_next_state(self, COMM_WAITR);
+               connect_indication( self, self->qos, skb);
+               break;
+
+       case GOT_PARAMETERS:
+               
+               ircomm_next_state(self, COMM_QUERYLSAP_WAIT);
+               query_lsapsel( self );
+               break;
+
+       case IRCOMM_DISCONNECT_REQUEST:
+               ircomm_next_state(self, COMM_IDLE);
+               queryias_done(self);
+               break;
+
+       case QUERYIAS_ERROR:
+               ircomm_next_state(self, COMM_IDLE);
+               disconnect_indication(self, NULL);
+               queryias_done(self);
+               break;
+
+       default:
+               DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+                     event, ircommevent[event]);
+       }
+}
+
+/*
+ * ircomm_state_querylsapwait
+ */
+
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+                                      struct sk_buff *skb )
+{
+       switch(event){
+
+       case TTP_CONNECT_INDICATION:
+
+               ircomm_next_state(self, COMM_WAITR);
+               connect_indication( self, self->qos, skb);
+               break;
+
+       case GOT_LSAPSEL:
+               
+               ircomm_next_state(self, COMM_WAITI);
+               queryias_done(self);
+               issue_connect_request( self, skb );
+               break;
+
+       case IRCOMM_DISCONNECT_REQUEST:
+               ircomm_next_state(self, COMM_IDLE);
+               queryias_done(self);
+               break;
+
+       case QUERYIAS_ERROR:
+               ircomm_next_state(self, COMM_IDLE);
+               disconnect_indication(self, NULL);
+               queryias_done(self);
+               break;
+
+
+       default:
+               DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+                     event, ircommevent[event]);
+       }
+}
+
 /*
  * ircomm_state_waiti
  */
@@ -688,6 +955,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
        case IRCOMM_DISCONNECT_REQUEST:
                ircomm_next_state(self, COMM_IDLE);
                issue_disconnect_request(self, skb);
+               queryias_done(self);
                break;
 
        case TTP_DISCONNECT_INDICATION:
@@ -695,6 +963,19 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event,
                disconnect_indication(self, skb);
                break;
 
+       case DISCOVERY_INDICATION:
+               DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+               queryias_done(self);
+               break;
+       case GOT_PARAMETERS:
+               DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+               queryias_done(self);
+               break;
+       case GOT_LSAPSEL:
+               DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+               queryias_done(self);
+               break;
+
 /*     case LMP_DISCONNECT_INDICATION: */
 /*             disconnect_indication();                 */
 /*             ircomm_next_state(self, COMM_IDLE);              */
@@ -732,11 +1013,26 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
        case IRCOMM_DISCONNECT_REQUEST:
                ircomm_next_state(self, COMM_IDLE);
                issue_disconnect_request(self, skb);
+               queryias_done(self);
                break;
 /*     case LM_DISCONNECT_INDICATION: */
 /*             disconnect_indication(); */
 /*             ircomm_next_state(self, COMM_IDLE); */
 /*             break; */
+
+       case DISCOVERY_INDICATION:
+               DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+               queryias_done(self);
+               break;
+       case GOT_PARAMETERS:
+               DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+               queryias_done(self);
+               break;
+       case GOT_LSAPSEL:
+               DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+               queryias_done(self);
+               break;
+
        default:
                DEBUG(0,"ircomm_state_conn:unknown event =%d(%s)\n",
                      event, ircommevent[event]);
@@ -744,6 +1040,7 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
 }
 
 
+
 /*
  *  ----------------------------------------------------------------------
  *  IrCOMM service interfaces and supporting functions
@@ -751,172 +1048,97 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event,
  *  ----------------------------------------------------------------------
  */
 
-int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype)
-{
-       int retval=0;
-       __u16 hints;
-
-       ASSERT( self != NULL, return -EFAULT;);
-       ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;);
-       DEBUG(4,__FUNCTION__"():servicetype = %d\n",servicetype);
+/* 
+ * start_discovering()
+ *
+ * start discovering and enter DISCOVERY_WAIT state
+ */
 
-       /*
-        * wait if another instance is discovering now
-        */  
-       if(discovering_instance){
-               interruptible_sleep_on( &self->discovery_wait);
-               if(signal_pending(current)){
-                       return -EINTR; /* cought a signal */
-               }
-               if(self->state == COMM_CONN)
-                       return 0;  /* got connected */
-       }
-       ASSERT(discovering_instance == NULL, return -EFAULT;);
-       discovering_instance = self;
+static void start_discovering(struct ircomm_cb *self)
+{
+       __u16  hints; 
+       ASSERT( self != NULL, return;);
+       ASSERT( self->magic == IRCOMM_MAGIC, return;);
+       DEBUG(4,__FUNCTION__"():servicetype = %d\n",self->servicetype);
        
-       /*
-        * start discovering
-        */
+
        hints = irlmp_service_to_hint(S_COMM);
 
        DEBUG(0,__FUNCTION__"():start discovering..\n");
        switch (ircomm_cs) {
        case 0:
-               skey = irlmp_register_service(hints);
-               ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+               MOD_INC_USE_COUNT;
+               self->queryias_lock = 1;
+               discovering_instance = self;
+               self->skey = irlmp_register_service(hints);
+               self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
                                             NULL);
                break;
                
        case 1:    /* client only */
+               MOD_INC_USE_COUNT;
+               self->queryias_lock = 1;
+               discovering_instance = self;
                DEBUG( 0, __FUNCTION__"():client only mode\n");
-               ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+               self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
                                             NULL);
                break;
 
        case 2:     /*  server only  */
        default:
                DEBUG( 0, __FUNCTION__"():server only mode\n");
-               skey = irlmp_register_service(hints);
+               self->skey = irlmp_register_service(hints);
                discovering_instance = NULL;
-               return 0;
+               break;
        }
+       
+       return;
+}
 
+/*
+ * queryias_done(self)
+ *
+ * called when discovery process got wrong results, completed, or terminated.
+ */
 
-       /*
-        * waiting for discovery
-        */
-       interruptible_sleep_on( &self->discovery_wait);
-       if(signal_pending(current)){
-               retval = -EINTR; goto bailout; /* cought a signal */
+static void queryias_done(struct ircomm_cb *self)
+{
+       DEBUG(0, __FUNCTION__"():\n");
+       if(self->queryias_lock){
+               self->queryias_lock = 0;
+               discovering_instance = NULL;
+               MOD_DEC_USE_COUNT;
+               irlmp_unregister_client(self->ckey);
        }
-       if(self->state == COMM_CONN)
-               goto bailout;     /* got connected */
+       if(ircomm_cs != 1)
+               irlmp_unregister_service(self->skey);
+       return;
+}
 
-       /*
-        * query Parameters field of IAS and waiting for answer
-        */
 
-       self->servicetype = 0;
+
+static void query_parameters(struct ircomm_cb *self)
+{
+
        DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n");
        iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters",
                                       self->saddr, self->daddr,
                                       ircomm_getvalue_confirm, self );
-
-       interruptible_sleep_on( &self->ias_wait);
-       if(signal_pending(current)){
-               retval = -EINTR; goto bailout; /* cought a signal */
-       }
-       if(self->state == COMM_CONN)
-               goto bailout;     /* got connected */
+}
 
 
-       /* really got Parameters field? */
-       if(self->ias_type != IAS_OCT_SEQ){
-               retval = -EFAULT;
-               goto bailout;
-       }
-
-       /* 
-        * check if servicetype we want is available 
-        */
-       self->peer_cap = self->servicetype;
-
-       DEBUG(0,__FUNCTION__"():peer capability is:\n");
-       DEBUG(0,"3wire raw: %s\n",((self->servicetype & THREE_WIRE_RAW) ? "yes":"no"));
-       DEBUG(0,"3wire    : %s\n",((self->servicetype & THREE_WIRE) ? "yes":"no"));
-       DEBUG(0,"9wire    : %s\n",((self->servicetype & NINE_WIRE) ? "yes":"no"));
-       DEBUG(0,"IEEE1284 : %s\n",((self->servicetype & CENTRONICS) ? "yes":"no"));
-
-       self->servicetype &= servicetype;
-       if(!(self->servicetype)){
-               retval = -ENODEV;
-               goto bailout;
-       }
-
-       /*
-        * then choose better one 
-        */
+static void query_lsapsel(struct ircomm_cb * self)
+{
+       DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
 
-       if(self->servicetype & THREE_WIRE_RAW)
-               servicetype = THREE_WIRE_RAW;
-       if(self->servicetype & THREE_WIRE)
-               servicetype = THREE_WIRE;
-       if(self->servicetype & NINE_WIRE)
-               servicetype = NINE_WIRE;
-       if(self->servicetype & CENTRONICS)
-               servicetype = CENTRONICS;
-
-       self->servicetype = servicetype;
-#if 1
-       /*
-        * waiting for discovery again 
-        */
-       interruptible_sleep_on( &self->discovery_wait);
-       if(signal_pending(current)){
-               retval = -EINTR; goto bailout; /* cought a signal */
-       }
-       if(self->state == COMM_CONN)
-               goto bailout;     /* got connected */
-#endif
-       /*
-        * query lsapsel field and waiting for answer
-        */
-       query_lsapsel(self);
-       interruptible_sleep_on( &self->ias_wait);
-       if(signal_pending(current)){
-               retval = -EINTR; goto bailout; /* cought a signal */
-       }
-       if(self->state == COMM_CONN)
-               goto bailout;     /* got connected */
-
-       /* really got Lsapsel field? */
-       if(self->ias_type != IAS_INTEGER){
-               retval = -EFAULT;
-               goto bailout;
-       } 
-#if 1
-       /*
-        * waiting for discovery again...
-        */
-       interruptible_sleep_on( &self->discovery_wait);
-       if(signal_pending(current)){
-               retval = -EINTR; goto bailout; /* cought a signal */
+       if (!(self->servicetype & THREE_WIRE_RAW)) {
+               iriap_getvaluebyclass_request( 
+                       "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
+                       self->saddr, self->daddr,
+                       ircomm_getvalue_confirm, self );
+       } else {
+               DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
        }
-       if(self->state == COMM_CONN)
-               goto bailout;     /* got connected */
-#endif
-
-       /* succeed! ready to connect */
-       discovering_instance = NULL;
-       ircomm_connect_request(self);
-       return 0; 
-
- bailout:
-       /* failed.  not ready to connect */
-       discovering_instance = NULL;
-       irlmp_unregister_service(skey);
-       irlmp_unregister_client(ckey);
-       return retval;
 }
 
 /* 
@@ -926,7 +1148,7 @@ int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype)
  */
 
 
-void ircomm_connect_request(struct ircomm_cb *self)
+void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
 {
        /*
         * TODO:build a packet which contains "initial control parameters"
@@ -939,7 +1161,8 @@ void ircomm_connect_request(struct ircomm_cb *self)
 
        DEBUG(0, __FUNCTION__"():sending connect_request...\n");
 
-       ircomm_control_request(self, SERVICETYPE); /*servictype*/
+       self->servicetype= servicetype;
+       /* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
 
        self->maxsdusize = SAR_DISABLE;
        ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL);
@@ -986,6 +1209,7 @@ void ircomm_disconnect_request(struct ircomm_cb *self,
        ASSERT( self->magic == IRCOMM_MAGIC, return;);
        DEBUG(0,__FUNCTION__"()\n");
 
+#if 0
        /* unregister layer */
        switch (ircomm_cs) {
        case 1:    /* client only */
@@ -1001,6 +1225,7 @@ void ircomm_disconnect_request(struct ircomm_cb *self,
                irlmp_unregister_service(skey);
                break;
        }
+#endif
 
        self->disconnect_priority = priority;
        if(priority != P_HIGH)
@@ -1353,7 +1578,7 @@ void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type)
                        break;
                
                case SERVICETYPE:
-                       self->servicetype = data[2];
+                       self->peer_servicetype = data[2];
                        break;
 
                case PORT_TYPE:
@@ -1482,128 +1707,6 @@ void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type)
 
 
 
-/*
- * ircomm_getvalue_confirm()
- * handler for iriap_getvaluebyclass_request() 
- */
-
-static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value,
-                                    void *priv)
-{
-       struct ircomm_cb *self = (struct ircomm_cb *) priv;
-       struct sk_buff *skb= NULL;
-       __u8 *frame;
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-       /* Check if request succeeded */
-       if ( !value) {
-               DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
-               return;
-       }
-
-       DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
-
-       self->ias_type = value->type;
-       switch(value->type){
-       case IAS_OCT_SEQ:
-               
-               DEBUG(4, __FUNCTION__"():got octet sequence:\n");
-#if 0
-               {
-                       int i;
-                       for ( i=0;i<value->len;i++)
-                               printk("%02x",
-                                      (__u8)(*(value->t.oct_seq + i)));
-                       printk("\n");
-               }
-#endif
-               skb = dev_alloc_skb((value->len) + 2);
-               ASSERT(skb != NULL, return;);
-               frame = skb_put(skb,2);
-               /* MSB first */
-               frame[0] = ( value->len >> 8 ) & 0xff;
-               frame[1] = value->len & 0xff;
-               
-               frame = skb_put(skb,value->len);
-               memcpy(frame, value->t.oct_seq, value->len);
-               ircomm_parse_tuples(self, skb, IAS_PARAM);
-               kfree_skb(skb);
-
-               wake_up_interruptible( &self->ias_wait);
-               break;
-
-       case IAS_INTEGER:
-               /* LsapSel seems to be sent to me */    
-               DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
-
-               if ( value->t.integer == -1){
-                       DEBUG( 0, __FUNCTION__"():invalid value!\n");
-                       return;
-               }
-
-               if(self->state == COMM_IDLE){
-                       self->dlsap = value->t.integer;
-
-                       wake_up_interruptible( &self->ias_wait);
-               }
-               break;
-
-       case IAS_MISSING:
-               DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
-               break;
-   
-       default:
-               DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
-               break;
-       }
-}
-
-
-/*
- * query_lsapsel()
- *    quering the remote IAS to ask which
- *    dlsap we should use
- */
-
-static void query_lsapsel(struct ircomm_cb * self)
-{
-       DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
-
-       if (!(self->servicetype & THREE_WIRE_RAW)) {
-               iriap_getvaluebyclass_request( 
-                       "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
-                       self->saddr, self->daddr,
-                       ircomm_getvalue_confirm, self );
-       } else {
-               DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
-       }
-}
-
-/*
- * ircomm_discovery_indication()
- *    Remote device is discovered, try query the remote IAS to see which
- *    device it is, and which services it has.
- */
-
-static void ircomm_discovery_indication(discovery_t *discovery)
-{
-       struct ircomm_cb *self;
-
-       self = discovering_instance;
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
-       self->daddr = discovery->daddr;
-       self->saddr = discovery->saddr;
-
-       DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
-
-       wake_up_interruptible( &self->discovery_wait);
-       return;
-}
-
-
 struct ircomm_cb * ircomm_open_instance( struct notify_t client_notify)
 {
        int i;
index 9e468ba90d9b8bee1c92c0f43eedc5c1e81cd9a0..2df2fdd6015d98d8a4c176289b3667f50e9f2ed6 100644 (file)
@@ -51,7 +51,7 @@ struct termios *irvtd_termios_locked[COMM_MAX_TTY];
 static int irvtd_refcount;
 struct irvtd_cb **irvtd = NULL;
 
-static char *revision_date = "Wed Mar 10 15:33:03 1999";
+static char *revision_date = "Sun Apr 18 17:31:53 1999";
 
 
 /*
@@ -74,6 +74,7 @@ void irvtd_stop(struct tty_struct *tty);
 void irvtd_start(struct tty_struct *tty);
 void irvtd_hangup(struct tty_struct *tty);
 void irvtd_flush_buffer(struct tty_struct *tty);
+void irvtd_flush_chars(struct tty_struct *tty);
 
 static void change_speed(struct irvtd_cb *driver);
 static void irvtd_write_to_tty( struct irvtd_cb *);
@@ -90,14 +91,6 @@ static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
                           int *eof, void *unused);
 
 
-/*
- * ----------------------------------------------------------------------
- * 
- *
-
- * ----------------------------------------------------------------------
- */
-
 /*
  **********************************************************************
  *
@@ -122,11 +115,13 @@ static void irvtd_write_to_tty( struct irvtd_cb *driver)
        struct sk_buff *skb;
        struct tty_struct *tty = driver->tty;
        
+       if(driver->rx_disable)
+               return;
+
        skb = skb_dequeue(&driver->rxbuff);
        if(skb == NULL)
                return; /* there's nothing */
 
-
        /* 
         * we should parse controlchannel field here. 
         * (see process_data() in ircomm.c)
@@ -244,6 +239,7 @@ static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb)
                irttp_flow_request(driver->comm->tsap, FLOW_STOP);
                driver->ttp_stoprx = 1;
        }
+       irvtd_write_to_tty(driver);
        return 0;
 }
 
@@ -268,7 +264,7 @@ static void irvtd_start_timer( struct irvtd_cb *driver)
        
        driver->timer.data     = (unsigned long) driver;
        driver->timer.function = &irvtd_timer_expired;
-       driver->timer.expires  = jiffies + (HZ / 20);  /* 50msec */
+       driver->timer.expires  = jiffies + (HZ / 5);  /* 200msec */
        
        add_timer( &driver->timer);
 }
@@ -282,13 +278,10 @@ static void irvtd_timer_expired(unsigned long data)
        ASSERT(driver->magic == IRVTD_MAGIC,return;);
        DEBUG(4, __FUNCTION__"()\n");
 
-       if(!(driver->tty->hw_stopped) && !(driver->tx_disable))
-               irvtd_send_data_request(driver);
+       irvtd_send_data_request(driver);
+
+       irvtd_write_to_tty(driver);
 
-       if(!(driver->rx_disable)){
-               irvtd_write_to_tty(driver);
-       }
-       
        /* start our timer again and again */
        irvtd_start_timer(driver);
 }
@@ -302,6 +295,8 @@ static void irvtd_send_data_request(struct irvtd_cb *driver)
        ASSERT(skb != NULL,return;);
        DEBUG(4, __FUNCTION__"()\n");
 
+       if(driver->tty->hw_stopped || driver->tx_disable)
+               return;
        if(!skb->len)
                return;   /* no data to send */
 
@@ -315,7 +310,7 @@ static void irvtd_send_data_request(struct irvtd_cb *driver)
        }
 #endif
 
-       DEBUG(4, __FUNCTION__"():sending %d bytes\n",(int)skb->len );
+       DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
        driver->icount.tx += skb->len;
        err = ircomm_data_request(driver->comm, driver->txbuff);
        if (err){
@@ -327,7 +322,7 @@ static void irvtd_send_data_request(struct irvtd_cb *driver)
        /* allocate a new frame */
        skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
        if (skb == NULL){
-               printk(__FUNCTION__"():flush_txbuff():alloc_skb failed!\n");
+               printk(__FUNCTION__"():alloc_skb failed!\n");
        } else {
                skb_reserve(skb, COMM_HEADER_SIZE);
        }
@@ -369,10 +364,11 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
        /*
         * sending initial control parameters here
         */
-#if 1
        if(driver->comm->servicetype == THREE_WIRE_RAW)
                return;                /* do nothing */
 
+       driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
+
        ircomm_control_request(driver->comm, SERVICETYPE);
        ircomm_control_request(driver->comm, DATA_RATE);
        ircomm_control_request(driver->comm, DATA_FORMAT);
@@ -389,7 +385,6 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos,
                break;
        default:
        }
-#endif
        
        driver->tx_disable = 0;
        wake_up_interruptible(&driver->open_wait);
@@ -414,15 +409,27 @@ void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos,
 
        DEBUG(4,"irvtd_connect_indication:sending connect_response...\n");
 
-       /*TODO: connect_response should send initialcontrolparameters! TH*/
-
        ircomm_connect_response(comm, NULL, SAR_DISABLE );
 
+       driver->tx_disable = 0;
+
        /*
-        * set default value
+        * send initial control parameters
         */
+       if(driver->comm->servicetype == THREE_WIRE_RAW)
+               return;                /* do nothing */
+
+       driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
+
+       switch(driver->comm->servicetype){
+       case NINE_WIRE:
+               ircomm_control_request(driver->comm, DTELINE_STATE);
+               break;
+       default:
+       }
+
+
        driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
-       driver->tx_disable = 0;
        wake_up_interruptible(&driver->open_wait);
 }
 
@@ -445,7 +452,13 @@ void irvtd_disconnect_indication(void *instance, void *sap , LM_REASON reason,
        DEBUG(4,"irvtd_disconnect_indication:\n");
 
        driver->tx_disable = 1;
-       driver->disconnect_pend = 1;
+       if(skb_queue_empty(&driver->rxbuff)){
+               /* disconnect */
+               driver->rx_disable = 1;
+               tty_hangup(driver->tty);
+       } else {
+               driver->disconnect_pend = 1;
+       }
 }
 
 /*
@@ -559,6 +572,12 @@ void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd)
         }
        break;
 
+       case FLOW_CONTROL:
+       case DATA_RATE:
+       case XON_XOFF_CHAR:
+       case DTELINE_STATE:
+               /* (maybe) nothing to do  */
+               break;
        default:
                DEBUG(0,__FUNCTION__"():PI = 0x%02x is not implemented\n",
                      (int)driver->comm->pi);
@@ -624,19 +643,6 @@ static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp,
        while (1) {
                current->state = TASK_INTERRUPTIBLE;
                
-               if (driver->comm->state == COMM_CONN){
-                       /* 
-                        * signal DTR and RTS
-                        */
-                       driver->comm->dte = driver->mcr |= (MCR_DTR  |
-                                                           MCR_RTS  |
-                                                           DELTA_DTR|
-                                                           DELTA_RTS );
-
-                       ircomm_control_request(driver->comm, DTELINE_STATE);
-               }
-
-
                if (tty_hung_up_p(filp) ||
                    !(driver->flags & ASYNC_INITIALIZED)) {
 #ifdef DO_RESTART
@@ -755,7 +761,6 @@ static void change_speed(struct irvtd_cb *driver)
 
 static int irvtd_startup(struct irvtd_cb *driver)
 {
-       int retval = 0;
        struct ias_object* obj;
        struct notify_t irvtd_notify;
 
@@ -805,17 +810,13 @@ static int irvtd_startup(struct irvtd_cb *driver)
        irias_insert_object( obj);
 
        driver->flags |= ASYNC_INITIALIZED;
+
        /*
         * discover a peer device
         *         TODO: other servicetype(i.e. 3wire,3wireraw) support
         */
-       retval = ircomm_query_ias_and_connect(driver->comm, NINE_WIRE);
-       if(retval){
-               DEBUG(0, __FUNCTION__"(): ircomm_query_ias returns %d\n",
-                     retval);
-               return retval;
-       }
-
+       ircomm_connect_request(driver->comm, NINE_WIRE);
+       
        /*
         * TODO:we have to initialize control-channel here!
         *   i.e.set something into RTS,CTS and so on....
@@ -931,7 +932,7 @@ static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout)
        ASSERT(driver->magic == IRVTD_MAGIC, return;);
        ASSERT(driver->comm != NULL, return;);
 
-       DEBUG(0, __FUNCTION__"():\n");  
+       DEBUG(1, __FUNCTION__"():\n");  
        if(!tty->closing)
                return;   /* nothing to do */
        
@@ -944,7 +945,7 @@ static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout)
        orig_jiffies = jiffies;
 
        while (driver->comm->tsap->disconnect_pend) {
-               DEBUG(0, __FUNCTION__"():wait..\n");
+               DEBUG(1, __FUNCTION__"():wait..\n");
                current->state = TASK_INTERRUPTIBLE;
                current->counter = 0;   /* make us low-priority */
                schedule_timeout(HZ);    /* 1sec */
@@ -964,7 +965,7 @@ static void irvtd_shutdown(struct irvtd_cb * driver)
        if (!(driver->flags & ASYNC_INITIALIZED))
                return;
 
-       DEBUG(0,__FUNCTION__"()\n");
+       DEBUG(1,__FUNCTION__"()\n");
 
        /*
         * This comment is written in serial.c:
@@ -1017,7 +1018,7 @@ void irvtd_close(struct tty_struct * tty, struct file * filp)
        int line;
        unsigned long flags;
 
-       DEBUG(0, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
+       DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
 
        ASSERT(driver != NULL, return;);
        ASSERT(driver->magic == IRVTD_MAGIC, return;);
@@ -1030,7 +1031,7 @@ void irvtd_close(struct tty_struct * tty, struct file * filp)
                 * upper tty layer caught a HUP signal and called irvtd_hangup()
                 * before. so we do nothing here.
                 */
-               DEBUG(0, __FUNCTION__"():tty_hung_up_p.\n");
+               DEBUG(1, __FUNCTION__"():tty_hung_up_p.\n");
                MOD_DEC_USE_COUNT;
                restore_flags(flags);
                return;
@@ -1142,7 +1143,6 @@ int irvtd_write(struct tty_struct * tty, int from_user,
 
        DEBUG(4, __FUNCTION__"()\n");
 
-
        save_flags(flags);
        while(1){
                cli();
@@ -1164,11 +1164,23 @@ int irvtd_write(struct tty_struct * tty, int from_user,
                wrote += c;
                count -= c;
                buf += c;
+               irvtd_send_data_request(driver);
        }
        restore_flags(flags);
        return (wrote);
 }
 
+void irvtd_flush_chars(struct tty_struct *tty)
+{
+       struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
+       ASSERT( driver != NULL, return;);
+       ASSERT( driver->magic == IRVTD_MAGIC, return;);
+
+       DEBUG(4, __FUNCTION__"()\n");
+       irvtd_send_data_request(driver);
+}
+
+
 /*
  * Function irvtd_put_char (tty, ch)
  *
@@ -1606,14 +1618,14 @@ void irvtd_set_termios(struct tty_struct *tty, struct termios * old_termios){
 
 static void irvtd_send_xchar(struct tty_struct *tty, char ch){
 
-       DEBUG(0, __FUNCTION__"():\n");
+       DEBUG(1, __FUNCTION__"():\n");
        irvtd_put_char(tty, ch);
 }
 
 void irvtd_throttle(struct tty_struct *tty){
        struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
 
-       DEBUG(0, "irvtd_throttle:\n");
+       DEBUG(1, "irvtd_throttle:\n");
 
        if (I_IXOFF(tty))
                irvtd_put_char(tty, STOP_CHAR(tty));
@@ -1628,7 +1640,7 @@ void irvtd_throttle(struct tty_struct *tty){
 
 void irvtd_unthrottle(struct tty_struct *tty){
        struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-       DEBUG(0, "irvtd_unthrottle:\n");
+       DEBUG(1, "irvtd_unthrottle:\n");
 
        if (I_IXOFF(tty))
                irvtd_put_char(tty, START_CHAR(tty));
@@ -1760,7 +1772,7 @@ int irvtd_register_ttydriver(void){
         irvtd_drv.close = irvtd_close;
         irvtd_drv.write = irvtd_write;
         irvtd_drv.put_char = irvtd_put_char;
-       irvtd_drv.flush_chars = NULL;
+       irvtd_drv.flush_chars = irvtd_flush_chars;
         irvtd_drv.write_room = irvtd_write_room;
        irvtd_drv.chars_in_buffer = irvtd_chars_in_buffer; 
         irvtd_drv.flush_buffer = irvtd_flush_buffer;
@@ -1916,7 +1928,7 @@ __initfunc(int irvtd_init(void))
                memset( irvtd[i], 0, sizeof(struct irvtd_cb));
                irvtd[i]->magic = IRVTD_MAGIC;
                irvtd[i]->line = i;
-               irvtd[i]->closing_wait = 30*HZ ;
+               irvtd[i]->closing_wait = 10*HZ ;
                irvtd[i]->close_delay = 5*HZ/10 ; 
        }
 
index eaf9f2cd4bce612b5c1176faf607d728ffc1f247..cf9e6ea3441d90b0aac6640e28816a5b82567b65 100644 (file)
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      irda_device.c
- * Version:       0.4
+ * Version:       0.5
  * Description:   Abstract device driver layer and helper functions
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Wed Apr  7 17:16:54 1999
+ * Modified at:   Wed Apr 21 09:48:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -129,26 +129,28 @@ int irda_device_open(struct irda_device *self, char *name, void *priv)
 
        /* Allocate memory if needed */
        if (self->rx_buff.truesize > 0) {
-               self->rx_buff.data = ( __u8 *) kmalloc(self->rx_buff.truesize,
+               self->rx_buff.head = ( __u8 *) kmalloc(self->rx_buff.truesize,
                                                       self->rx_buff.flags);
-               if (self->rx_buff.data == NULL)
+               if (self->rx_buff.head == NULL)
                        return -ENOMEM;
 
-               memset(self->rx_buff.data, 0, self->rx_buff.truesize);
+               memset(self->rx_buff.head, 0, self->rx_buff.truesize);
        }
        if (self->tx_buff.truesize > 0) {
-               self->tx_buff.data = ( __u8 *) kmalloc(self->tx_buff.truesize, 
+               self->tx_buff.head = ( __u8 *) kmalloc(self->tx_buff.truesize, 
                                                       self->tx_buff.flags);
-               if (self->tx_buff.data == NULL)
+               if (self->tx_buff.head == NULL)
                        return -ENOMEM;
 
-               memset(self->tx_buff.data, 0, self->tx_buff.truesize);
+               memset(self->tx_buff.head, 0, self->tx_buff.truesize);
        }
        
        self->magic = IRDA_DEVICE_MAGIC;
 
        self->rx_buff.in_frame = FALSE;
        self->rx_buff.state = OUTSIDE_FRAME;
+       self->tx_buff.data = self->tx_buff.head;
+       self->rx_buff.data = self->rx_buff.head;
 
        /* Initialize timers */
        init_timer(&self->media_busy_timer);    
@@ -184,7 +186,7 @@ int irda_device_open(struct irda_device *self, char *name, void *priv)
        /* Open network device */
        dev_open(&self->netdev);
 
-       printk("IrDA device %s registered.\n", self->name);
+       MESSAGE("IrDA: Registred device %s\n", self->name);
 
        irda_device_set_media_busy(self, FALSE);
 
@@ -197,8 +199,6 @@ int irda_device_open(struct irda_device *self, char *name, void *priv)
        /* It's now safe to initilize the saddr */
        memcpy(self->netdev.dev_addr, &self->irlap->saddr, 4);
 
-       DEBUG(4, __FUNCTION__ "()->\n");
-
        return 0;
 }
 
@@ -226,11 +226,11 @@ void __irda_device_close(struct irda_device *self)
        /* Stop timers */
        del_timer(&self->media_busy_timer);
 
-       if (self->tx_buff.data)
-               kfree(self->tx_buff.data);
+       if (self->tx_buff.head)
+               kfree(self->tx_buff.head);
 
-       if (self->rx_buff.data)
-               kfree(self->rx_buff.data);
+       if (self->rx_buff.head)
+               kfree(self->rx_buff.head);
 
        self->magic = 0;
 }
@@ -462,26 +462,6 @@ int irda_device_txqueue_empty( struct irda_device *self)
        return TRUE;
 }
 
-/*
- * Function irda_get_mtt (skb)
- *
- *    Utility function for getting the minimum turnaround time out of 
- *    the skb, where it has been hidden in the cb field.
- */
-inline unsigned short irda_get_mtt(struct sk_buff *skb)
-{
-       unsigned short mtt;
-
-       if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
-               mtt = 10000;
-       else
-               mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt;
-
-       ASSERT(mtt <= 10000, return 10000;);
-       
-       return mtt;
-}
-
 /*
  * Function setup_dma (idev, buffer, count, mode)
  *
@@ -561,7 +541,6 @@ int irda_device_proc_read(char *buf, char **start, off_t offset, int len,
                               self->description);
                
                len += irda_device_print_flags(self, buf+len);
-
                len += sprintf(buf+len, "\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\n");
                
                len += sprintf(buf+len, "\t%d\t", 
index d0264377920ed7ee6a78d7b0773e5767a82438ef..b87ccbd028143fb861c6c4a0e4d88461ce2f2f4d 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Tue Mar 23 19:38:46 1999
+ * Modified at:   Fri Apr 23 09:57:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -31,6 +31,7 @@
 #include <linux/irda.h>
 
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irttp.h>
@@ -172,6 +173,7 @@ struct iriap_cb *iriap_open( __u8 slsap_sel, int mode)
                DEBUG( 0, "iriap_open: Unable to allocated LSAP!\n");
                return NULL;
        }
+       slsap_sel = lsap->slsap_sel;
        DEBUG( 4, __FUNCTION__ "(), source LSAP sel=%02x\n", slsap_sel);
        
        self->magic = IAS_MAGIC;
@@ -179,7 +181,7 @@ struct iriap_cb *iriap_open( __u8 slsap_sel, int mode)
        self->slsap_sel = slsap_sel;
        self->mode = mode;
 
-       /* init_timer( &self->watchdog_timer); */
+       init_timer( &self->watchdog_timer);
 
        hashbin_insert( iriap, (QUEUE*) self, slsap_sel, NULL);
        
@@ -204,7 +206,7 @@ static void __iriap_close( struct iriap_cb *self)
        ASSERT( self != NULL, return;);
        ASSERT( self->magic == IAS_MAGIC, return;);
 
-       /* del_timer( &self->watchdog_timer); */
+       del_timer( &self->watchdog_timer);
 
        self->magic = 0;
 
@@ -258,7 +260,7 @@ static void iriap_disconnect_indication( void *instance, void *sap,
 
        ASSERT( iriap != NULL, return;);
 
-       /* del_timer( &self->watchdog_timer); */
+       del_timer( &self->watchdog_timer);
 
        if ( self->mode == IAS_CLIENT) {
                DEBUG( 4, __FUNCTION__ "(), disconnect as client\n");
@@ -267,8 +269,8 @@ static void iriap_disconnect_indication( void *instance, void *sap,
                 * Inform service user that the request failed by sending 
                 * it a NULL value.
                 */
-               if ( self->confirm)
-                       self->confirm( 0, NULL, self->priv);
+               if (self->confirm)
+                       self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
                
                
                iriap_do_client_event( self, IAP_LM_DISCONNECT_INDICATION, 
@@ -348,9 +350,9 @@ void iriap_getvalue(void)
  *    Retreive all values from attribute in all objects with given class
  *    name
  */
-void iriap_getvaluebyclass_request( char *name, char *attr, 
-                                   __u32 saddr, __u32 daddr,
-                                   CONFIRM_CALLBACK callback, void *priv)
+void iriap_getvaluebyclass_request(char *name, char *attr, 
+                                  __u32 saddr, __u32 daddr,
+                                  CONFIRM_CALLBACK callback, void *priv)
 {
        struct sk_buff *skb;
        struct iriap_cb *self;
@@ -358,9 +360,9 @@ void iriap_getvaluebyclass_request( char *name, char *attr,
        int name_len, attr_len;
        __u8 slsap = LSAP_ANY;  /* Source LSAP to use */
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
-       self = iriap_open( slsap, IAS_CLIENT);
+       self = iriap_open(slsap, IAS_CLIENT);
        if (!self)
                return;
 
@@ -376,29 +378,29 @@ void iriap_getvaluebyclass_request( char *name, char *attr,
         */
        self->operation = GET_VALUE_BY_CLASS; 
 
-       /* Give ourselves 7 secs to finish this operation */
-       /* iriap_start_watchdog_timer( self, 700); */
+       /* Give ourselves 10 secs to finish this operation */
+       iriap_start_watchdog_timer(self, 10*HZ);
        
        skb = dev_alloc_skb( 64);
        if (!skb)
                return;
 
-       name_len = strlen( name);
-       attr_len = strlen( attr);
+       name_len = strlen(name);
+       attr_len = strlen(attr);
 
        /* Reserve space for MUX and LAP header */
-       skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
-       skb_put( skb, 3+name_len+attr_len);
+       skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+       skb_put(skb, 3+name_len+attr_len);
        frame = skb->data;
 
        /* Build frame */
        frame[0] = IAP_LST | GET_VALUE_BY_CLASS;
        frame[1] = name_len;                       /* Insert length of name */
-       memcpy( frame+2, name, name_len);          /* Insert name */
+       memcpy(frame+2, name, name_len);           /* Insert name */
        frame[2+name_len] = attr_len;              /* Insert length of attr */
-       memcpy( frame+3+name_len, attr, attr_len); /* Insert attr */
+       memcpy(frame+3+name_len, attr, attr_len);  /* Insert attr */
 
-       iriap_do_client_event( self, IAP_CALL_REQUEST_GVBC, skb);
+       iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb);
 }
 
 /*
@@ -415,7 +417,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
        int charset;
        __u32 value_len;
        __u32 tmp_cpu32;
-       __u16 tmp_cpu16;
        __u16 obj_id;
        __u16 len;
        __u8  type;
@@ -430,14 +431,14 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
        n = 2;
 
        /* Get length, MSB first */
-       memcpy(&len, fp+n, 2); n += 2;
-       be16_to_cpus(&len); 
+       len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
 
        DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
 
        /* Get object ID, MSB first */
-       memcpy(&obj_id, fp+n, 2); n += 2;
-       be16_to_cpus(&obj_id);
+       obj_id = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
+/*     memcpy(&obj_id, fp+n, 2); n += 2; */
+/*     be16_to_cpus(&obj_id); */
 
        type = fp[n++];
        DEBUG( 4, __FUNCTION__ "(), Value type = %d\n", type);
@@ -484,9 +485,8 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
                value = irias_new_string_value(fp+n);
                break;
        case IAS_OCT_SEQ:
-               memcpy(&tmp_cpu16, fp+n, 2);  n += 2;
-               be16_to_cpus(&tmp_cpu16);
-               value_len = tmp_cpu16;
+               value_len = be16_to_cpu(get_unaligned((__u16 *)(fp+n)));
+               n += 2;
                
                /* FIXME:should be 1024, but.... */
                DEBUG(0, __FUNCTION__ "():octet sequence:len=%d\n", value_len);
@@ -499,11 +499,11 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb)
                break;
        }
        
-       if (self->confirm)
-               self->confirm(obj_id, value, self->priv);
-       
        /* Finished, close connection! */
        iriap_disconnect_request(self);
+
+       if (self->confirm)
+               self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
 }
 
 /*
@@ -550,7 +550,7 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id,
        fp[n++] = ret_code;
 
        /* Insert list length (MSB first) */
-       tmp_be16 = __constant_htons( 0x0001);
+       tmp_be16 = __constant_htons(0x0001);
        memcpy(fp+n, &tmp_be16, 2);  n += 2; 
 
        /* Insert object identifier ( MSB first) */
@@ -703,17 +703,17 @@ void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos,
 {
        struct iriap_cb *self;
        
-       self = ( struct iriap_cb *) instance;
+       self = (struct iriap_cb *) instance;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IAS_MAGIC, return;);
-       ASSERT( userdata != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IAS_MAGIC, return;);
+       ASSERT(userdata != NULL, return;);
        
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
        
        /* del_timer( &self->watchdog_timer); */
 
-       iriap_do_client_event( self, IAP_LM_CONNECT_CONFIRM, userdata);
+       iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata);
 }
 
 /*
@@ -778,7 +778,7 @@ static int iriap_data_indication(void *instance, void *sap,
        }
 
        if (~opcode & IAP_ACK) {
-               DEBUG(0, __FUNCTION__ "() Got ack frame!\n");
+               DEBUG(2, __FUNCTION__ "() Got ack frame!\n");
        /*      return; */
        }
 
@@ -797,9 +797,21 @@ static int iriap_data_indication(void *instance, void *sap,
                        break;
                case IAS_CLASS_UNKNOWN:
                        printk(KERN_WARNING "IrIAP No such class!\n");
+                       /* Finished, close connection! */
+                       iriap_disconnect_request(self);
+
+                       if (self->confirm)
+                               self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 
+                                             self->priv);
                        break;
                case IAS_ATTRIB_UNKNOWN:
                        printk(KERN_WARNING "IrIAP No such attribute!\n");
+                       /* Finished, close connection! */
+                       iriap_disconnect_request(self);
+
+                       if (self->confirm)
+                               self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 
+                                             self->priv);
                        break;
                }
                iriap_do_call_event( self, IAP_RECV_F_LST, skb);
@@ -854,18 +866,20 @@ void iriap_call_indication( struct iriap_cb *self, struct sk_buff *skb)
        }
 }
 
+/*
+ * Function iriap_watchdog_timer_expired (data)
+ *
+ *    
+ *
+ */
 void iriap_watchdog_timer_expired( unsigned long data)
 {
        struct iriap_cb *self = ( struct iriap_cb *) data;
        
-       DEBUG( 0, __FUNCTION__ "()\n");
-
-       return;
-
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == IAS_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == IAS_MAGIC, return;);
 
-       DEBUG( 0, __FUNCTION__ "() Timeout! closing myself!\n");
+       DEBUG(0, __FUNCTION__ "() Timeout! closing myself!\n");
        iriap_close( self);
 }
 
index d679d86e35117d8930b6b02adcbb0dc11ca744fb..f2f8271cf5a0c465503251e08ccb0a4c391c940a 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Wed Apr  7 16:56:35 1999
+ * Modified at:   Thu Apr 22 23:03:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
@@ -30,7 +30,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
-#include <linux/inetdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <net/arp.h>
@@ -106,7 +105,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
 {
        struct irmanager_event mgr_event;
 
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -122,8 +121,8 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr)
        if (self->dev.start) {
                /* Open TSAPs */
                irlan_client_open_ctrl_tsap(self);
-               irlan_provider_open_ctrl_tsap(self);
-               irlan_open_data_tsap(self);
+               irlan_provider_open_ctrl_tsap(self);
+               irlan_open_data_tsap(self);
                
                irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
        } else if (self->notify_irmanager) {
@@ -162,7 +161,7 @@ void irlan_client_discovery_indication(discovery_t *discovery)
        struct irlan_cb *self, *entry;
        __u32 saddr, daddr;
        
-       DEBUG(2, __FUNCTION__"()\n");
+       DEBUG(0, __FUNCTION__"()\n");
 
        ASSERT(irlan != NULL, return;);
        ASSERT(discovery != NULL, return;);
@@ -171,8 +170,7 @@ void irlan_client_discovery_indication(discovery_t *discovery)
        daddr = discovery->daddr;
 
        /* 
-        *  Check if we already have an instance for dealing with this 
-        *  provider.
+        *  Check if we already dealing with this provider.
         */
        self = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
        if (self) {
@@ -190,7 +188,7 @@ void irlan_client_discovery_indication(discovery_t *discovery)
         */
        self = hashbin_find(irlan, DEV_ADDR_ANY, NULL);
        if (self) {
-               DEBUG(2, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n");
+               DEBUG(0, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n");
                /*
                 * Rehash instance, now we have a client (daddr) to serve.
                 */
@@ -200,27 +198,16 @@ void irlan_client_discovery_indication(discovery_t *discovery)
                self->daddr = daddr;
                self->saddr = saddr;
 
-               DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
+               DEBUG(0, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
                hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
                
                /* Check if network device has been registered */
                if (!self->netdev_registered)
                        irlan_register_netdev(self);
                
-               /* Remember that we might have to start a new provider */
-               self->client.start_new_provider = TRUE;
-       } else {
-               DEBUG(2, __FUNCTION__ "(), Found none, starting new one!\n");
-               /* No instance available, so we have to start one! */
-               self = irlan_open(saddr, daddr, TRUE);
-               if (!self) {
-                       DEBUG(2, __FUNCTION__ "(), irlan_open failed!\n");
-                       return;
-               }
-               ASSERT( self != NULL, return;);
+               /* Restart watchdog timer */
+               irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
        }
-       /* Restart watchdog timer */
-       irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 }
        
 /*
@@ -367,13 +354,12 @@ void irlan_client_reconnect_data_channel(struct irlan_cb *self)
 }
 
 /*
- * Function irlan_client_extract_params (skb)
+ * Function irlan_client_parse_response (self, skb)
  *
  *    Extract all parameters from received buffer, then feed them to 
  *    check_params for parsing
- *
  */
-void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb)
+void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 {
        __u8 *frame;
        __u8 *ptr;
@@ -392,7 +378,7 @@ void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb)
        ASSERT(self->magic == IRLAN_MAGIC, return;);
        
        if (!skb) {
-               DEBUG(2, __FUNCTION__ "(), Got NULL skb!\n");
+               ERROR( __FUNCTION__ "(), Got NULL skb!\n");
                return;
        }
        frame = skb->data;
@@ -423,7 +409,7 @@ void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb)
 
        /* For all parameters */
        for (i=0; i<count;i++) {
-               ret = irlan_get_param(ptr, name, value, &val_len);
+               ret = irlan_extract_param(ptr, name, value, &val_len);
                if (ret == -1) {
                        DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
                        break;
@@ -445,9 +431,6 @@ void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb)
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
                                       char *value, int val_len) 
 {
-#ifdef CONFIG_IRLAN_GRATUITOUS_ARP
-       struct in_device *in_dev;
-#endif
        __u16 tmp_cpu; /* Temporary value in host order */
        __u8 *bytes;
        int i;
@@ -550,21 +533,6 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
                      bytes[5]);
                for (i = 0; i < 6; i++) 
                        self->dev.dev_addr[i] = bytes[i];
-
-#ifdef CONFIG_IRLAN_GRATUITOUS_ARP
-               /* 
-                * When we get a new MAC address do a gratuitous ARP. This
-                * is useful if we have changed access points on the same
-                * subnet.  
-                */
-               DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
-               in_dev = self->dev.ip_ptr;
-               arp_send(ARPOP_REQUEST, ETH_P_ARP, 
-                         in_dev->ifa_list->ifa_address,
-                         &self->dev, 
-                         in_dev->ifa_list->ifa_address,
-                         NULL, self->dev.dev_addr, NULL);
-#endif
        }
 }
 
@@ -574,8 +542,8 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
  *    Got results from remote LM-IAS
  *
  */
-void irlan_client_get_value_confirm(__u16 obj_id, struct ias_value *value,
-                                   void *priv) 
+void irlan_client_get_value_confirm(int result, __u16 obj_id, 
+                                   struct ias_value *value, void *priv) 
 {
        struct irlan_cb *self;
        
@@ -587,7 +555,7 @@ void irlan_client_get_value_confirm(__u16 obj_id, struct ias_value *value,
        ASSERT(self->magic == IRLAN_MAGIC, return;);
 
        /* Check if request succeeded */
-       if (!value) {
+       if (result != IAS_SUCCESS) {
                DEBUG(2, __FUNCTION__ "(), got NULL value!\n");
                irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, 
                                      NULL);
index ec666c3d2c454ed031c03c2fbba3c2d67d1a532f..1544c093e14dc7560b55dc364f078092e94fc7b0 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Feb  4 16:08:07 1999
+ * Modified at:   Thu Apr 22 12:23:22 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -226,7 +226,7 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event,
        case IRLAN_DATA_INDICATION:
                ASSERT(skb != NULL, return -1;);
        
-               irlan_client_extract_params(self, skb);
+               irlan_client_parse_response(self, skb);
                
                irlan_next_client_state(self, IRLAN_MEDIA);
                
@@ -266,7 +266,7 @@ static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event,
 
        switch(event) {
        case IRLAN_DATA_INDICATION:
-               irlan_client_extract_params(self, skb);
+               irlan_client_parse_response(self, skb);
                irlan_open_data_channel(self);
                irlan_next_client_state(self, IRLAN_OPEN);
                break;
@@ -305,7 +305,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 
        switch(event) {
        case IRLAN_DATA_INDICATION:
-               irlan_client_extract_params(self, skb);
+               irlan_client_parse_response(self, skb);
                
                /*
                 *  Check if we have got the remote TSAP for data 
@@ -336,11 +336,6 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event,
                                              IRLAN_MTU, NULL);
                        
                        irlan_next_client_state(self, IRLAN_DATA);
-
-                       if (self->client.start_new_provider) {
-                               irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
-                               self->client.start_new_provider = FALSE;
-                       }
                        break;
                default:
                        DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
@@ -468,7 +463,7 @@ static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 
        switch(event) {
        case IRLAN_DATA_INDICATION:
-               irlan_client_extract_params(self, skb);
+               irlan_client_parse_response(self, skb);
                break;          
        case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
        case IRLAN_LAP_DISCONNECT:
index 607c71c398799e787755454168403728c50a52d7..00619cf44c992734a774683885256e0817026a44 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Wed Apr  7 17:03:21 1999
+ * Modified at:   Thu Apr 22 23:13:47 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -112,9 +112,11 @@ struct proc_dir_entry proc_irlan = {
 void irlan_watchdog_timer_expired(unsigned long data)
 {
        struct irmanager_event mgr_event;
-       struct irlan_cb *self = (struct irlan_cb *) data;
+       struct irlan_cb *self, *entry;
        
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
+
+       self = (struct irlan_cb *) data;
 
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -132,147 +134,38 @@ void irlan_watchdog_timer_expired(unsigned long data)
                 *  by the user.
                 */
                self->notify_irmanager = FALSE;
-       } else
-               irlan_close(self);
-}
-
-void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout)
-{
-       DEBUG(4, __FUNCTION__ "()\n");
-       
-       irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self,
-                        irlan_watchdog_timer_expired);
+       } else {
+               DEBUG(0, __FUNCTION__ "(), recycling instance!\n");
+               if (self->netdev_registered) {
+                       DEBUG(0, __FUNCTION__ "(), removing netdev!\n");
+                       unregister_netdev(&self->dev);
+                       self->netdev_registered = FALSE;
+               }
+
+               /* Unbind from daddr */
+               entry = hashbin_remove(irlan, self->daddr, NULL);
+               ASSERT(entry == self, return;);
+
+               self->daddr = DEV_ADDR_ANY;
+               self->saddr = DEV_ADDR_ANY;
+
+               DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
+               hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+       }
 }
 
 /*
- * Function irlan_eth_open (dev)
+ * Function irlan_start_watchdog_timer (self, timeout)
  *
- *    Network device has been opened by user
- *
- */
-static int irlan_eth_open(struct device *dev)
-{
-       struct irlan_cb *self;
-       
-       DEBUG(4, __FUNCTION__ "()\n");
-
-       ASSERT(dev != NULL, return -1;);
-
-       self = (struct irlan_cb *) dev->priv;
-
-       ASSERT(self != NULL, return -1;);
-
-       /* Ready to play! */
-/*     dev->tbusy = 0; */ /* Wait until data link is ready */
-       dev->interrupt = 0;
-       dev->start = 1;
-
-       self->notify_irmanager = TRUE;
-
-       /* We are now open, so time to do some work */
-       irlan_client_wakeup(self, self->saddr, self->daddr);
-
-       MOD_INC_USE_COUNT;
-       
-       return 0;
-}
-
-/*
- * Function irlan_eth_close (dev)
+ *    
  *
- *    Stop the ether network device, his function will usually be called by
- *    ifconfig down. We should now disconnect the link, We start the 
- *    close timer, so that the instance will be removed if we are unable
- *    to discover the remote device after the disconnect.
  */
-static int irlan_eth_close(struct device *dev)
+void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout)
 {
-       struct irlan_cb *self = (struct irlan_cb *) dev->priv;
-
        DEBUG(4, __FUNCTION__ "()\n");
        
-       /* Stop device */
-       dev->tbusy = 1;
-       dev->start = 0;
-
-       MOD_DEC_USE_COUNT;
-
-       irlan_close_data_channel(self);
-
-       irlan_close_tsaps(self);
-
-       irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
-       irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);      
-       
-       irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
-
-       /* Device closed by user! */
-       if (self->notify_irmanager)
-               self->notify_irmanager = FALSE;
-       else
-               self->notify_irmanager = TRUE;
-
-       return 0;
-}
-/*
- * Function irlan_eth_init (dev)
- *
- *    The network device initialization function.
- *
- */
-int irlan_eth_init(struct device *dev)
-{
-       struct irmanager_event mgr_event;
-       struct irlan_cb *self;
-
-       DEBUG(4, __FUNCTION__"()\n");
-
-       ASSERT(dev != NULL, return -1;);
-       
-       self = (struct irlan_cb *) dev->priv;
-
-       dev->open               = irlan_eth_open;
-       dev->stop               = irlan_eth_close;
-       dev->hard_start_xmit    = irlan_eth_xmit; 
-       dev->get_stats          = irlan_eth_get_stats;
-       dev->set_multicast_list = irlan_eth_set_multicast_list;
-
-       dev->tbusy = 1;
-       
-       ether_setup(dev);
-       
-       dev->tx_queue_len = TTP_MAX_QUEUE;
-
-#if 0
-       /*  
-        *  OK, since we are emulating an IrLAN sever we will have to give
-        *  ourself an ethernet address!
-        *  FIXME: this must be more dynamically
-        */
-       dev->dev_addr[0] = 0x40;
-       dev->dev_addr[1] = 0x00;
-       dev->dev_addr[2] = 0x00;
-       dev->dev_addr[3] = 0x00;
-       dev->dev_addr[4] = 0x23;
-       dev->dev_addr[5] = 0x45;
-#endif
-       /* 
-        * Network device has now been registered, so tell irmanager about
-        * it, so it can be configured with network parameters
-        */
-       mgr_event.event = EVENT_IRLAN_START;
-       sprintf(mgr_event.devname, "%s", self->ifname);
-       irmanager_notify(&mgr_event);
-
-       /* 
-        * We set this so that we only notify once, since if 
-        * configuration of the network device fails, the user
-        * will have to sort it out first anyway. No need to 
-        * try again.
-        */
-       self->notify_irmanager = FALSE;
-
-       return 0;
+       irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self,
+                        irlan_watchdog_timer_expired);
 }
 
 /*
@@ -312,8 +205,12 @@ __initfunc(int irlan_init(void))
        /* Start the first IrLAN instance */
        new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
 
+       irlan_open_data_tsap(new);
+       irlan_client_open_ctrl_tsap(new);
+       irlan_provider_open_ctrl_tsap(new);
+
        /* Do some fast discovery! */
-       irlmp_discovery_request(8);
+       irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
 
        return 0;
 }
@@ -345,7 +242,7 @@ int irlan_register_netdev(struct irlan_cb *self)
 {
        int i=0;
 
-       DEBUG(4, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
        /* Check if we should call the device eth<x> or irlan<x> */
        if (!eth) {
@@ -416,10 +313,6 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
        irlan_next_client_state(self, IRLAN_IDLE);
        irlan_next_provider_state(self, IRLAN_IDLE);
 
-       irlan_open_data_tsap(self);
-       irlan_provider_open_ctrl_tsap(self);
-       irlan_client_open_ctrl_tsap(self);
-
        /* Register network device now, or wait until some later time? */
        if (netdev)
                irlan_register_netdev(self);
@@ -436,7 +329,7 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev)
  */
 static void __irlan_close(struct irlan_cb *self)
 {
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
        
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -447,11 +340,13 @@ static void __irlan_close(struct irlan_cb *self)
        /* Close all open connections and remove TSAPs */
        irlan_close_tsaps(self);
 
-       if (self->netdev_registered)
+       if (self->netdev_registered) {
                unregister_netdev(&self->dev);
+               self->netdev_registered = FALSE;
+       }
        
        self->magic = 0;
-       kfree(self);
+       kfree(self);
 }
 
 /*
@@ -464,7 +359,7 @@ void irlan_close(struct irlan_cb *self)
 {
        struct irlan_cb *entry;
        
-       DEBUG(2, __FUNCTION__ "()\n");
+       DEBUG(0, __FUNCTION__ "()\n");
 
         ASSERT(self != NULL, return;);
        ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -572,7 +467,7 @@ void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason,
 
        switch(reason) {
        case LM_USER_REQUEST: /* User request */
-               irlan_close(self);
+               //irlan_close(self);
                break;
        case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
                irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
@@ -636,7 +531,7 @@ void irlan_open_data_tsap(struct irlan_cb *self)
        self->stsap_sel_data = self->tsap_data->stsap_sel;
 }
 
-static void irlan_close_tsaps(struct irlan_cb *self)
+void irlan_close_tsaps(struct irlan_cb *self)
 {
        DEBUG(4, __FUNCTION__ "()\n");
 
@@ -1122,12 +1017,12 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
 }
 
 /*
- * Function irlan_get_response_param (buf, param, value)
+ * Function irlan_extract_param (buf, name, value, len)
  *
  *    Extracts a single parameter name/value pair from buffer and updates
  *    the buffer pointer to point to the next name/value pair. 
  */
-int irlan_get_param(__u8 *buf, char *name, char *value, __u16 *len)
+int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
 {
        __u8 name_len;
        __u16 val_len;
@@ -1276,6 +1171,20 @@ void print_ret_code(__u8 code)
        }
 }
 
+void irlan_mod_inc_use_count(void)
+{
+#ifdef MODULE
+       MOD_INC_USE_COUNT;
+#endif
+}
+
+void irlan_mod_dec_use_count(void)
+{
+#ifdef MODULE
+       MOD_DEC_USE_COUNT;
+#endif
+}
+
 #ifdef MODULE
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
index 19aea4d1051841d2efe7b10cb814a31f2f36cf36..c1965a11714fdd69cecec8f6531634829a330f41 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Mon Mar 22 17:41:59 1999
+ * Modified at:   Thu Apr 22 14:26:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
 #include <linux/if_arp.h>
 #include <net/arp.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irlan_common.h>
+#include <net/irda/irlan_client.h>
+#include <net/irda/irlan_event.h>
 #include <net/irda/irlan_eth.h>
 
+/*
+ * Function irlan_eth_init (dev)
+ *
+ *    The network device initialization function.
+ *
+ */
+int irlan_eth_init(struct device *dev)
+{
+       struct irmanager_event mgr_event;
+       struct irlan_cb *self;
+
+       DEBUG(0, __FUNCTION__"()\n");
+
+       ASSERT(dev != NULL, return -1;);
+       
+       self = (struct irlan_cb *) dev->priv;
+
+       dev->open               = irlan_eth_open;
+       dev->stop               = irlan_eth_close;
+       dev->hard_start_xmit    = irlan_eth_xmit; 
+       dev->get_stats          = irlan_eth_get_stats;
+       dev->set_multicast_list = irlan_eth_set_multicast_list;
+
+       dev->tbusy = 1;
+       
+       ether_setup(dev);
+       
+       dev->tx_queue_len = TTP_MAX_QUEUE;
+
+#if 0
+       /*  
+        *  OK, since we are emulating an IrLAN sever we will have to give
+        *  ourself an ethernet address!
+        *  FIXME: this must be more dynamically
+        */
+       dev->dev_addr[0] = 0x40;
+       dev->dev_addr[1] = 0x00;
+       dev->dev_addr[2] = 0x00;
+       dev->dev_addr[3] = 0x00;
+       dev->dev_addr[4] = 0x23;
+       dev->dev_addr[5] = 0x45;
+#endif
+       /* 
+        * Network device has now been registered, so tell irmanager about
+        * it, so it can be configured with network parameters
+        */
+       mgr_event.event = EVENT_IRLAN_START;
+       sprintf(mgr_event.devname, "%s", self->ifname);
+       irmanager_notify(&mgr_event);
+
+       /* 
+        * We set this so that we only notify once, since if 
+        * configuration of the network device fails, the user
+        * will have to sort it out first anyway. No need to 
+        * try again.
+        */
+       self->notify_irmanager = FALSE;
+
+       return 0;
+}
+
+/*
+ * Function irlan_eth_open (dev)
+ *
+ *    Network device has been opened by user
+ *
+ */
+int irlan_eth_open(struct device *dev)
+{
+       struct irlan_cb *self;
+       
+       DEBUG(0, __FUNCTION__ "()\n");
+
+       ASSERT(dev != NULL, return -1;);
+
+       self = (struct irlan_cb *) dev->priv;
+
+       ASSERT(self != NULL, return -1;);
+
+       /* Ready to play! */
+/*     dev->tbusy = 0; */ /* Wait until data link is ready */
+       dev->interrupt = 0;
+       dev->start = 1;
+
+       self->notify_irmanager = TRUE;
+
+       /* We are now open, so time to do some work */
+       irlan_client_wakeup(self, self->saddr, self->daddr);
+
+       irlan_mod_inc_use_count();
+       
+       return 0;
+}
+
+/*
+ * Function irlan_eth_close (dev)
+ *
+ *    Stop the ether network device, his function will usually be called by
+ *    ifconfig down. We should now disconnect the link, We start the 
+ *    close timer, so that the instance will be removed if we are unable
+ *    to discover the remote device after the disconnect.
+ */
+int irlan_eth_close(struct device *dev)
+{
+       struct irlan_cb *self = (struct irlan_cb *) dev->priv;
+
+       DEBUG(0, __FUNCTION__ "()\n");
+       
+       /* Stop device */
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       irlan_mod_dec_use_count();
+
+       irlan_close_data_channel(self);
+
+       irlan_close_tsaps(self);
+
+       irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
+       irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);      
+       
+       irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
+
+       /* Device closed by user! */
+       if (self->notify_irmanager)
+               self->notify_irmanager = FALSE;
+       else
+               self->notify_irmanager = TRUE;
+
+       return 0;
+}
+
 /*
  * Function irlan_eth_tx (skb)
  *
@@ -219,6 +354,30 @@ void irlan_eth_rebuild_header(void *buff, struct device *dev,
        /* return 0; */
 }
 
+/*
+ * Function irlan_etc_send_gratuitous_arp (dev)
+ *
+ *    Send gratuitous ARP to announce that we have changed
+ *    hardware address, so that all peers updates their ARP tables
+ */
+void irlan_etc_send_gratuitous_arp(struct device *dev) 
+{
+       struct in_device *in_dev;
+
+       /* 
+        * When we get a new MAC address do a gratuitous ARP. This
+        * is useful if we have changed access points on the same
+        * subnet.  
+        */
+       DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
+       in_dev = dev->ip_ptr;
+       arp_send(ARPOP_REQUEST, ETH_P_ARP, 
+                in_dev->ifa_list->ifa_address,
+                &dev, 
+                in_dev->ifa_list->ifa_address,
+                NULL, dev->dev_addr, NULL);
+}
+
 /*
  * Function set_multicast_list (dev)
  *
index e60a70439b3a88d7938077767685275a25f75931..8e2c3c25ab89ceb8c094387f843e6ed6528a3088 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Tue Apr  6 19:08:20 1999
+ * Modified at:   Thu Apr 22 14:28:52 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
@@ -129,7 +129,7 @@ void irlan_provider_connect_indication(void *instance, void *sap,
        ASSERT(tsap == self->provider.tsap_ctrl,return;);
        ASSERT(self->provider.state == IRLAN_IDLE, return;);
 
-       /* Check if this provider is unused */
+       /* Check if this provider is currently unused */
        if (self->daddr == DEV_ADDR_ANY) {
                /*
                 * Rehash instance, now we have a client (daddr) to serve.
@@ -168,14 +168,6 @@ void irlan_provider_connect_indication(void *instance, void *sap,
        if ((self->access_type == ACCESS_PEER) && 
            (self->client.state == IRLAN_IDLE))
                irlan_client_wakeup(self, self->saddr, self->daddr);
-
-       /* 
-        * This provider is now in use, so start a new provider instance to
-         * serve other clients. This will also change the LM-IAS entry so that
-        * other clients don't try to connect to us, now that we are busy.
-        */
-       new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
-       self->client.start_new_provider = FALSE;
 }
 
 /*
@@ -231,20 +223,20 @@ int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb)
 {
        int ret;
        
-       ret = irlan_provider_extract_params(self, CMD_OPEN_DATA_CHANNEL, skb);
+       ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
 
        return ret;
 }
 
 /*
- * Function extract_params (skb)
+ * Function parse_command (skb)
  *
  *    Extract all parameters from received buffer, then feed them to 
  *    check_params for parsing
  *
  */
-int irlan_provider_extract_params(struct irlan_cb *self, int cmd,
-                                 struct sk_buff *skb) 
+int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
+                                struct sk_buff *skb) 
 {
        __u8 *frame;
        __u8 *ptr;
@@ -285,7 +277,7 @@ int irlan_provider_extract_params(struct irlan_cb *self, int cmd,
        
        /* For all parameters */
        for (i=0; i<count;i++) {
-               ret = irlan_get_param(ptr, name, value, &val_len);
+               ret = irlan_extract_param(ptr, name, value, &val_len);
                if (ret < 0) {
                        DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
                        break;
@@ -394,19 +386,19 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
  *    Register provider support so we can accept incomming connections.
  * 
  */
-void irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
+int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
 {
        struct notify_t notify;
        struct tsap_cb *tsap;
        
        DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == IRLAN_MAGIC, return;);
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
        /* Check if already open */
        if (self->provider.tsap_ctrl)
-               return;
+               return -1;
        
        /*
         *  First register well known control TSAP
@@ -421,11 +413,13 @@ void irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
        tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
        if (!tsap) {
                DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
-               return;
+               return -1;
        }
        self->provider.tsap_ctrl = tsap;
 
        /* Register with LM-IAS */
-       irlan_ias_register(self,tsap->stsap_sel);
+       irlan_ias_register(self, tsap->stsap_sel);
+
+       return 0;
 }
 
index c8dc9b44cccd8ef043f5e0f1ba2194a7019a0edb..6bdf503f1075a2e3d8060bdae14a4d619f7da597 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Wed Feb  3 21:43:06 1999
+ * Modified at:   Thu Apr 22 10:46:28 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -108,8 +108,15 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event,
        switch(event) {
        case IRLAN_GET_INFO_CMD:
                /* Be sure to use 802.3 in case of peer mode */
-               if (self->access_type == ACCESS_PEER)
+               if (self->access_type == ACCESS_PEER) {
                        self->media = MEDIA_802_3;
+                       
+                       /* Check if client has started yet */
+                       if (self->client.state == IRLAN_IDLE) {
+                               /* This should get the client going */
+                               irlmp_discovery_request(8);
+                       }
+               }
 
                irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO, 
                                          RSP_SUCCESS);
@@ -165,7 +172,7 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event,
 
        switch(event) {
        case IRLAN_FILTER_CONFIG_CMD:
-               irlan_provider_extract_params(self, CMD_FILTER_OPERATION, skb);
+               irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
                irlan_provider_send_reply(self, CMD_FILTER_OPERATION, 
                                          RSP_SUCCESS);
                /* Keep state */
@@ -207,7 +214,7 @@ static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event,
 
        switch(event) {
        case IRLAN_FILTER_CONFIG_CMD:
-               irlan_provider_extract_params(self, CMD_FILTER_OPERATION, skb);
+               irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
                irlan_provider_send_reply(self, CMD_FILTER_OPERATION, 
                                          RSP_SUCCESS);
                break;
index ec0610b556350f995e8e721b754b47f4c93d5727..d24923652a586949b5e53da3010f2aef4858c08e 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Tue Apr  6 21:07:08 1999
+ * Modified at:   Fri Apr 23 10:12:29 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -44,9 +44,9 @@
 #include <net/irda/irlap_comp.h>
 
 hashbin_t *irlap = NULL;
-int sysctl_slot_timeout = SLOT_TIMEOUT;
+int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
 
-static void __irlap_close( struct irlap_cb *self);
+static void __irlap_close(struct irlap_cb *self);
 
 static char *lap_reasons[] = {
        "ERROR, NOT USED",
@@ -301,27 +301,21 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb)
  *    IrLMP for further processing
  *
  */
-inline void irlap_data_indication( struct irlap_cb *self, struct sk_buff *skb) 
+inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb) 
 {
-       DEBUG( 4, __FUNCTION__ "()\n"); 
-
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-
        /* Hide LAP header from IrLMP layer */
-       skb_pull( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+       skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-       if ( self->qos_tx.compression.value) {
-               skb = irlap_decompress_frame( self, skb);
-               if ( !skb) {
-                       DEBUG( 1, __FUNCTION__ "(), Decompress error!\n");
+       if (self->qos_tx.compression.value) {
+               skb = irlap_decompress_frame(self, skb);
+               if (!skb) {
+                       DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
                        return;
                }
        }
 #endif
-       irlmp_link_data_indication( self->notify.instance, LAP_RELIABLE, skb);
+       irlmp_link_data_indication(self->notify.instance, LAP_RELIABLE, skb);
 }
 
 /*
@@ -515,22 +509,22 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery)
                info.discovery = discovery;
                
                /* Check if the slot timeout is within limits */
-               if ( sysctl_slot_timeout < 2) {
-                       DEBUG( 1, __FUNCTION__ 
-                              "(), to low value for slot timeout!\n");
-                       sysctl_slot_timeout = 2;
+               if (sysctl_slot_timeout < 20) {
+                       ERROR(__FUNCTION__ 
+                             "(), to low value for slot timeout!\n");
+                       sysctl_slot_timeout = 20;
                }
                /* 
                 * Highest value is actually 8, but we allow higher since
                 * some devices seems to require it.
                 */
-               if ( sysctl_slot_timeout > 16) {
-                       DEBUG( 1, __FUNCTION__ 
-                              "(), to high value for slot timeout!\n");
-                       sysctl_slot_timeout = 16;
+               if (sysctl_slot_timeout > 160) {
+                       ERROR(__FUNCTION__ 
+                             "(), to high value for slot timeout!\n");
+                       sysctl_slot_timeout = 160;
                }
 
-               self->slot_timeout = sysctl_slot_timeout;
+               self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
                
                irlap_do_event( self, DISCOVERY_REQUEST, NULL, &info);
        } else { 
@@ -807,24 +801,18 @@ void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos)
 {
        int usecs;
        int speed;
-       int bytes = 0;
+       int bytes ;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( qos != NULL, return;);
-
        /* Get QoS values.  */
        speed = qos->baud_rate.value;
        usecs = qos->min_turn_time.value;
 
        /* No need to calculate XBOFs for speeds over 115200 bps */
-       if ( speed > 115200) {
+       if (speed > 115200) {
                self->mtt_required = usecs;
                return;
        }
        
-       DEBUG( 4, __FUNCTION__ "(), delay=%d usecs\n", usecs); 
-       
        /*  
         *  Send additional BOF's for the next frame for the requested
         *  min turn time, so now we must calculate how many chars (XBOF's) we 
@@ -832,8 +820,6 @@ void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos)
         */
        bytes = speed * usecs / 10000000;
 
-       DEBUG( 4, __FUNCTION__ "(), xbofs delay = %d\n", bytes);
-       
        self->xbofs_delay = bytes;
 }
 
@@ -1028,7 +1014,7 @@ void irlap_apply_default_connection_parameters( struct irlap_cb *self)
        self->qos_tx.data_size.value = 64;
        self->qos_tx.additional_bofs.value = 11;
 
-       irlap_flush_all_queues( self);
+       irlap_flush_all_queues(self);
 
        self->disconnect_pending = FALSE;
 }
@@ -1079,11 +1065,10 @@ void irlap_apply_connection_parameters(struct irlap_cb *self,
 
        /* 
         *  Initialize timeout values, some of the rules are listed on 
-        *  page 92 in IrLAP. Divide by 10 since the kernel timers has a
-        *  resolution of 10 ms.
+        *  page 92 in IrLAP.
         */
-       self->poll_timeout = qos->max_turn_time.value / 10;
-       self->final_timeout = qos->max_turn_time.value / 10;
+       self->poll_timeout = qos->max_turn_time.value * HZ / 1000;
+       self->final_timeout = qos->max_turn_time.value * HZ / 1000;
        self->wd_timeout = self->poll_timeout * 2;
 
 #ifdef CONFIG_IRDA_COMPRESSION
index 99dd1783062fa1ba084de27a6e150295e7f07916..a2fbadf65045d951b1c915e3d7d5bd70f8737b68 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Fri Mar 26 14:24:09 1999
+ * Modified at:   Fri Apr 23 11:55:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
 
 #include <net/irda/irda_device.h>
 
-static int irlap_state_ndm    ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_query  ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reply  ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_conn   ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_setup  ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_offline( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_xmit_p ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_pclose ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_nrm_p  ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
+#if CONFIG_IRDA_FAST_RR
+int sysctl_fast_poll_increase = 50;
+#endif
+
+static int irlap_state_ndm    (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_query  (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_reply  (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_conn   (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_setup  (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_nrm_p  (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
 static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, 
                                  struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset  ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_nrm_s  ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_xmit_s ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_sclose ( struct irlap_cb *self, IRLAP_EVENT event, 
-                               struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset_check( struct irlap_cb *, IRLAP_EVENT event, 
-                                   struct sk_buff *, struct irlap_info *);
+static int irlap_state_reset  (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_nrm_s  (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event, 
+                              struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, 
+                                  struct sk_buff *, struct irlap_info *);
 
 static const char *irlap_event[] = {
        "DISCOVERY_REQUEST",
@@ -145,37 +149,37 @@ static int (*state[])( struct irlap_cb *self, IRLAP_EVENT event,
 /*
  * Function irda_poll_timer_expired (data)
  *
- *    
- *
+ *    Poll timer has expired. Normally we must now send a RR frame to the
+ *    remote device
  */
-static void irlap_poll_timer_expired( unsigned long data)
+static void irlap_poll_timer_expired(unsigned long data)
 {
        struct irlap_cb *self = (struct irlap_cb *) data;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
        
-       irlap_do_event( self, POLL_TIMER_EXPIRED, NULL, NULL);
+       irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
 }
 
-void irlap_start_poll_timer( struct irlap_cb *self, int timeout)
+void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
 {
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LAP_MAGIC, return;);
 
 #ifdef CONFIG_IRDA_FAST_RR
-       if ( skb_queue_len( &self->tx_list) == 0) {
-               if ( self->fast_RR == TRUE) {
+       if (skb_queue_len(&self->tx_list) == 0) {
+               if (self->fast_RR == TRUE) {
                        /*
                         *  Assert that the fast poll timer has not reached the
                         *  normal poll timer yet
                         */
-                       if ( self->fast_RR_timeout < timeout) {
+                       if (self->fast_RR_timeout < timeout) {
                                /*
                                 *  FIXME: this should be a more configurable
                                 *         function
                                 */
-                               self->fast_RR_timeout += 15;
+                               self->fast_RR_timeout += (sysctl_fast_poll_increase * HZ/1000);
 
                                /* Use this fast(er) timeout instead */
                                timeout = self->fast_RR_timeout;
@@ -183,17 +187,20 @@ void irlap_start_poll_timer( struct irlap_cb *self, int timeout)
                } else {
                        self->fast_RR = TRUE;
 
-                       /* Start with just 1 ms */
-                       self->fast_RR_timeout = 1;
-                       timeout = 1;
+                       /* Start with just 0 ms */
+                       self->fast_RR_timeout = 0;
+                       timeout = 0;
                }
        } else
                self->fast_RR = FALSE;
 
-       DEBUG( 4, __FUNCTION__ "(), Timeout=%d\n", timeout);
+       DEBUG(4, __FUNCTION__ "(), Timeout=%d\n", timeout);
 #endif
-       irda_start_timer( &self->poll_timer, timeout, 
-                         (unsigned long) self, irlap_poll_timer_expired);
+       if (timeout == 0)
+               irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
+       else
+               irda_start_timer(&self->poll_timer, timeout, 
+                                (unsigned long) self, irlap_poll_timer_expired);
 }
 
 /*
@@ -338,25 +345,25 @@ static int irlap_state_ndm( struct irlap_cb *self, IRLAP_EVENT event,
        case DISCOVERY_REQUEST:         
                ASSERT( info != NULL, return -1;);
 
-               if ( irda_device_is_media_busy( self->irdev)) {
+               if (irda_device_is_media_busy(self->irdev)) {
                        DEBUG(0, __FUNCTION__ "(), media busy!\n"); 
                        /* irlap->log.condition = MEDIA_BUSY; */
                        
                        /* Always switch state before calling upper layers */
-                       irlap_next_state( self, LAP_NDM); 
+                       irlap_next_state(self, LAP_NDM); 
                        
                        /* This will make IrLMP try again */
-                       irlap_discovery_confirm( self, NULL);
+                       irlap_discovery_confirm(self, NULL);
                        return 0;
                } 
                
                self->S = info->S;
                self->s = info->s;
-               irlap_send_discovery_xid_frame( self, info->S, info->s, TRUE,
-                                               info->discovery);
+               irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE,
+                                              info->discovery);
                self->s++;
 
-               irlap_start_slot_timer( self, self->slot_timeout);
+               irlap_start_slot_timer(self, self->slot_timeout);
                irlap_next_state(self, LAP_QUERY);
                break;
 
@@ -440,38 +447,38 @@ static int irlap_state_query( struct irlap_cb *self, IRLAP_EVENT event,
                irlap_next_state( self, LAP_QUERY); 
                break;
        case SLOT_TIMER_EXPIRED:
-               if ( self->s < self->S) {
-                       irlap_send_discovery_xid_frame( self, self->S, 
-                                                       self->s, TRUE,
-                                                       self->discovery_cmd);
+               if (self->s < self->S) {
+                       irlap_send_discovery_xid_frame(self, self->S, 
+                                                      self->s, TRUE,
+                                                      self->discovery_cmd);
                        self->s++;
-                       irlap_start_slot_timer( self, self->slot_timeout);
+                       irlap_start_slot_timer(self, self->slot_timeout);
                        
                        /* Keep state */
-                       irlap_next_state( self, LAP_QUERY);
+                       irlap_next_state(self, LAP_QUERY);
                } else {
                        /* This is the final slot! */
-                       irlap_send_discovery_xid_frame( self, self->S, 0xff, 
-                                                       TRUE,
-                                                       self->discovery_cmd);
+                       irlap_send_discovery_xid_frame(self, self->S, 0xff, 
+                                                      TRUE,
+                                                      self->discovery_cmd);
 
                        /* Always switch state before calling upper layers */
-                       irlap_next_state( self, LAP_NDM);
+                       irlap_next_state(self, LAP_NDM);
        
                        /*
                         *  We are now finished with the discovery procedure, 
                         *  so now we must return the results
                         */
-                       irlap_discovery_confirm( self, self->discovery_log);
+                       irlap_discovery_confirm(self, self->discovery_log);
                }
                break;
        default:
                DEBUG(2, __FUNCTION__ "(), Unknown event %d, %s\n", event, 
                      irlap_event[event]);
 
-               if ( skb != NULL) {
+               if (skb)
                        dev_kfree_skb( skb);
-               }
+
                ret = -1;
                break;
        }
@@ -485,37 +492,37 @@ static int irlap_state_query( struct irlap_cb *self, IRLAP_EVENT event,
  *    are waiting for the right time slot to send a response XID frame
  * 
  */
-static int irlap_state_reply( struct irlap_cb *self, IRLAP_EVENT event, 
-                             struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, 
+                            struct sk_buff *skb, struct irlap_info *info) 
 {
        discovery_t *discovery_rsp;
        int ret=0;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return -1;);
-       ASSERT( self->magic == LAP_MAGIC, return -1;);
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-       switch( event) {
+       switch(event) {
        case QUERY_TIMER_EXPIRED:
                DEBUG(2, __FUNCTION__ "(), QUERY_TIMER_EXPIRED <%ld>\n",
                      jiffies);
-               irlap_next_state( self, LAP_NDM);
+               irlap_next_state(self, LAP_NDM);
                break;
        case RECV_DISCOVERY_XID_CMD:
-               ASSERT( info != NULL, return -1;);
+               ASSERT(info != NULL, return -1;);
                /*
                 *  Last frame?
                 */
-               if ( info->s == 0xff) {
-                       del_timer( &self->query_timer);
+               if (info->s == 0xff) {
+                       del_timer(&self->query_timer);
                        
                        /* info->log.condition = REMOTE; */
 
                        /* Always switch state before calling upper layers */
-                       irlap_next_state( self, LAP_NDM);
+                       irlap_next_state(self, LAP_NDM);
 
-                       irlap_discovery_indication( self, info->discovery); 
+                       irlap_discovery_indication(self, info->discovery); 
                } else if ((info->s >= self->slot) && (!self->frame_sent)) {
                        discovery_rsp = irlmp_get_discovery_response();
                        discovery_rsp->daddr = info->daddr;
@@ -549,17 +556,17 @@ static int irlap_state_reply( struct irlap_cb *self, IRLAP_EVENT event,
  *    layer to accept or refuse connection 
  *
  */
-static int irlap_state_conn( struct irlap_cb *self, IRLAP_EVENT event, 
-                            struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, 
+                           struct sk_buff *skb, struct irlap_info *info) 
 {
        int ret = 0;
 
-       DEBUG( 4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
+       DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
 
-       ASSERT( self != NULL, return -1;);
-       ASSERT( self->magic == LAP_MAGIC, return -1;);
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-       switchevent) {
+       switch (event) {
        case CONNECT_RESPONSE:
                skb_pull( skb, 11);
 
@@ -762,7 +769,7 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event,
        DEBUG( 4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
               irlap_event[ event], self->vs, self->vr); 
                
-       switchevent) {
+       switch (event) {
        case SEND_I_CMD:
                ASSERT( skb != NULL, return -1;);
                DEBUG( 4, __FUNCTION__ "(), Window=%d\n", self->window);
@@ -822,7 +829,7 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event,
                } else {
                        DEBUG( 4, __FUNCTION__ 
                               "(), Unable to send! remote busy?\n");
-                       skb_queue_head( &self->tx_list, skb);
+                       skb_queue_head(&self->tx_list, skb);
 
                        /*
                         *  The next ret is important, because it tells 
@@ -831,19 +838,19 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event,
                        ret = -EPROTO;
                }
                break;
+       case POLL_TIMER_EXPIRED:
+               irlap_send_rr_frame(self, CMD_FRAME);
+               irlap_start_final_timer(self, self->final_timeout);
+               irlap_next_state(self, LAP_NRM_P);
+               break;
        case DISCONNECT_REQUEST:
-               del_timer( &self->poll_timer);
-               irlap_wait_min_turn_around( self, &self->qos_tx);
-               irlap_send_disc_frame( self);
-               irlap_flush_all_queues( self);
-               irlap_start_final_timer( self, self->final_timeout);
+               del_timer(&self->poll_timer);
+               irlap_wait_min_turn_around(self, &self->qos_tx);
+               irlap_send_disc_frame(self);
+               irlap_flush_all_queues(self);
+               irlap_start_final_timer(self, self->final_timeout);
                self->retry_count = 0;
-               irlap_next_state( self, LAP_PCLOSE);
-               break;
-       case POLL_TIMER_EXPIRED:
-               irlap_send_rr_frame( self, CMD_FRAME);
-               irlap_start_final_timer( self, self->final_timeout);
-               irlap_next_state( self, LAP_NRM_P);
+               irlap_next_state(self, LAP_PCLOSE);
                break;
        default:
                DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
@@ -916,117 +923,18 @@ static int irlap_state_pclose( struct irlap_cb *self, IRLAP_EVENT event,
  *   transmit any frames and is expecting to receive frames only from the
  *   secondary to which transmission permissions has been given.
  */
-static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, 
-                             struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, 
+                            struct sk_buff *skb, struct irlap_info *info) 
 {
        int ret = 0;
        int ns_status;
        int nr_status;
 
-       ASSERT( self != NULL, return -1;);
-       ASSERT( self->magic == LAP_MAGIC, return -1;);
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-       switch( event) {
-       case RECV_RR_RSP:
-               DEBUG( 4, __FUNCTION__ "(), RECV_RR_FRAME: "
-                      "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
-                      self->retry_count, info->nr, self->va, self->vs, 
-                      self->vr);
-
-               ASSERT( info != NULL, return -1;);
-
-               /*  
-                *  If you get a RR, the remote isn't busy anymore, 
-                *  no matter what the NR 
-                */
-               self->remote_busy = FALSE;
-
-               /* 
-                *  Nr as expected? 
-                */
-               ret = irlap_validate_nr_received( self, info->nr);
-               if ( ret == NR_EXPECTED) {      
-                       /* Stop final timer */
-                       del_timer( &self->final_timer);
-                       
-                       /* Update Nr received */
-                       irlap_update_nr_received( self, info->nr);
-                       
-                       /*
-                        *  Got expected NR, so reset the retry_count. This 
-                        *  is not done by the IrLAP standard , which is 
-                        *  strange! DB.
-                        */
-                       self->retry_count = 0;                  
-                       irlap_wait_min_turn_around( self, &self->qos_tx);
-
-                       /* Start poll timer */
-                       irlap_start_poll_timer( self, self->poll_timeout);
-
-                       irlap_next_state( self, LAP_XMIT_P);
-               } else if ( ret == NR_UNEXPECTED) {
-                       ASSERT( info != NULL, return -1;);      
-                       /* 
-                        *  Unexpected nr! 
-                        */
-                       
-                       /* Update Nr received */
-                       irlap_update_nr_received( self, info->nr);
-
-                       DEBUG( 4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, "
-                              "vs=%d, vr=%d\n",
-                              self->retry_count, info->nr, self->va, 
-                              self->vs, self->vr);
-                       
-                       /* Resend rejected frames */
-                       irlap_resend_rejected_frames( self, CMD_FRAME);
-                       
-                       /*
-                        *  Start only if not running, DB
-                        *  TODO: Should this one be here?
-                        */
-                       /* if ( !self->final_timer.prev) */
-/*                             irda_start_timer( FINAL_TIMER, self->final_timeout);  */
-
-                       /* Keep state */
-                       irlap_next_state( self, LAP_NRM_P);
-               } else if ( ret == NR_INVALID) {
-                       DEBUG(1, "irlap_state_nrm_p: received RR with "
-                             "invalid nr !\n");
-                       del_timer( &self->final_timer);
-
-                       irlap_next_state( self, LAP_RESET_WAIT);
-
-                       irlap_disconnect_indication( self, 
-                                                    LAP_RESET_INDICATION);
-                       self->xmitflag = TRUE;
-               }
-               if (skb)
-                       dev_kfree_skb( skb);
-               break;
-       case RECV_RNR_FRAME:
-               DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
-                      "nr=%d, va=%d, vs=%d, vr=%d\n",
-                      self->retry_count, info->nr, self->va, self->vs, 
-                      self->vr);
-
-               ASSERT( info != NULL, return -1;);
-
-               /* Stop final timer */
-               del_timer( &self->final_timer);
-               self->remote_busy = TRUE;
-
-               /* Update Nr received */
-               irlap_update_nr_received( self, info->nr);
-                       
-               /* Start poll timer */
-               irlap_start_poll_timer( self, self->poll_timeout);
-
-               irlap_next_state( self, LAP_XMIT_P);
-
-               dev_kfree_skb( skb);
-               break;
-       case RECV_I_RSP:
+       switch (event) {
+       case RECV_I_RSP: /* Optimize for the common case */
                /* FIXME: must check for remote_busy below */
 #ifdef CONFIG_IRDA_FAST_RR
                /* 
@@ -1039,8 +947,8 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
 
                ASSERT( info != NULL, return -1;);
 
-               ns_status = irlap_validate_ns_received( self, info->ns);
-               nr_status = irlap_validate_nr_received( self, info->nr);
+               ns_status = irlap_validate_ns_received(self, info->ns);
+               nr_status = irlap_validate_nr_received(self, info->nr);
 
                /* 
                 *  Check for expected I(nformation) frame
@@ -1049,7 +957,7 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                        /* 
                         *  poll bit cleared?
                         */
-                       if ( !info->pf) {
+                       if (!info->pf) {
                                self->vr = (self->vr + 1) % 8;
                        
                                /* Update Nr received */
@@ -1058,16 +966,16 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                                self->ack_required = TRUE;
                                
                                /* Keep state, do not move this line */
-                               irlap_next_state( self, LAP_NRM_P);
+                               irlap_next_state(self, LAP_NRM_P);
                                
-                               irlap_data_indication( self, skb);
+                               irlap_data_indication(self, skb);
                        } else {
-                               del_timer( &self->final_timer);
+                               del_timer(&self->final_timer);
 
                                self->vr = (self->vr + 1) % 8;
                        
                                /* Update Nr received */
-                               irlap_update_nr_received( self, info->nr);
+                               irlap_update_nr_received(self, info->nr);
                
                                /*  
                                 *  Got expected NR, so reset the
@@ -1077,13 +985,17 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                                self->retry_count = 0;
                                self->ack_required = TRUE;
                        
-                               /* This is the last frame */
-                               irlap_start_poll_timer( self, self->poll_timeout);
-                               irlap_wait_min_turn_around( self, &self->qos_tx);
-                               /* Do not move this line */
-                               irlap_next_state( self, LAP_XMIT_P);
+                               irlap_wait_min_turn_around(self, &self->qos_tx);
+                               /* 
+                                * Important to switch state before calling
+                                * upper layers
+                                */
+                               irlap_next_state(self, LAP_XMIT_P);
                        
-                               irlap_data_indication( self, skb);
+                               irlap_data_indication(self, skb);
+
+                               /* This is the last frame */
+                               irlap_start_poll_timer(self, self->poll_timeout);
                        }
                        break;
                        
@@ -1091,8 +1003,7 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                /*
                 *  Unexpected next to send (Ns)
                 */
-               if (( ns_status == NS_UNEXPECTED) && 
-                   ( nr_status == NR_EXPECTED)) 
+               if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
                {
                        if ( !info->pf) {
                                irlap_update_nr_received( self, info->nr);
@@ -1125,8 +1036,7 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                /* 
                 *  Unexpected next to receive (Nr) 
                 */
-               if (( ns_status == NS_EXPECTED) && 
-                   ( nr_status == NR_UNEXPECTED))
+               if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
                {
                        if ( info->pf) {
                                self->vr = (self->vr + 1) % 8;
@@ -1169,8 +1079,8 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                 *  Unexpected next to send (Ns) and next to receive (Nr)
                 *  Not documented by IrLAP!
                 */
-               if (( ns_status == NS_UNEXPECTED) && 
-                   ( nr_status == NR_UNEXPECTED)) 
+               if ((ns_status == NS_UNEXPECTED) && 
+                   (nr_status == NR_UNEXPECTED)) 
                {
                        DEBUG( 4, "IrLAP: unexpected nr and ns!\n");
                        if ( info->pf) {
@@ -1194,37 +1104,137 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
                /*
                 *  Invalid NR or NS
                 */
-               if (( nr_status == NR_INVALID) || ( ns_status == NS_INVALID)) {
-                       if ( info->pf) {
-                               del_timer( &self->final_timer);
+               if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) {
+                       if (info->pf) {
+                               del_timer(&self->final_timer);
                                
-                               irlap_next_state( self, LAP_RESET_WAIT);
+                               irlap_next_state(self, LAP_RESET_WAIT);
 
-                               irlap_disconnect_indication( self, LAP_RESET_INDICATION);
+                               irlap_disconnect_indication(self, LAP_RESET_INDICATION);
                                self->xmitflag = TRUE;
                        } else {
-                               del_timer( &self->final_timer);
+                               del_timer(&self->final_timer);
                                
-                               irlap_disconnect_indication( self, LAP_RESET_INDICATION);
+                               irlap_disconnect_indication(self, LAP_RESET_INDICATION);
                                
                                self->xmitflag = FALSE;
                        }
                        break;
                }
                DEBUG(1, __FUNCTION__ "(), Not implemented!\n");
-               DEBUG(1, __FUNCTION__ "(), event=%s, ns_status=%d, nr_status=%d\n", 
-                      irlap_event[ event], ns_status, nr_status);
+               DEBUG(1, __FUNCTION__ 
+                     "(), event=%s, ns_status=%d, nr_status=%d\n", 
+                     irlap_event[ event], ns_status, nr_status);
                break;
        case RECV_UI_FRAME:
                /*  poll bit cleared?  */
-               if ( !info->pf) {
-                       irlap_unit_data_indication( self, skb);
-                       irlap_next_state( self, LAP_NRM_P);
+               if (!info->pf) {
+                       irlap_unit_data_indication(self, skb);
+                       irlap_next_state(self, LAP_NRM_P);
                } else {
+                       del_timer(&self->final_timer);
+                       irlap_unit_data_indication(self, skb);
+                       irlap_start_poll_timer(self, self->poll_timeout);
+               }
+               break;
+       case RECV_RR_RSP:
+               DEBUG(4, __FUNCTION__ "(), RECV_RR_FRAME: "
+                     "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
+                     self->retry_count, info->nr, self->va, self->vs, 
+                     self->vr);
+
+               ASSERT(info != NULL, return -1;);
+
+               /*  
+                *  If you get a RR, the remote isn't busy anymore, 
+                *  no matter what the NR 
+                */
+               self->remote_busy = FALSE;
+
+               /* 
+                *  Nr as expected? 
+                */
+               ret = irlap_validate_nr_received(self, info->nr);
+               if (ret == NR_EXPECTED) {       
+                       /* Stop final timer */
+                       del_timer(&self->final_timer);
+                       
+                       /* Update Nr received */
+                       irlap_update_nr_received(self, info->nr);
+                       
+                       /*
+                        *  Got expected NR, so reset the retry_count. This 
+                        *  is not done by the IrLAP standard , which is 
+                        *  strange! DB.
+                        */
+                       self->retry_count = 0;                  
+                       irlap_wait_min_turn_around(self, &self->qos_tx);
+
+                       irlap_next_state(self, LAP_XMIT_P);
+
+                       /* Start poll timer */
+                       irlap_start_poll_timer(self, self->poll_timeout);
+               } else if (ret == NR_UNEXPECTED) {
+                       ASSERT( info != NULL, return -1;);      
+                       /* 
+                        *  Unexpected nr! 
+                        */
+                       
+                       /* Update Nr received */
+                       irlap_update_nr_received( self, info->nr);
+
+                       DEBUG( 4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, "
+                              "vs=%d, vr=%d\n",
+                              self->retry_count, info->nr, self->va, 
+                              self->vs, self->vr);
+                       
+                       /* Resend rejected frames */
+                       irlap_resend_rejected_frames( self, CMD_FRAME);
+                       
+                       /*
+                        *  Start only if not running, DB
+                        *  TODO: Should this one be here?
+                        */
+                       /* if ( !self->final_timer.prev) */
+/*                             irda_start_timer( FINAL_TIMER, self->final_timeout);  */
+
+                       /* Keep state */
+                       irlap_next_state( self, LAP_NRM_P);
+               } else if (ret == NR_INVALID) {
+                       DEBUG(1, "irlap_state_nrm_p: received RR with "
+                             "invalid nr !\n");
                        del_timer( &self->final_timer);
-                       irlap_unit_data_indication( self, skb);
-                       irlap_start_poll_timer( self, self->poll_timeout);
+
+                       irlap_next_state( self, LAP_RESET_WAIT);
+
+                       irlap_disconnect_indication( self, 
+                                                    LAP_RESET_INDICATION);
+                       self->xmitflag = TRUE;
                }
+               if (skb)
+                       dev_kfree_skb( skb);
+               break;
+       case RECV_RNR_FRAME:
+               DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
+                      "nr=%d, va=%d, vs=%d, vr=%d\n",
+                      self->retry_count, info->nr, self->va, self->vs, 
+                      self->vr);
+
+               ASSERT( info != NULL, return -1;);
+
+               /* Stop final timer */
+               del_timer( &self->final_timer);
+               self->remote_busy = TRUE;
+
+               /* Update Nr received */
+               irlap_update_nr_received( self, info->nr);
+
+               irlap_next_state( self, LAP_XMIT_P);
+                       
+               /* Start poll timer */
+               irlap_start_poll_timer( self, self->poll_timeout);
+
+               dev_kfree_skb( skb);
                break;
        case RECV_FRMR_RSP:
                del_timer( &self->final_timer);
@@ -1322,8 +1332,8 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event,
  *    awaiting reset of disconnect request.
  *
  */
-int irlap_state_reset_wait( struct irlap_cb *self, IRLAP_EVENT event, 
-                           struct sk_buff *skb, struct irlap_info *info)
+static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, 
+                                 struct sk_buff *skb, struct irlap_info *info)
 {
        int ret = 0;
        
@@ -1368,19 +1378,19 @@ int irlap_state_reset_wait( struct irlap_cb *self, IRLAP_EVENT event,
  *    reply.
  *
  */
-int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, 
-                      struct sk_buff *skb, struct irlap_info *info)
+static int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, 
+                             struct sk_buff *skb, struct irlap_info *info)
 {
        int ret = 0;
        
-       DEBUG( 3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
+       DEBUG(3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
        
-       ASSERT( self != NULL, return -1;);
-       ASSERT( self->magic == LAP_MAGIC, return -1;);
+       ASSERT(self != NULL, return -1;);
+       ASSERT(self->magic == LAP_MAGIC, return -1;);
        
-       switch( event) {
+       switch(event) {
        case RECV_DISC_FRAME:
-               del_timer( &self->final_timer);
+               del_timer(&self->final_timer);
 
                irlap_apply_default_connection_parameters( self);
 
@@ -1398,8 +1408,10 @@ int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event,
                irlap_reset_confirm();
                
                self->remote_busy = FALSE;
-               irlap_start_poll_timer( self, self->poll_timeout);
+
                irlap_next_state( self, LAP_XMIT_P);
+
+               irlap_start_poll_timer( self, self->poll_timeout);
                break;
        case FINAL_TIMER_EXPIRED:
                if ( self->retry_count < 3) {
@@ -1540,53 +1552,8 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
        ASSERT( self != NULL, return -1;);
        ASSERT( self->magic == LAP_MAGIC, return -1;);
 
-       switch( event) {
-       case RECV_RR_CMD:
-               self->retry_count = 0;
-
-               /* 
-                *  Nr as expected? 
-                */
-               nr_status = irlap_validate_nr_received( self, info->nr);
-               if ( nr_status == NR_EXPECTED) {
-                       if (( skb_queue_len( &self->tx_list) > 0) && 
-                           ( self->window > 0)) {
-                               self->remote_busy = FALSE;
-                               
-                               /* Update Nr received */
-                               irlap_update_nr_received( self, info->nr);
-                               del_timer( &self->wd_timer);
-                               
-                               irlap_wait_min_turn_around( self, &self->qos_tx);
-                               irlap_next_state( self, LAP_XMIT_S);
-                       } else {                        
-                               self->remote_busy = FALSE;
-                               /* Update Nr received */
-                               irlap_update_nr_received( self, info->nr);
-                               irlap_wait_min_turn_around( self, &self->qos_tx);
-                               
-                               irlap_send_rr_frame( self, RSP_FRAME);
-                               
-                               irlap_start_wd_timer( self, self->wd_timeout);
-                               irlap_next_state( self, LAP_NRM_S);
-                       }
-               } else if ( nr_status == NR_UNEXPECTED) {
-                       self->remote_busy = FALSE;
-                       irlap_update_nr_received( self, info->nr);
-                       irlap_resend_rejected_frames( self, RSP_FRAME);
-
-                       irlap_start_wd_timer( self, self->wd_timeout);
-
-                       /* Keep state */
-                       irlap_next_state( self, LAP_NRM_S); 
-               } else {
-                       DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
-               } 
-               if ( skb)
-                       dev_kfree_skb( skb);
-
-               break;
-       case RECV_I_CMD:
+       switch(event) {
+       case RECV_I_CMD: /* Optimize for the common case */
                /* FIXME: must check for remote_busy below */
                DEBUG( 4, __FUNCTION__ "(), event=%s nr=%d, vs=%d, ns=%d, "
                       "vr=%d, pf=%d\n", irlap_event[event], info->nr, 
@@ -1764,6 +1731,51 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event,
                                irlap_next_state( self, LAP_NRM_S);
                        }
                }
+               break;
+       case RECV_RR_CMD:
+               self->retry_count = 0;
+
+               /* 
+                *  Nr as expected? 
+                */
+               nr_status = irlap_validate_nr_received( self, info->nr);
+               if ( nr_status == NR_EXPECTED) {
+                       if (( skb_queue_len( &self->tx_list) > 0) && 
+                           ( self->window > 0)) {
+                               self->remote_busy = FALSE;
+                               
+                               /* Update Nr received */
+                               irlap_update_nr_received( self, info->nr);
+                               del_timer( &self->wd_timer);
+                               
+                               irlap_wait_min_turn_around( self, &self->qos_tx);
+                               irlap_next_state( self, LAP_XMIT_S);
+                       } else {                        
+                               self->remote_busy = FALSE;
+                               /* Update Nr received */
+                               irlap_update_nr_received( self, info->nr);
+                               irlap_wait_min_turn_around( self, &self->qos_tx);
+                               
+                               irlap_send_rr_frame( self, RSP_FRAME);
+                               
+                               irlap_start_wd_timer( self, self->wd_timeout);
+                               irlap_next_state( self, LAP_NRM_S);
+                       }
+               } else if ( nr_status == NR_UNEXPECTED) {
+                       self->remote_busy = FALSE;
+                       irlap_update_nr_received( self, info->nr);
+                       irlap_resend_rejected_frames( self, RSP_FRAME);
+
+                       irlap_start_wd_timer( self, self->wd_timeout);
+
+                       /* Keep state */
+                       irlap_next_state( self, LAP_NRM_S); 
+               } else {
+                       DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
+               } 
+               if ( skb)
+                       dev_kfree_skb( skb);
+
                break;
        case RECV_SNRM_CMD:
                del_timer( &self->wd_timer);
@@ -1897,7 +1909,3 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event,
 
        return ret;
 }
-
-
-
-
index 1ace3038e8569e69532b22297c4de092de1dafe2..cda78e7f1d536ffb9462de13a53ffbcad4c1fe66 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Tue Apr  6 16:35:21 1999
+ * Modified at:   Fri Apr 23 09:30:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
  *    need to do this since it's per packet relevant information.
  *
  */
-void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb)
+static inline void irlap_insert_mtt(struct irlap_cb *self, struct sk_buff *skb)
 {
        struct irlap_skb_cb *cb;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-
        cb = (struct irlap_skb_cb *) skb->cb;
        
        cb->magic = LAP_MAGIC;
@@ -71,8 +68,6 @@ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb)
        
        /* Reset XBOF's delay (used only for getting min turn time) */
        self->xbofs_delay = 0;
-
-       DEBUG( 4, __FUNCTION__ "(), using %d xbofs\n", cb->xbofs);
 }
 
 /*
@@ -83,10 +78,11 @@ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb)
  */
 void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
 {
-       /* Some init stuff */
+       /* Some common init stuff */
        skb->dev = self->netdev;
        skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data;
        skb->protocol = htons(ETH_P_IRDA);
+       skb->priority = TC_PRIO_BESTEFFORT;
 
        /* 
         * Insert MTT (min. turn time) into skb, so that the device driver 
@@ -534,13 +530,10 @@ static void irlap_recv_discovery_xid_cmd( struct irlap_cb *self,
  *    Build and transmit RR (Receive Ready) frame. Notice that it is currently
  *    only possible to send RR frames with the poll bit set.
  */
-void irlap_send_rr_frame( struct irlap_cb *self, int command) 
+void irlap_send_rr_frame(struct irlap_cb *self, int command) 
 {
-       struct sk_buff *skb = NULL;
+       struct sk_buff *skb;
        __u8 *frame;
-       
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
 
        skb = dev_alloc_skb(32);
        if (!skb)
@@ -553,8 +546,6 @@ void irlap_send_rr_frame( struct irlap_cb *self, int command)
 
        frame[1] = RR | PF_BIT | (self->vr << 5);
 
-       DEBUG(4, __FUNCTION__ "(), vr=%d, %ld\n", self->vr, jiffies); 
-
        irlap_queue_xmit(self, skb);
 }
 
@@ -569,27 +560,7 @@ static inline void irlap_recv_rr_frame(struct irlap_cb *self,
                                       struct sk_buff *skb, 
                                       struct irlap_info *info, int command)
 {
-       __u8 *frame;
-
-       frame = skb->data;
-       info->nr = frame[1] >> 5;
-
-       DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
-
-       /*
-        *  Make sure the state-machine is in the right state for receiving, 
-        *  if not, then we just discard the received frame for now!
-        *  TODO: check if we should queue this frame, or make tty tell that
-        *  it is receiving frames until the frame is delivered instead of
-        *  until it is outside a frame.
-        */
-#if 0
-       if ((self->state != LAP_NRM_P) && (self->state != LAP_NRM_S)) {
-               DEBUG(0, __FUNCTION__ "(), Wrong state, dropping frame!\n");
-               dev_kfree_skb(skb);
-               return;
-       }
-#endif
+       info->nr = skb->data[1] >> 5;
 
        /* Check if this is a command or a response frame */
        if (command)
@@ -676,16 +647,7 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb)
 {
        struct sk_buff *tx_skb;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
-
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-
-       /* Initialize variables */
-       tx_skb = NULL;
-
-       if ( skb->data[1] == I_FRAME) {
+       if (skb->data[1] == I_FRAME) {
 
                /*  
                 *  Insert frame sequence number (Vs) in control field before
@@ -693,10 +655,10 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb)
                 */
                skb->data[1] = I_FRAME | (self->vs << 1);
                
-               /* Copy buffer */
-               tx_skb = skb_clone( skb, GFP_ATOMIC);
-               if ( tx_skb == NULL) {
-                       dev_kfree_skb( skb);
+               /* Copy buffer */
+               tx_skb = skb_clone(skb, GFP_ATOMIC);
+               if (tx_skb == NULL) {
+                       dev_kfree_skb(skb);
                        return;
                }
                
@@ -704,12 +666,12 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb)
                 *  make sure the skb->sk accounting of memory usage is sane
                 */
                if (skb->sk != NULL)
-                       skb_set_owner_w( tx_skb, skb->sk);
+                       skb_set_owner_w(tx_skb, skb->sk);
                
                /* 
                 *  Insert frame in store, in case of retransmissions 
                 */
-               skb_queue_tail( &self->wx_list, skb);
+               skb_queue_tail(&self->wx_list, skb);
                
                self->vs = (self->vs + 1) % 8;
                self->ack_required = FALSE;             
@@ -718,7 +680,7 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb)
                irlap_send_i_frame( self, tx_skb, CMD_FRAME);
        } else {
                DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
-               irlap_send_ui_frame( self, skb, CMD_FRAME);
+               irlap_send_ui_frame(self, skb, CMD_FRAME);
                self->window -= 1;
        }
 }
@@ -731,17 +693,8 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb)
 {
        struct sk_buff *tx_skb;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
-
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-
-       /* Initialize variables */
-       tx_skb = NULL;
-
        /* Is this reliable or unreliable data? */
-       if ( skb->data[1] == I_FRAME) {
+       if (skb->data[1] == I_FRAME) {
                
                /*  
                 *  Insert frame sequence number (Vs) in control field before
@@ -750,9 +703,9 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb)
                skb->data[1] = I_FRAME | (self->vs << 1);
                
                /* Copy buffer */
-               tx_skb = skb_clone( skb, GFP_ATOMIC);
-               if ( tx_skb == NULL) {
-                       dev_kfree_skb( skb);
+               tx_skb = skb_clone(skb, GFP_ATOMIC);
+               if (tx_skb == NULL) {
+                       dev_kfree_skb(skb);
                        return;
                }
                
@@ -760,20 +713,20 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb)
                 *  make sure the skb->sk accounting of memory usage is sane
                 */
                if (skb->sk != NULL)
-                       skb_set_owner_w( tx_skb, skb->sk);
+                       skb_set_owner_w(tx_skb, skb->sk);
                
                /* 
                 *  Insert frame in store, in case of retransmissions 
                 */
-               skb_queue_tail( &self->wx_list, skb);
+               skb_queue_tail(&self->wx_list, skb);
                
                /*  
                 *  Set poll bit if necessary. We do this to the copied
                 *  skb, since retransmitted need to set or clear the poll
-                *  bit depending on when they are sent.  
+                *  bit depending on when they are sent.  
                 */
                /* Stop P timer */
-               del_timer( &self->poll_timer);
+               del_timer(&self->poll_timer);
                
                tx_skb->data[1] |= PF_BIT;
                
@@ -781,24 +734,24 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb)
                self->ack_required = FALSE;
                self->window = self->window_size;
 
-               irlap_start_final_timer( self, self->final_timeout);
+               irlap_start_final_timer(self, self->final_timeout);
 
-               irlap_send_i_frame( self, tx_skb, CMD_FRAME);
+               irlap_send_i_frame(self, tx_skb, CMD_FRAME);
        } else {
-               DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
+               DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
 
-               del_timer( &self->poll_timer);
+               del_timer(&self->poll_timer);
 
-               if ( self->ack_required) {
-                       irlap_send_ui_frame( self, skb, CMD_FRAME);
-                       irlap_send_rr_frame( self, CMD_FRAME);
+               if (self->ack_required) {
+                       irlap_send_ui_frame(self, skb, CMD_FRAME);
+                       irlap_send_rr_frame(self, CMD_FRAME);
                        self->ack_required = FALSE;
                } else {
                        skb->data[1] |= PF_BIT;
-                       irlap_send_ui_frame( self, skb, CMD_FRAME);
+                       irlap_send_ui_frame(self, skb, CMD_FRAME);
                }
                self->window = self->window_size;
-               irlap_start_final_timer( self, self->final_timeout);
+               irlap_start_final_timer(self, self->final_timeout);
        }
 }
 
@@ -926,7 +879,7 @@ void irlap_resend_rejected_frames( struct irlap_cb *self, int command)
        ASSERT( self != NULL, return;);
        ASSERT( self->magic == LAP_MAGIC, return;);
 
-       DEBUG( 4, __FUNCTION__ "(), retry_count=%d\n", self->retry_count);
+       DEBUG(2, __FUNCTION__ "(), retry_count=%d\n", self->retry_count);
 
        /* Initialize variables */
        skb = tx_skb = NULL;
@@ -939,7 +892,11 @@ void irlap_resend_rejected_frames( struct irlap_cb *self, int command)
        while ( skb != NULL) {
                irlap_wait_min_turn_around( self, &self->qos_tx);
 
-               tx_skb = skb_clone( skb, GFP_ATOMIC);
+               /* We copy the skb to be retransmitted since we will have to 
+                * modify it. Cloning will confuse packet sniffers 
+                */
+               /* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+               tx_skb = skb_copy(skb, GFP_ATOMIC);
                if ( tx_skb == NULL) {
                        /* Unlink tx_skb from list */
                        tx_skb->next = tx_skb->prev = NULL;
@@ -997,12 +954,12 @@ void irlap_resend_rejected_frames( struct irlap_cb *self, int command)
                         *  If send window > 1 then send frame with pf 
                         *  bit cleared
                         */ 
-                       if (( self->window > 1) && 
-                           skb_queue_len( &self->tx_list) > 0) 
+                       if ((self->window > 1) && 
+                           skb_queue_len(&self->tx_list) > 0) 
                        {
-                               irlap_send_data_primary( self, skb);
+                               irlap_send_data_primary(self, skb);
                        } else {
-                               irlap_send_data_primary_poll( self, skb);
+                               irlap_send_data_primary_poll(self, skb);
                        }
                }
        }
@@ -1057,6 +1014,15 @@ void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,
        /* Insert next to receive (Vr) */
        frame[1] |= (self->vr << 5);  /* insert nr */
 
+#if 0
+       {
+               int ns;
+               ns = (frame[1] >> 1) & 0x07; /* Next to send */
+
+               DEBUG(0, __FUNCTION__ "(), ns=%d\n", ns);
+       }
+#endif
+
        irlap_queue_xmit(self, skb);
 }
 
@@ -1070,30 +1036,13 @@ static inline void irlap_recv_i_frame(struct irlap_cb *self,
                                      struct sk_buff *skb, 
                                      struct irlap_info *info, int command) 
 {
-       __u8 *frame;
-
-       frame = skb->data;
-
-       info->nr = frame[1] >> 5;          /* Next to receive */
-       info->pf = frame[1] & PF_BIT;      /* Final bit */
-       info->ns = (frame[1] >> 1) & 0x07; /* Next to send */
+       info->nr = skb->data[1] >> 5;          /* Next to receive */
+       info->pf = skb->data[1] & PF_BIT;      /* Final bit */
+       info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */
 
        DEBUG(4, __FUNCTION__"(), ns=%d, nr=%d, pf=%d, %ld\n", 
              info->ns, info->nr, info->pf>>4, jiffies); 
 
-       /*
-        *  Make sure the state-machine is in the right state for receiving, 
-        *  if not, then we just discard the received frame for now!
-        *  TODO: check if we should queue this frame, or make tty tell that
-        *  it is receiving frames until the frame is delivered instead of
-        *  until it is outside a frame.
-        */
-       if ((self->state != LAP_NRM_P) && ( self->state != LAP_NRM_S)) {
-               DEBUG(0, __FUNCTION__ "(), Wrong state, dropping frame!\n");
-               dev_kfree_skb(skb);
-               return;
-       }
-
        /* Check if this is a command or a response frame */
        if (command)
                irlap_do_event(self, RECV_I_CMD, skb, info);
@@ -1266,7 +1215,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct device *dev,
 
        ASSERT( self != NULL, return -1;);
        ASSERT( self->magic == LAP_MAGIC, return -1;);
-       ASSERT(( skb != NULL) && (skb->len > 1), return -1;);
+       ASSERT( skb->len > 1, return -1;);
        
        frame = skb->data;
 
index c2f57aea65b75fbaa5cdd7bee190d9ea571e743f..d76661b6cf1ed47474f1364689ff40e2b094e187 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Wed Apr  7 17:31:48 1999
+ * Modified at:   Fri Apr 23 09:13:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -719,9 +719,12 @@ void irlmp_do_discovery(int nslots)
  */
 void irlmp_discovery_request(int nslots)
 {
-
        DEBUG(4, __FUNCTION__ "(), nslots=%d\n", nslots);
 
+       /* Check if user wants to override the default */
+       if (nslots == DISCOVERY_DEFAULT_SLOTS)
+               nslots = sysctl_discovery_slots;
+
        /* 
         * If discovery is already running, then just return the current 
         * discovery log
@@ -877,10 +880,8 @@ discovery_t *irlmp_get_discovery_response()
  *    Send some data to peer device
  *
  */
-void irlmp_data_request( struct lsap_cb *self, struct sk_buff *skb) 
+void irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) 
 {
-       DEBUG(4, __FUNCTION__ "()\n"); 
-
        ASSERT(skb != NULL, return;);
        ASSERT(self != NULL, return;);
        ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -898,14 +899,8 @@ void irlmp_data_request( struct lsap_cb *self, struct sk_buff *skb)
  *    Got data from LAP layer so pass it up to upper layer
  *
  */
-void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
+inline void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
-       DEBUG(4, __FUNCTION__ "()\n"); 
-
-       ASSERT(self != NULL, return;);
-       ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-       ASSERT(skb != NULL, return;);
-
        /* Hide LMP header from layer above */
        skb_pull(skb, LMP_HEADER);
 
index 3f61d4db0418e53a1e25688bad9d041899138482..20a2dff352c30e9d892594bcf114b9ad649b925a 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Thu Apr  8 16:26:41 1999
+ * Modified at:   Fri Apr 23 08:57:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -114,16 +114,16 @@ static void (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) =
 };
 
 /* Do connection control events */
-void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event, 
-                         struct sk_buff *skb)
+void irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, 
+                        struct sk_buff *skb)
 {
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
-       DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-              irlmp_event[ event], irlmp_state[ self->lsap_state]);
+       DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
+             irlmp_event[ event], irlmp_state[ self->lsap_state]);
 
-       (*lsap_state[ self->lsap_state]) ( self, event, skb);
+       (*lsap_state[self->lsap_state]) (self, event, skb);
 }
 
 /*
@@ -132,23 +132,21 @@ void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event,
  *    Do IrLAP control events
  *
  */
-void irlmp_do_lap_event( struct lap_cb *self, IRLMP_EVENT event, 
-                        struct sk_buff *skb) 
+void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, 
+                       struct sk_buff *skb) 
 {
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LAP_MAGIC, return;);
        
-       DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-              irlmp_event[event], 
-              irlmp_state[self->lap_state]);
+       DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
+             irlmp_event[event], 
+             irlmp_state[self->lap_state]);
 
-       (*lap_state[ self->lap_state]) ( self, event, skb);
+       (*lap_state[self->lap_state]) (self, event, skb);
 }
 
 void irlmp_discovery_timer_expired( unsigned long data)
 {
-/*     struct irlmp_cb *self = ( struct irlmp_cb *) data; */
-       
        DEBUG(4, "IrLMP, discovery timer expired!\n");
        
        if (sysctl_discovery)
@@ -306,8 +304,8 @@ static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event,
  *    ACTIVE, IrLAP connection is active
  *
  */
-static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event, 
-                               struct sk_buff *skb)
+static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, 
+                              struct sk_buff *skb)
 {
        struct lsap_cb *lsap;
        struct lsap_cb *lsap_current;
@@ -343,7 +341,7 @@ static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event,
                /* Keep state */
                break;
        case LM_LAP_DISCONNECT_REQUEST:
-               DEBUG( 4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
+               DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
 
                /*
                 *  Need to find out if we should close IrLAP or not. If there
@@ -357,7 +355,7 @@ static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event,
                break;
        case LM_LAP_IDLE_TIMEOUT:
                if (hashbin_get_size(self->lsaps) == 0) {
-                       DEBUG(0, __FUNCTION__ 
+                       DEBUG(2, __FUNCTION__ 
                              "(), no more LSAPs so time to close IrLAP\n");
                        irlmp_next_lap_state(self, LAP_STANDBY);
                        
@@ -365,7 +363,7 @@ static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event,
                }
                break;
        case LM_LAP_DISCONNECT_INDICATION:
-               DEBUG( 4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
+               DEBUG(4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
        
                irlmp_next_lap_state( self, LAP_STANDBY);               
                
@@ -525,18 +523,36 @@ static void irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event,
  *    DATA_TRANSFER_READY
  *
  */
-static void irlmp_state_dtr( struct lsap_cb *self, IRLMP_EVENT event, 
-                            struct sk_buff *skb) 
+static void irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, 
+                           struct sk_buff *skb) 
 {
        LM_REASON reason;
 
-       DEBUG( 4, __FUNCTION__ "()\n");
+       DEBUG(4, __FUNCTION__ "()\n");
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
-       ASSERT( self->lap != NULL, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+       ASSERT(self->lap != NULL, return;);
 
-       switch( event) {
+       switch (event) {
+       case LM_DATA_REQUEST: /* Optimize for the common case */
+               irlmp_send_data_pdu(self->lap, self->dlsap_sel, 
+                                   self->slsap_sel, FALSE, skb);
+               /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
+               break;
+       case LM_DATA_INDICATION: /* Optimize for the common case */
+               irlmp_data_indication(self, skb); 
+               /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
+               break;
+       case LM_UDATA_REQUEST:
+               ASSERT(skb != NULL, return;);
+               irlmp_send_data_pdu(self->lap, self->dlsap_sel, 
+                                   self->slsap_sel, TRUE, skb);
+               break;
+       case LM_UDATA_INDICATION:
+               irlmp_udata_indication(self, skb); 
+               /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
+               break;
        case LM_CONNECT_REQUEST:
                DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, "
                      "error, LSAP already connected\n");
@@ -548,65 +564,45 @@ static void irlmp_state_dtr( struct lsap_cb *self, IRLMP_EVENT event,
                /* Keep state */
                break;
        case LM_DISCONNECT_REQUEST:
-               ASSERT( skb != NULL, return;);
+               ASSERT(skb != NULL, return;);
 
-               irlmp_send_lcf_pdu( self->lap, self->dlsap_sel, 
-                                   self->slsap_sel, DISCONNECT, skb);
-               irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+               irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, 
+                                  self->slsap_sel, DISCONNECT, skb);
+               irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
                
                /* Try to close the LAP connection if its still there */
-               if ( self->lap) {
-                       DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n");
-                       irlmp_do_lap_event( self->lap, 
-                                           LM_LAP_DISCONNECT_REQUEST, 
-                                           NULL);
+               if (self->lap) {
+                       DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+                       irlmp_do_lap_event(self->lap, 
+                                          LM_LAP_DISCONNECT_REQUEST, 
+                                          NULL);
                }
-
-               break;
-       case LM_DATA_REQUEST:
-               ASSERT( skb != NULL, return;);
-               irlmp_send_data_pdu( self->lap, self->dlsap_sel, 
-                                    self->slsap_sel, FALSE, skb);
-               /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
-               break;
-       case LM_UDATA_REQUEST:
-               ASSERT( skb != NULL, return;);
-               irlmp_send_data_pdu( self->lap, self->dlsap_sel, 
-                                    self->slsap_sel, TRUE, skb);
-               break;
-       case LM_DATA_INDICATION:
-               irlmp_data_indication( self, skb); 
-               /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
-               break;
-       case LM_UDATA_INDICATION:
-               irlmp_udata_indication( self, skb); 
-               /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
                break;
        case LM_LAP_DISCONNECT_INDICATION:
-               irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+               irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
-               reason = irlmp_convert_lap_reason( self->lap->reason);
+               reason = irlmp_convert_lap_reason(self->lap->reason);
 
-               irlmp_disconnect_indication( self, reason, NULL);
+               irlmp_disconnect_indication(self, reason, NULL);
                break;
        case LM_DISCONNECT_INDICATION:
-               irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+               irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
                        
-               ASSERT( self->lap != NULL, return;);
-               ASSERT( self->lap->magic == LMP_LAP_MAGIC, return;);
+               ASSERT(self->lap != NULL, return;);
+               ASSERT(self->lap->magic == LMP_LAP_MAGIC, return;);
        
                ASSERT(skb != NULL, return;);
                ASSERT(skb->len > 3, return;);
                reason = skb->data[3];
 
                 /* Try to close the LAP connection */
-               DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n");
+               DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
                irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
-               irlmp_disconnect_indication( self, reason, skb);
+               irlmp_disconnect_indication(self, reason, skb);
                break;
        default:
-               DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+               DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
                break;  
        }       
 }
index 14a9141f05f963ba1d1d26d35c576a92ff0951da..bf1bab31ecf7a602c4c2faaf7aca624979247d42 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Tue Apr  6 18:31:11 1999
+ * Modified at:   Fri Apr 23 09:12:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
 #include <net/irda/irlmp_frame.h>
 #include <net/irda/discovery.h>
 
-static struct lsap_cb *irlmp_find_lsap( struct lap_cb *self, __u8 dlsap, 
-                                       __u8 slsap, int status, hashbin_t *);
+static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap, 
+                                      __u8 slsap, int status, hashbin_t *);
 
-inline void irlmp_send_data_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
-                                int expedited, struct sk_buff *skb)
+inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
+                               int expedited, struct sk_buff *skb)
 {
        __u8 *frame;
 
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-
        frame = skb->data;
 
        frame[0] = dlsap;
        frame[1] = slsap;
 
-       if ( expedited) {
+       if (expedited) {
                DEBUG( 4, __FUNCTION__ "(), sending expedited data\n");
                irlap_data_request( self->irlap, skb, FALSE);
-       } else {
-               DEBUG( 4, __FUNCTION__ "(), sending reliable data\n");
-               irlap_data_request( self->irlap, skb, TRUE);    
-       }
+       } else
+               irlap_data_request( self->irlap, skb, TRUE);
 }
 
 /*
@@ -98,18 +92,17 @@ void irlmp_send_lcf_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
  *    Used by IrLAP to pass received data frames to IrLMP layer
  *
  */
-void irlmp_link_data_indication( struct lap_cb *self, int reliable, 
-                                struct sk_buff *skb)
+void irlmp_link_data_indication(struct lap_cb *self, int reliable, 
+                               struct sk_buff *skb)
 {
-       __u8 *fp;
-       __u8  slsap_sel;   /* Source (this) LSAP address */
-       __u8  dlsap_sel;   /* Destination LSAP address */
        struct lsap_cb *lsap;
+       __u8   slsap_sel;   /* Source (this) LSAP address */
+       __u8   dlsap_sel;   /* Destination LSAP address */
+       __u8   *fp;
        
-       ASSERT( self != NULL, return;);
-       ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-       ASSERT( skb != NULL, return;);
-       ASSERT( skb->len > 2, return;);
+       ASSERT(self != NULL, return;);
+       ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+       ASSERT(skb->len > 2, return;);
 
        fp = skb->data;
 
@@ -124,7 +117,7 @@ void irlmp_link_data_indication( struct lap_cb *self, int reliable,
         *  Check if this is an incoming connection, since we must deal with
         *  it in a different way than other established connections.
         */
-       if ((fp[0] & CONTROL_BIT) && ( fp[2] == CONNECT_CMD)) {
+       if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
                DEBUG(3,"Incoming connection, source LSAP=%d, dest LSAP=%d\n",
                      slsap_sel, dlsap_sel);
                
@@ -184,10 +177,17 @@ void irlmp_link_data_indication( struct lap_cb *self, int reliable,
                        break;
                }
        } else if (reliable == LAP_RELIABLE) {
-               /* Must be pure data */
-               irlmp_do_lsap_event( lsap, LM_DATA_INDICATION, skb);
+               /* Optimize and bypass the state machine if possible */
+               if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
+                       irlmp_data_indication(lsap, skb);
+               else
+                       irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
        } else if (reliable == LAP_UNRELIABLE) {
-               irlmp_do_lsap_event( lsap, LM_UDATA_INDICATION, skb);
+               /* Optimize and bypass the state machine if possible */
+               if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
+                       irlmp_data_indication(lsap, skb);
+               else
+                       irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
        }
 }
 
@@ -297,8 +297,6 @@ void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log)
        irlmp_add_discovery_log(irlmp->cachelog, log);
       
        irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
-
-       DEBUG( 4, __FUNCTION__ "() -->\n");
 }
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
@@ -324,36 +322,31 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
 {
        struct lsap_cb *lsap;
        
-       ASSERT( self != NULL, return NULL;);
-       ASSERT( self->magic == LMP_LAP_MAGIC, return NULL;);
-
        /* 
         *  Optimize for the common case. We assume that the last frame
         *  received is in the same connection as the last one, so check in
         *  cache first to avoid the linear search
         */
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-       if (( irlmp->cache.valid) && 
-           ( irlmp->cache.slsap_sel == slsap_sel) && 
-           ( irlmp->cache.dlsap_sel == dlsap_sel)) 
+       if ((irlmp->cache.valid) && 
+           (irlmp->cache.slsap_sel == slsap_sel) && 
+           (irlmp->cache.dlsap_sel == dlsap_sel)) 
        {
                return (irlmp->cache.lsap);
        }
 #endif
-       lsap = ( struct lsap_cb *) hashbin_get_first(queue);
-       while ( lsap != NULL) {
+       lsap = (struct lsap_cb *) hashbin_get_first(queue);
+       while (lsap != NULL) {
                /* 
                 *  If this is an incomming connection, then the destination 
                 *  LSAP selector may have been specified as LM_ANY so that 
                 *  any client can connect. In that case we only need to check
                 *  if the source LSAP (in our view!) match!
                 */
-               if (( status == CONNECT_CMD) && 
-                   ( lsap->slsap_sel == slsap_sel) &&      
-                   ( lsap->dlsap_sel == LSAP_ANY)) 
+               if ((status == CONNECT_CMD) && 
+                   (lsap->slsap_sel == slsap_sel) &&      
+                   (lsap->dlsap_sel == LSAP_ANY)) 
                {
-                       DEBUG( 4,"Incoming connection: Setting dlsap_sel=%d\n",
-                              dlsap_sel);
                        lsap->dlsap_sel = dlsap_sel;
                        
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
@@ -364,15 +357,15 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel,
                /*
                 *  Check if source LSAP and dest LSAP selectors match.
                 */
-               if (( lsap->slsap_sel == slsap_sel) && 
-                   ( lsap->dlsap_sel == dlsap_sel)) 
+               if ((lsap->slsap_sel == slsap_sel) && 
+                   (lsap->dlsap_sel == dlsap_sel)) 
                {
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-                       irlmp_update_cache( lsap);
+                       irlmp_update_cache(lsap);
 #endif
                        return lsap;
                }
-               lsap = ( struct lsap_cb *) hashbin_get_next( queue);
+               lsap = ( struct lsap_cb *) hashbin_get_next(queue);
        }
 
        /* Sorry not found! */
index ba8150d06788fc601c6ce43d807c317993b9a66a..6ccd7a3d903a21fd7486e3817dfb161bd7c89540 100644 (file)
@@ -518,8 +518,8 @@ static int irlpt_client_data_indication(void *instance, void *sap,
  *    Fixed to match changes in iriap.h, DB.
  *
  */
-void irlpt_client_get_value_confirm(__u16 obj_id, struct ias_value *value
-                                   void *priv)
+void irlpt_client_get_value_confirm(int result, __u16 obj_id
+                                   struct ias_value *value, void *priv)
 {
        struct irlpt_info info;
        struct irlpt_cb *self;
@@ -534,7 +534,7 @@ void irlpt_client_get_value_confirm(__u16 obj_id, struct ias_value *value,
        ASSERT( self->magic == IRLPT_MAGIC, return;);
 
        /* Check if request succeeded */
-       if ( !value) {
+       if (result != IAS_SUCCESS) {
                DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
                irlpt_client_do_event( self, IAS_PROVIDER_NOT_AVAIL, NULL, 
                                       &info);
index ba49eb3a5310ac3375abe5acc2c5aa7f63ccf232..88d61c2cd62bca7850d4e7be3a6e28f0078fc29f 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Mon Mar 29 09:06:52 1999
+ * Modified at:   Mon Apr 12 11:31:01 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
@@ -50,12 +50,12 @@ extern struct proc_dir_entry proc_irda;
 struct irda_cb irda; /* One global instance */
 
 #ifdef CONFIG_IRDA_DEBUG
-__u32 irda_debug = IRDA_DEBUG;
+__u32 irda_debug = IRDA_DEBUG_LEVEL;
 #endif
 
 extern void irda_proc_register(void);
 extern void irda_proc_unregister(void);
-extern int irda_sysctl_register(void);
+extern int  irda_sysctl_register(void);
 extern void irda_sysctl_unregister(void);
 
 extern void irda_proto_init(struct net_proto *pro);
@@ -266,22 +266,6 @@ void irda_cleanup(void)
 }
 #endif /* MODULE */
 
-/*
- * Function irda_lock (lock)
- *
- *    Lock variable. Returns false if the lock is already set.
- *    
- */
-inline int irda_lock(int *lock) 
-{
-       if (test_and_set_bit( 0, (void *) lock))  {
-               DEBUG(3, __FUNCTION__ 
-                     "(), Trying to lock, already locked variable!\n");
-               return FALSE;
-        }  
-       return TRUE;
-}
-
 /*
  * Function irda_unlock (lock)
  *
index 7565138e94766490bf94c6c471d43729bb9626c0..0b9a4f1893cff23505927f58ea842c17fe011604 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 24 22:12:06 1998
- * Modified at:   Mon Jan 25 13:55:54 1999
+ * Modified at:   Fri Apr 23 09:46:38 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
@@ -36,6 +36,7 @@ enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, SLOT_TIMEOUT };
 extern int sysctl_discovery;
 extern int sysctl_discovery_slots;
 extern int sysctl_slot_timeout;
+extern int sysctl_fast_poll_increase;
 int sysctl_compression = 0;
 extern char sysctl_devname[];
 
@@ -52,7 +53,11 @@ static ctl_table irda_table[] = {
        { COMPRESSION, "compression", &sysctl_compression,
          sizeof(int), 0644, NULL, &proc_dointvec },
 #ifdef CONFIG_IRDA_DEBUG
-       { DEBUG, "debug", &irda_debug,
+        { DEBUG, "debug", &irda_debug,
+         sizeof(int), 0644, NULL, &proc_dointvec },
+#endif
+#ifdef CONFIG_IRDA_FAST_RR
+        { SLOTS, "fast_poll_increase", &sysctl_fast_poll_increase,
          sizeof(int), 0644, NULL, &proc_dointvec },
 #endif
        { SLOTS, "discovery_slots", &sysctl_discovery_slots,
index 77380ca0b78bca530b3249d2ea591f3e0ae51dc6..bf0624eee0f926cfa2dd0984b5a568225b82da50 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Thu Mar 25 10:27:08 1999
+ * Modified at:   Sat Apr 10 10:32:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -639,7 +640,6 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
                          struct sk_buff *userdata) 
 {
        struct sk_buff *skb;
-       __u16 tmp_be;
        __u8 *frame;
        __u8 n;
        
@@ -703,8 +703,8 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
                frame[2] = 0x01; /* MaxSduSize */
                frame[3] = 0x02; /* Value length */
 
-               tmp_be = cpu_to_be16((__u16) max_sdu_size);
-               memcpy(frame+4, &tmp_be, 2);
+               put_unaligned(cpu_to_be16((__u16) max_sdu_size), 
+                             (__u16 *)(frame+4));
        } else {
                /* Insert plain TTP header */
                frame = skb_push(skb, TTP_HEADER);
@@ -728,11 +728,10 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
                           __u32 max_seg_size, struct sk_buff *skb) 
 {
        struct tsap_cb *self;
-       __u16 tmp_cpu;
-       __u8 *frame;
-       __u8 n;
        int parameters;
+       __u8 *frame;
        __u8 plen, pi, pl;
+       __u8 n;
 
        DEBUG(4, __FUNCTION__ "()\n");
        
@@ -770,14 +769,26 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos,
                pi   = frame[2];
                pl   = frame[3];
 
-               ASSERT(pl == 2, return;);
-
-               memcpy(&tmp_cpu, frame+4, 2); /* Align value */
-               be16_to_cpus(&tmp_cpu);       /* Convert to host order */
-               self->tx_max_sdu_size = tmp_cpu;
+               switch (pl) {
+               case 1:
+                       self->tx_max_sdu_size = *(frame+4);
+                       break;
+               case 2:
+                       self->tx_max_sdu_size = 
+                               be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
+                       break;
+               case 4:
+                       self->tx_max_sdu_size = 
+                               be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
+                       break;
+               default:
+                       printk(KERN_ERR __FUNCTION__ 
+                              "() illegal value length for max_sdu_size!\n");
+                       self->tx_max_sdu_size = 0;
+               };
 
                DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", 
-                      self->tx_max_sdu_size);
+                     self->tx_max_sdu_size);
        }
        
        DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
@@ -804,11 +815,10 @@ void irttp_connect_indication(void *instance, void *sap,
 {
        struct tsap_cb *self;
        struct lsap_cb *lsap;
-       __u16 tmp_cpu;
-       __u8 *frame;
        int parameters;
-       int n;
+       __u8 *frame;
        __u8 plen, pi, pl;
+       __u8 n;
 
        self = (struct tsap_cb *) instance;
 
@@ -818,9 +828,6 @@ void irttp_connect_indication(void *instance, void *sap,
 
        lsap = (struct lsap_cb *) sap;
 
-       /* FIXME: just remove this when we know its working */
-       ASSERT(max_seg_size == qos->data_size.value, return;);
-
        self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER;
 
        DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
@@ -836,18 +843,31 @@ void irttp_connect_indication(void *instance, void *sap,
        
        parameters = frame[0] & 0x80;   
        if (parameters) {
-               DEBUG(4, __FUNCTION__ "(), Contains parameters!\n");
+               DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
                plen = frame[1];
                pi   = frame[2];
                pl   = frame[3];
 
-               ASSERT(pl == 2, return;);
-
-               memcpy(&tmp_cpu, frame+4, 2); /* Align value */
-               be16_to_cpus(&tmp_cpu);       /* Convert to host order */
-
-               self->tx_max_sdu_size = tmp_cpu;
-               DEBUG(4, __FUNCTION__ "(), MaxSduSize=%d\n", 
+               switch (pl) {
+               case 1:
+                       self->tx_max_sdu_size = *(frame+4);
+                       break;
+               case 2:
+                       self->tx_max_sdu_size = 
+                               be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
+                       break;
+               case 4:
+                       self->tx_max_sdu_size = 
+                               be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
+                       break;
+               default:
+                       printk(KERN_ERR __FUNCTION__ 
+                              "() illegal value length for max_sdu_size!\n");
+                       self->tx_max_sdu_size = 0;
+               };
+
+
+               DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", 
                      self->tx_max_sdu_size);
        }
 
@@ -873,7 +893,6 @@ void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
                            struct sk_buff *userdata)
 {
        struct sk_buff *skb;
-       __u32 tmp_be;
        __u8 *frame;
        __u8 n;
 
@@ -932,8 +951,8 @@ void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
                frame[2] = 0x01; /* MaxSduSize */
                frame[3] = 0x02; /* Value length */
 
-               tmp_be = cpu_to_be16((__u16)max_sdu_size);
-               memcpy(frame+4, &tmp_be, 2);
+               put_unaligned(cpu_to_be16((__u16) max_sdu_size), 
+                             (__u16 *)(frame+4));
        } else {
                /* Insert TTP header */
                frame = skb_push(skb, TTP_HEADER);
index 015d7559f59269f080104c8a6cd663d464b5a1d9..7b226dfa6481dad5710d39b39395ca62909d4968 100644 (file)
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Sep  9 00:00:26 1997
- * Modified at:   Mon Feb  1 09:56:21 1999
+ * Modified at:   Mon Apr 12 11:49:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -70,7 +70,7 @@ void irda_qos_compute_intersection( struct qos_info *qos, struct qos_info *new)
        qos->compression.bits     &= new->compression.bits;
 #endif
 
-       irda_qos_bits_to_value( qos);
+       irda_qos_bits_to_value(qos);
 }
 
 /*
index 03abf24ed8f098b762bb71cfcf9c5c35d11cd55c..c4822e2c6e8655bb9531ff4066678bcc4130b921 100644 (file)
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      wrapper.c
- * Version:       1.0
+ * Version:       1.1
  * Description:   SIR wrapper layer
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Mar 26 21:52:53 1999
+ * Modified at:   Wed Apr 21 12:45:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -34,9 +34,7 @@
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
 
-#define MIN_LENGTH 14
-
-inline static int stuff_byte( __u8 byte, __u8 *buf);
+inline static int stuff_byte(__u8 byte, __u8 *buf);
 
 /*
  * Function async_wrap (skb, *tx_buff)
@@ -44,17 +42,17 @@ inline static int stuff_byte( __u8 byte, __u8 *buf);
  *    Makes a new buffer with wrapping and stuffing, should check that 
  *    we don't get tx buffer overflow.
  */
-int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize)
+int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
 {
-       __u8 byte;
-       int i, n;
+       int i;
+       int n;
        int xbofs;
        union {
                __u16 value;
                __u8 bytes[2];
        } fcs;
 
-       ASSERT( skb != NULL, return 0;);
+       ASSERT(skb != NULL, return 0;);
 
        /* Initialize variables */
        fcs.value = INIT_FCS;
@@ -72,33 +70,31 @@ int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize)
         */
        if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC) {
                DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n");
-               xbofs = 11;
+               xbofs = 10;
        } else
                xbofs = ((struct irlap_skb_cb *)(skb->cb))->xbofs;
 
-       for (i=0; i<xbofs; i++) {
-               tx_buff[n++] = XBOF; 
-       }
-
+#if 0
+       for (i=0; i<xbofs; i++)
+               tx_buff[n++] = XBOF;
+#else
+       memset(tx_buff+n, XBOF, xbofs);
+       n += xbofs;
+#endif
        /* Start of packet character BOF */
        tx_buff[n++] = BOF;
 
        /* Insert frame and calc CRC */
        for (i=0; i < skb->len; i++) {
-               byte = skb->data[i];
-               
                /*
                 *  Check for the possibility of tx buffer overflow. We use
                 *  bufsize-5 since the maximum number of bytes that can be 
                 *  transmitted after this point is 5.
                 */
-               if ( n > buffsize-5) {
-                       printk( KERN_WARNING 
-                               "IrDA Wrapper: TX-buffer overflow!\n");
-                       return n;
-               }
-               n+=stuff_byte( byte, tx_buff+n);
-               fcs.value = IR_FCS( fcs.value, byte);
+               ASSERT(n < (buffsize-5), return n;);
+
+               n += stuff_byte(skb->data[i], tx_buff+n);
+               fcs.value = IR_FCS(fcs.value, skb->data[i]);
        }
        
        /* Insert CRC in little endian format (LSB first) */
@@ -111,7 +107,16 @@ int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize)
        n += stuff_byte(fcs.bytes[0], tx_buff+n);
 #endif
        tx_buff[n++] = EOF;
-       
+
+#if 0
+       {
+               int i;
+               
+               for (i=0;i<n;i++)
+                       printk("%02x", tx_buff[i]);
+               printk("\n");
+       }
+#endif
        return n;
 }
 
@@ -121,10 +126,10 @@ int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize)
  *    Got a frame, make a copy of it, and pass it up the stack!
  *
  */
-static inline void async_bump( struct irda_device *idev, __u8 *buf, int len)
+static inline void async_bump(struct irda_device *idev, __u8 *buf, int len)
 {
                struct sk_buff *skb;
+
        skb = dev_alloc_skb(len+1);
        if (!skb)  {
                idev->stats.rx_dropped++;
@@ -132,18 +137,14 @@ static inline void async_bump( struct irda_device *idev, __u8 *buf, int len)
        }
 
        /*  Align IP header to 20 bytes */
-       skb_reserve( skb, 1);
+       skb_reserve(skb, 1);
        
-       ASSERT( len-2 > 0, return;);
-
         /* Copy data without CRC */
-       skb_put( skb, len-2);
-       memcpy( skb->data, buf, len-2); 
+       memcpy(skb_put(skb, len-2), buf, len-2); 
        
        /* 
         *  Feed it to IrLAP layer 
         */
-       /* memcpy(skb_put(skb,count), ax->rbuff, count); */
        skb->dev = &idev->netdev;
        skb->mac.raw  = skb->data;
        skb->protocol = htons(ETH_P_IRDA);
@@ -159,18 +160,18 @@ static inline void async_bump( struct irda_device *idev, __u8 *buf, int len)
  *    Parse and de-stuff frame received from the IR-port
  *
  */
-void async_unwrap_char( struct irda_device *idev, __u8 byte) 
+void async_unwrap_char(struct irda_device *idev, __u8 byte) 
 {
        /* State machine for receiving frames */           
-       switchidev->rx_buff.state) {
+       switch (idev->rx_buff.state) {
        case OUTSIDE_FRAME:
-               switch( byte) {
+               switch(byte) {
                case BOF:
                        idev->rx_buff.state = BEGIN_FRAME;
                        idev->rx_buff.in_frame = TRUE;
                        break;
                case XBOF:
-                       idev->xbofs++;
+                       /* idev->xbofs++; */
                        break;
                case EOF:
                        irda_device_set_media_busy( idev, TRUE);
@@ -180,9 +181,8 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte)
                }
                break;
        case BEGIN_FRAME:
-               switch ( byte) {
+               switch (byte) {
                case BOF:
-                       
                        /* Continue */
                        break;
                case CE:
@@ -198,28 +198,29 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte)
                        break;
                default:
                        /* Got first byte of frame */
-                       idev->rx_buff.data[ idev->rx_buff.len++] = byte;
+                       idev->rx_buff.data = idev->rx_buff.head;
+                       idev->rx_buff.len = 0;
+
+                       idev->rx_buff.data[idev->rx_buff.len++] = byte;
                        
-                       idev->rx_buff.fcs = IR_FCS( INIT_FCS, byte);
+                       idev->rx_buff.fcs = IR_FCS(INIT_FCS, byte);
                        idev->rx_buff.state = INSIDE_FRAME;
                        break;
                }
                break;
        case LINK_ESCAPE:
-               switch ( byte) {
+               switch (byte) {
                case BOF:
                        /* New frame? */
                        idev->rx_buff.state = BEGIN_FRAME;
-                       idev->rx_buff.len = 0;
-                       irda_device_set_media_busy( idev, TRUE);
+                       irda_device_set_media_busy(idev, TRUE);
                        break;
                case CE:
-                       DEBUG( 4, "WARNING: State not defined\n");
+                       DEBUG(4, "WARNING: State not defined\n");
                        break;
                case EOF:
                        /* Abort frame */
                        idev->rx_buff.state = OUTSIDE_FRAME;
-                       idev->rx_buff.len = 0;
                        break;
                default:
                        /* 
@@ -227,28 +228,25 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte)
                         *  following CE, IrLAP p.114 
                         */
                        byte ^= IR_TRANS;
-                       if ( idev->rx_buff.len < idev->rx_buff.truesize)  {
-                               idev->rx_buff.data[ idev->rx_buff.len++] = byte;
-                       
+                       if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+                               idev->rx_buff.data[idev->rx_buff.len++] = byte;
                                idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
                                                           byte);
                                idev->rx_buff.state = INSIDE_FRAME;
                        } else {
-                               DEBUG( 1, __FUNCTION__ 
+                               DEBUG(1, __FUNCTION__ 
                                       "(), Rx buffer overflow, aborting\n");
                                idev->rx_buff.state = OUTSIDE_FRAME;
-                               idev->rx_buff.len = 0;
                        }
                        break;
                }
                break;
        case INSIDE_FRAME:
-               switch ( byte) {
+               switch (byte) {
                case BOF:
                        /* New frame? */
                        idev->rx_buff.state = BEGIN_FRAME;
-                       idev->rx_buff.len = 0;
-                       irda_device_set_media_busy( idev, TRUE);
+                       irda_device_set_media_busy(idev, TRUE);
                        break;
                case CE:
                        /* Stuffed char */
@@ -262,14 +260,12 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte)
                        /* 
                         *  Test FCS and deliver frame if it's good
                         */                     
-                       if ( idev->rx_buff.fcs == GOOD_FCS) {
-                               async_bump( idev, idev->rx_buff.data, 
-                                           idev->rx_buff.len);
-                               idev->rx_buff.len = 0;
+                       if (idev->rx_buff.fcs == GOOD_FCS) {
+                               async_bump(idev, idev->rx_buff.data, 
+                                          idev->rx_buff.len);
                        } else {
                                /* Wrong CRC, discard frame!  */
-                               irda_device_set_media_busy( idev, TRUE); 
-                               idev->rx_buff.len = 0;
+                               irda_device_set_media_busy(idev, TRUE); 
 
                                idev->stats.rx_errors++;
                                idev->stats.rx_crc_errors++;
@@ -277,16 +273,14 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte)
                        break;
                default:
                        /* Next byte of frame */
-                       if ( idev->rx_buff.len < idev->rx_buff.truesize)  {
-                               idev->rx_buff.data[ idev->rx_buff.len++] = byte;
-                               
-                               idev->rx_buff.fcs = IR_FCS( idev->rx_buff.fcs,
-                                                           byte);
+                       if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+                               idev->rx_buff.data[idev->rx_buff.len++] = byte;
+                               idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
+                                                          byte);
                        } else {
-                               DEBUG( 1, __FUNCTION__ 
-                                      "(), Rx buffer overflow, aborting\n");
+                               DEBUG(1, __FUNCTION__ 
+                                     "(), Rx buffer overflow, aborting\n");
                                idev->rx_buff.state = OUTSIDE_FRAME;
-                               idev->rx_buff.len = 0;
                        }
                        break;
                }
@@ -301,9 +295,9 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte)
  *    buf. The buffer must at all times be able to have two bytes inserted.
  * 
  */
-inline static int stuff_byte( __u8 byte, __u8 *buf) 
+inline static int stuff_byte(__u8 byte, __u8 *buf) 
 {
-       switch ( byte) {
+       switch (byte) {
        case BOF: /* FALLTHROUGH */
        case EOF: /* FALLTHROUGH */
        case CE:
index 9cc89e362d1dee3fd2ec767a679b04bfd0d1af3d..764900d50f74a8c5ab551dfd3e3769068fb240ab 100644 (file)
@@ -21,6 +21,9 @@
 #include <net/dst.h>
 #include <net/checksum.h>
 #include <linux/etherdevice.h>
+#ifdef CONFIG_HIPPI
+#include <linux/hippidevice.h>
+#endif
 #include <net/pkt_sched.h>
 
 #ifdef CONFIG_BRIDGE
@@ -45,6 +48,8 @@
 #include <linux/igmp.h>
 
 extern struct net_proto_family inet_family_ops;
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
@@ -475,6 +480,15 @@ EXPORT_SYMBOL(kill_fasync);
 
 EXPORT_SYMBOL(if_port_text);
 
+#ifdef CONFIG_HIPPI
+EXPORT_SYMBOL(hippi_type_trans);
+EXPORT_SYMBOL(init_hippi_dev);
+EXPORT_SYMBOL(unregister_hipdev);
+#endif
+
+EXPORT_SYMBOL(sysctl_wmem_max);
+EXPORT_SYMBOL(sysctl_rmem_max);
+
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
 #include<linux/if_ltalk.h>
 EXPORT_SYMBOL(ltalk_setup);
index 052ea8eea31c496c06e52321c943addfd9e9c40e..c8094a882641ea9976158e1a80b625121faafd94 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
-#include <linux/module.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
index 74d45fe96880a7e81ceef848ed55ba00377bf711..8baf254ebf8ac3538eae7a7d6805d89d1a9df1e0 100644 (file)
@@ -14,7 +14,6 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>