S: Oak Park, Illinois 60302
S: USA
+N: Daniel J. Frasnelli
+E: dfrasnel@alphalinux.org
+W: http://www.alphalinux.org/
+P: 1024/3EF87611 B9 F1 44 50 D3 E8 C2 80 DA E5 55 AA 56 7C 42 DA
+D: DEC Alpha hacker
+D: Miscellaneous bug squisher
+
N: Jim Freeman
E: jfree@sovereign.org
W: http://www.sovereign.org/
S: Germany
N: Michael Hipp
-E: mhipp@student.uni-tuebingen.de
+E: hippm@informatik.uni-tuebingen.de
D: drivers for the racal ni5210 & ni6510 Ethernet-boards
S: Talstr. 1
S: D - 72072 Tuebingen
say M here and read Documentation/modules.txt. The module will be
called aic7xxx.o.
-Override driver defaults for commands per LUN
-CONFIG_OVERRIDE_CMDS
- Say Y here if you want to override the default maximum number of
- commands that a single device on the aic7xxx controller is allowed
- to have active at one time. This option only affects tagged queueing
- capable devices. The driver uses a value of 24 by default.
- If you say Y here, you can adjust the number of commands per LUN
- with the following configuration option.
+Enable or Disable Tagged Command Queueing by default
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+ This option causes the aic7xxx driver to attempt to use tagged command
+ queueing on any devices that claim to support it. If this is set to yes,
+ you can still turn off TCQ on troublesome devices with the use of the
+ tag_info boot parameter. See /usr/src/linux/drivers/scsi/README.aic7xxx
+ for more information on that and other aic7xxx setup commands. If this
+ option is turned off, you may still enable TCQ on known good devices by
+ use of the tag_info boot parameter.
- If unsure, say N.
-
-Maximum number of commands per LUN
-CONFIG_AIC7XXX_CMDS_PER_LUN
- Specify the maximum number of commands you would like to allocate
- per LUN (a LUN is a Logical Unit Number -- some physical SCSI
- devices, e.g. CD jukeboxes, act logically as several separate units,
- each of which gets its own number).
-
- Reasonable figures are in the range of 14 to 32 commands per device,
+ If you are unsure about your devices then it is safest to say N here.
+
+ However, TCQ can increase performance on some hard drives by as much
+ as 50% or more, so I would recommend that if you say N here, that you
+ at least read the README.aic7xxx file so you will know how to enable
+ this option manually should your drives prove to be safe in regards
+ to TCQ.
+
+ Conversely, certain drives are known to lock up or cause bus resets when
+ TCQ is enabled on them. If you have a Western Digital Enterprise SCSI
+ drive for instance, then don't even bother to enable TCQ on it as the
+ drive will become unreliable, and it will actually reduce performance.
+
+Default number of TCQ commands per device
+CONFIG_AIC7XXX_CMDS_PER_DEVICE
+ Specify the number of commands you would like to allocate per SCSI
+ device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+ Reasonable figures are in the range of 8 to 24 commands per device,
but depending on hardware could be increased or decreased from that
figure. If the number is too high for any particular device, the
driver will automatically compensate usually after only 10 minutes
- of uptime and will issue a message to alert you to the fact that the
- number of commands for that device has been reduced. It will not
- hinder performance if some of your devices eventually have their
- commands per LUN reduced, but is a waste of memory if all of your
- devices end up reducing this number down to a more reasonable
- figure. Default: 24
+ of uptime. It will not hinder performance if some of your devices
+ eventually have their command depth reduced, but is a waste of memory
+ if all of your devices end up reducing this number down to a more
+ reasonable figure.
+
+ NOTE: Certain very broken drives are known to lock up when given more
+ commands than they like to deal with. Quantum Fireball drives are the
+ most common in this category. For the Quantum Fireball drives I would
+ suggest no more than 8 commands per device.
+
+ Default: 8
Collect statistics to report in /proc
CONFIG_AIC7XXX_PROC_STATS
module, say M here and read Documentation/modules.txt as well as
Documentation/networking/net-modules.txt.
+SKnet MCA support
+CONFIG_SKMC
+ This are Micro Channel ethernet adapters. You need to set CONFIG_MCA
+ to use this driver. It's both available as an in-kernel driver and
+ as a module ( = code which can be inserted in and removed from the
+ running kernel whenever you want). If you want to compile it as a module,
+ say M here and read Documentation/modules.txt as well as
+ Documentation/networking/net-modules.txt. If you plan to use more than
+ one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+ available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. Supported
+ cards are the SKnet Junior MC2 and the SKnet MC2(+). Distinguishing
+ both cards is done automatically. Note that using multiple boards
+ of different type hasn't been tested with this driver.
+
EISA, VLB, PCI and on board controllers
CONFIG_NET_EISA
This is another class of network cards which attach directly to the
SOUND Appropriate sound system support is enabled.
VGA The VGA console has been enabled.
VT Virtual terminal support is enabled.
- XT IBM PC/XT support is enabled.
+ XT IBM PC/XT MFM hard disk support is enabled.
In addition, the following text indicates that the option:
Documentation on setup and use of EtherTap.
Contact Jay Schulist <Jay.Schulist@spacs.k12.wi.us> if you
-have questions or need futher assistance.
+have questions or need further assistance.
Introduction
============
1.2.3.4 will be the router to the outside world
1.2.3.5 our box
- 2.0.0.1 our box (appletalk side)
- 2.0.0.* a pile of macintoys
+ 2.0.0.1 our box (AppleTalk side)
+ 2.0.0.* a pile of Macintoys
-[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> macs
+[1.2.3.4]-------------1.2.3.5[Our Box]2.0.0.1---------> Macs
The routing on our box would be
Card Configuration:
-The interrupts and so forth are configured via the dipswitch on the
+The interrupts and so forth are configured via the DIP switch on the
board. Set the switches so as not to conflict with other hardware.
Interrupts -- set at most one. If none are set, the driver uses
- Notes on Linux's SG driver version 2.1.30
+ Notes on Linux's SG driver version 2.1.34
-----------------------------------------
- 990328
+ 990606
Introduction
============
+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 siblings 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 digitally amongst other things.
+
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.
+describing version 2.1.34 . The original driver was written by Lawrence
+Foard and 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.
+This is an abridged version of the sg documentation that is targeted
+at the linux/Documentation directory. The full document can be found
+at http://www.torque.net/sg/p/scsi-generic_long.txt .
-The interface and usage of the original sg driver has been documented
+The interface and usage of the original sg driver have 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.
+ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO-SCSI-Programming-HOWTO .
+A copy of this document can be found at:
+http://www.torque.net/sg/p/original/HOWTO-SCSI-Programming-HOWTO .
** 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).
+the sg device driver. The author is not aware of any useful
+pre-existing applications that have problems with version 2 (yet).
Architecture
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.
+The unifying layer of the SCSI sub-system is the so-called mid-level.
+Below that are the "low level" drivers which are the drivers for the
+various adapters supported by Linux. Also at this level are pseudo
+adapter drivers such as ide-scsi which converts the SCSI protocol to
+ATAPI (which are similar to one another) for use by IDE devices.
Since sg is a character device it supports the traditional Unix
system calls of open(), close(), read(), write() and ioctl(). Two other
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 'pack_len' is bizarre and ends up having the 'reply_len' put in it
+(perhaps it had a use at some stage). Even though it looks like an
+input variable, it is not read by sg internally (only written).
The 'reply_len' is the length of the data the corresponding read()
will/should request (including the sg_header).
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
+The 'result' is also bizarre, turning certain types of host codes to 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"
+The 'twelve_byte' field overrides the internal SCSI command length detection
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:
+a command length of 12 bytes.
+The command length detection algorithm is as follows:
Group: 0 1 2 3 4 5 6 7
Length: 6 10 10 12 12 12 10 10
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) */
+ int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
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. */
+ unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases:
+ when target_status is CHECK_CONDITION or
+ when target_status is COMMAND_TERMINATED or
+ when (driver_status & DRIVER_SENSE) is true. */
}; /* This structure is 36 bytes long on i386 */
Firstly the new header is binary compatible with the original. This is
the value of 'pack_id' available after a read() is the value given to that
variable in the prior, corresponding write().
+The SCSI command length can now be given directly using the SG_NEXT_CMD_LEN
+ioctl().
+
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>):
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
+the ide-scsi 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):
+whose "defines" are not visible outside the kernel. A copy of these
+defines can be found in sg_err.h (see the utilities section):
#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_BAD_TARGET 0x04 /* BAD target, device not responding? */
#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_ERROR 0x07 /* Internal error [DMA underrun on aic7xxx]*/
#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 */
+#define DID_SOFT_ERROR 0x0b /* The low level driver wants 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:
+DRIVER_SENSE) is true the 'sense_buffer' is also output. A copy of these
+defines can be found in sg_err.h (see the utilities section):
#define DRIVER_OK 0x00 /* Typically no suggestion */
#define DRIVER_BUSY 0x01
#define DRIVER_SOFT 0x02
#define DRIVER_INVALID 0x05
#define DRIVER_TIMEOUT 0x06
#define DRIVER_HARD 0x07
-#define DRIVER_SENSE 0x08
+#define DRIVER_SENSE 0x08 /* Implies sense_buffer output */
/* above status 'or'ed with one of the following suggestions */
#define SUGGEST_RETRY 0x10
#define SUGGEST_ABORT 0x20
#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
-
+'other_flags' still remains as a 10 bit field (reduced from 31 bits), so
+code that places 0 in it will still be happy. It is not used.
System Calls
Unix operating system calls when applied to a SCSI generic device
using this version of the device driver.
-open
-----
+open(const char * filename, int flags)
+--------------------------------------
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.
+sg devices with entries like: /dev/sg/c1b2t3u4 .] 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
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.
+allowed. These flags are found in <fcntl.h> .
By default, sequencing is per file descriptor in this version of sg. This
means, for example that 2 processes can independently manipulate the same
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().
+The driver will attempt to reserve SG_DEF_RESERVED_SIZE bytes (32KBytes in
+the current sg.h) on open(). The size of this reserved buffer can
+subsequently be modified with the SG_SET_RESERVED_SIZE ioctl(). In both
+cases these are requests subject to various dynamic constraints. The actual
+amount of memory obtained can be found by the SG_GET_RESERVED_SIZE ioctl().
+The reserved buffer will be used if:
+ - it is not already in use (eg when command queuing is in use)
+ - a write() does not call for a buffer size larger than the
+ reserved size.
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
+EACCES Either the user doesn't have appropriate permissions on
+ 'filename' or attempted to use both O_RDONLY and O_EXCL
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 ...
+ENODEV sg not compiled into kernel or the kernel cannot find the
+ sg module (or it can't initialize itself (low memory??))
+ENOENT given filename not found
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
+ENXIO either there is no attached device corresponding to given
+ filename or scsi sub-system is currently processing some
+ error (eg doing a device reset) or the sg driver/module
+ removed or corrupted
-write
------
+write(int sg_fd, const void * buffer, size_t count)
+---------------------------------------------------
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
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
+EDOM a) command queuing off: a packet is already queued
+ b) command queuing on: too many packets queued
+ (SG_MAX_QUEUE exceeded)
+ c) SCSI command length given in SG_NEXT_CMD_LEN too long
+EFAULT 'buffer' for 'count' bytes is an invalid memory range
+EIO incoming buffer too short. It should be at least (6 +
+ sizeof(struct sg_header))==42 bytes long
ENOMEM can't get memory for DMA. Take evasive action ...
- (see section on memory)
+ENXIO either scsi sub-system is currently processing some error
+ (eg doing a device reset) or the sg driver/module removed
+ or corrupted
-read
-----
+read(int sg_fd, void * buffer, size_t count)
+--------------------------------------------
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 .
+sufficient to accommodate this packet to avoid truncation. Truncation occurs
+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
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
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
+EFAULT 'buffer' for 'count' bytes is an invalid memory range
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
+ENXIO either scsi sub-system is currently processing some error
+ (eg doing a device reset) or the sg driver/module removed
+ or corrupted
-close
------
+close(int sg_fd)
+----------------
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
+arrange for 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
(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.
+A problem persists in version 2.1.34 if the sg driver is a module and is
+removed while packets are still "in flight".
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)
--------------------
+ioctl(int sg_fd, int command, ...) [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.
+more ...
+If a ioctl command is not recognized by sg (and the various lower levels
+that it may pass the command on to) then the error EINVAL occurs. If an
+invalid address is given (in the 3rd argument) then the error EFAULT occurs.
Those commands with an appended "+" are new in version 2.
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).
+already "in flight" will not be affected. The default value is set
+on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). This default is
+currently 1 minute and may not be long enough for formats.
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
+whether the host (adapter) is connected to a real SCSI bus or is an
emulated one (eg ide-scsi device driver). A value of 1 means emulated
while 0 is not.
+SG_SET_TRANSFORM W:
+Third argument is ignored. Only is meaningful when SG_EMULATED host has
+yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
+an EINVAL error occurs. The default state is to _not_ transform SCSI
+commands to the corresponding ATAPI commands but pass them straight
+through as is. [Only certain classes of SCSI commands need to be
+transformed to their ATAPI equivalents.] Making this ioctl command causes
+transforms to occur thereafter. Subsequent calls to this ioctl command
+have no additional effect. Beware, this state will affect all devices
+(and hence all related sg file descriptors) associated with this ide-scsi
+"bus".
+The author of ide-scsi has pointed out that this is not the intended
+behaviour which is a 3rd argument of 0 to disable transforms and 1 to
+enable transforms. Note the 3rd argument is an 'int' not a 'int *'.
+Perhaps the intended behaviour will be implemented soon.
+
+SG_GET_TRANSFORM:
+Third argument is ignored. Only is meaningful when SG_EMULATED host has
+yielded 1 (ie the low-level is the ide-scsi device driver); otherwise
+an EINVAL error occurs. Returns 0 to indicate _not_ transforming SCSI
+to ATAPI commands (default). Returns 1 when it is transforming.
+
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)
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
+extremely rare. If the "reserved" 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.
+Only the current file descriptor is affected.
SG_GET_LOW_DMA +:
Assumes 3rd argument points to an int and places 0 or 1 in it. 0
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.
+Assumes 3rd argument is pointing to an object of type Sg_scsi_id (see
+sg.h) 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()
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.
+Only the current file descriptor is affected by this command.
-SG_GET_LOW_DMA +:
+SG_GET_PACK_ID +:
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.
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)
+Assumes 3rd argument is pointing to an int. That value will be used to
+request a new reserved buffer of that size. The previous reserved buffer
+is freed (if it is not in use; if it was in use -EBUSY is returned).
+A new reserved buffer is then allocated and its actual size can be found by
+calling the SG_GET_RESERVED_SIZE ioctl(). The reserved buffer is then used
+for DMA purposes by subsequent write() commands if it is not already in
+use and if the write() is not calling for a buffer size larger than that
+reserved. The reserved buffer may well be a series of kernel buffers if the
+adapter supports scatter-gather. Large buffers can be requested (eg 1 MB).
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.
+the reserved buffer from open() or the most recent SG_SET_RESERVED_SIZE
+ioctl() call on this fd. The result can be 0 if memory is very tight. In
+this case it may not be wise to attempt something 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.
+state and there is one or more _other_ file descriptors using this sg
+device then an EBUSY 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 use 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
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.
+Changing the queuing state only affects write()s done after the change.
+Only the current file descriptor is affected 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_UNDERRUN_FLAG +:
+Assumes 3rd argument is pointing to an int. 0 (current default, set by
+SG_DEF_UNDERRUN_FLAG in sg.h) requests underruns be ignored. 1 requests
+that underruns be flagged. [The only low level driver that acts on this
+at the moment is the aic7xxx which yields a DID_ERROR error on underrun.]
+Only the current file descriptor is affected by this command (unless
+"per device" sequencing has been selected).
+
+SG_GET_UNDERRUN_FLAG +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+that underruns are not being reported. 1 implies that underruns are being
+reported (see SG_SET_UNDERRUN_FLAG for more details).
+
+SG_NEXT_CMD_LEN +:
+Assumes 3rd argument is pointing to an int. The value of the int (if > 0)
+will be used as the SCSI command length of the next SCSI command sent to
+a write() on this fd. After that write() the SCSI command length logic is
+reset to use automatic length detection (ie depending on SCSI command group
+and the 'twelve_byte' field). If the current SCSI command length maximum of
+12 is exceeded then the affected write() will yield an EDOM error.
+Giving this ioctl() a value of 0 will set automatic length detection for
+the next write(). N.B. Only the following write() on this fd is affected by
+this ioctl().
+
+SG_GET_VERSION_NUM +:
+Assumes 3rd argument points to an int. The version number is then placed
+in that int. A sg version such as 2.1.34 will yield "20134" from this ioctl.
+
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
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
-----
+poll(struct pollfd * udfds, unsigned int nfds, int timeout_ms)
+--------------------------------------------------------------
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.
+for polling; and optionally with asynchronous notification as well 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
+When POLLIN is set it implies that a read() will not block (nor 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
+(ie will _not_ yield an EDOM error). The setting of POLLOUT is affected
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.
+the data is being retrieved.
Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
it is per device.
-fcntl
------
+fcntl(int sg_fd, int cmd) or fcntl(int sg_fd, int cmd, long arg)
+----------------------------------------------------------------
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
+file descriptor. The following 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.
+found, switching to normal blocked io. A working example of this logic
+is in the sg_scan 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 ... */
+/* when 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 */
+/* since, for simple apps, it 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
+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.
+is in the sg_poll test program.
sigemptyset(&sig_set)
sigaddset(&sig_set, SIGPOLL)
Utility and Test Programs
=========================
+See the README file in the sg_utils<date>.tgz tarball. At the time of
+writing this was sg_utils990527.tgz .
+
+Briefly, that tarball contains the following utilities:
+sg_dd512 'dd' like program that assumes 512 byte blocks size
+sg_dd2048 'dd' like program that assumes 2048 byte blocks size
+sgq_dd512 like 'sg_dd512' but does command queuing on "if"
+sg_scan outputs information (optionally Inquiry) on SCSI devices
+sg_rbuf tests SCSI bus transfer speed (without physical IO)
+sg_whoami outputs info (optionally capacity) of given SCSI device
+sginfo outputs "mode" information about SCSI devices (it is a
+ re-port of the scsiinfo program onto the sg interface)
+
+It also contains the following test programs:
+sg_debug outputs sg driver state to console/log file
+sg_poll tests asynchronous notification
+sg_inquiry does a SCSI Inquiry command (from original HOWTO)
+sg_tst_med checks presence of media (from original HOWTO)
+
+There are also 2 source files (sg_err.[hc]) for outputting and categorizing
+SCSI 2 errors and warnings. This code is used by most of the above
+utility and test programs.
+
+The following programs: sg_dd512, sg_dd2048, sg_scan, sg_rbuf, sg_tst_med,
+sg_inquiry and sginfo, can be compiled either for this new sg driver _or_
+the original sg driver.
+
+
+Header files
+============
+User applications need to find the correct "sg.h" header file matching
+their kernel in order to write code using the sg device driver. This is
+sometimes more difficult than it should be. The correct "sg.h" will usually
+be found at /usr/src/linux/include/scsi/sg.h . Another important header
+file is "scsi.h" which will be in the same directory.
+
+Several distributions have taken their own copies of these files and placed
+them in /usr/include/scsi which is where "#include <scsi/sg.h>" would go
+looking. The directory /usr/include/scsi _should_ be a symbolic link to
+/usr/src/linux/include/scsi/ . It was is Redhat 5.1 and 5.2 but it is
+not is Redhat 6.0 . Some other distributions have the same problem. To
+solve this (as root) do the following:
+
+# cd /usr/include
+# mv scsi scsi_orig
+# ln -s ../src/linux/include/scsi scsi
+
+This doesn't seem to be a problem with /usr/include/linux (at least in
+Redhat where it is a symbolic link) so it is hard to understand why
+/usr/include/scsi is defined the way it is. The fact the
+/usr/include/linux is a symbolic link opens up the following solution
+proposed by the author of cdparanoia (Monty):
+#include <linux/../scsi/sg.h>
+
+
+Extra information in scsi-generic_long.txt
+==========================================
+This document is an abridged form of a more comprehensive document called
+scsi-generic_long.txt (see www.torque.net/sg/p/scsi-generic_long.txt).
+
+The longer document contains additional sections on:
+ - memory issues
+ - ioctl()s in common with sd, st + sr
+ - distinguishing the original from the new driver
+ - SG_BIG_BUFF and friends
+ - shortcomings
+ - future directions
+ - an appendix with some SCSI 2 information in it
+
+
+Conclusion
+==========
+The SCSI generic packet device driver attempts to make as few assumptions
+as possible about the device it is connected to while giving applications
+using it as much flexibility as possible on the SCSI command level. Sg
+needs to hide the "messy" kernel related details while protecting
+the integrity of the kernel against sg "abuse". Some of these aims are
+contradictory and some compromises need to be made. For example: should
+a sg based application be able to reset a SCSI bus when that could cause
+collateral damage to a disk holding the root file system? There is no
+easy answer to this and many other related questions.
+
+If you have any suggestion about sg (or improving (the accuracy of) this
+document) please contact me.
+
+
+Douglas Gilbert
+dgilbert@interlog.com
<HTML><HEAD>
-<TITLE>Video4Linux Kernel API Reference v0.1:19980516</TITLE>
+<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE>
</HEAD>
+<! Revision History: >
+<! 4/30/1999 - Fred Gleason (fredg@wava.com)>
+<! Documented extensions for the Radio Data System (RDS) extensions >
<BODY bgcolor="#ffffff">
<H3>Devices</H3>
Video4Linux provides the following sets of device files. These live on the
</TABLE>
<P>
Merely setting the window does not enable capturing. Overlay capturing
-is activatied by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
+is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
disabled by passing it a value of 0.
<P>
Some capture devices can capture a subfield of the image they actually see.
nature of the channel itself.
<P>
The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the
-capture to this input. It is not defined whether paramters such as colour
+capture to this input. It is not defined whether parameters such as colour
settings or tuning are maintained across a channel switch. The caller should
maintain settings as desired for each channel. (This is reasonable as
different video inputs may have different properties).
<TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD>
<TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD>
<TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD>
+<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD>
+<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD>
</TABLE>
<P>
The following modes are defined
<TR><TD><b>teletext</b><TD>Teletext device</TD>
</TABLE>
<P>
-
+<H3>RDS Datastreams</H3>
+For radio devices that support it, it is possible to receive Radio Data
+System (RDS) data by means of a read() on the device. The data is packed in
+groups of three, as follows:
+<TABLE>
+<TR><TD>First Octet</TD><TD>Least Siginificant Byte of RDS Block</TD></TR>
+<TR><TD>Second Octet</TD><TD>Most Siginificant Byte of RDS Block
+<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit. Indicates that
+an uncorrectable error occured during reception of this block.</TD></TR>
+<TR><TD> </TD><TD>Bit 6:</TD><TD>Corrected bit. Indicates that
+an error was corrected for this data block.</TD></TR>
+<TR><TD> </TD><TD>Bits 5-3:</TD><TD>Reeived Offset. Indicates the
+offset received by the sync system.</TD></TR>
+<TR><TD> </TD><TD>Bits 2-0:</TD><TD>Offset Name. Indicates the
+offset applied to this data.</TD></TR>
+</TABLE>
</BODY>
</HTML>
If this 64MB area overlaps the IO memory of the Bt848 you also have to
remap this. E.g.: insmod bttv vidmem=0xfb0 remap=0xfa0
- If the videomemory is found at the right place and there are no address
- conflicts but still no picture (or the computer even crashes.),
- try disabling features of your PCI chipset in the BIOS Setup.
+ If the video memory is found at the right place and there are no address
+ conflicts but still no picture (or the computer even crashes),
+ try disabling features of your PCI chipset in the BIOS setup.
Frank Kapahnke <frank@kapahnke.prima.ruhr.de> also reported that problems
with his S3 868 went away when he upgraded to XFree 3.2.
Disable backing store by starting X with the option "-bs"
-- When using 32bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
+- When using 32 bpp in XFree or 24+8bpp mode in AccelX 3.1 the system
can sometimes lock up if you use more than 1 bt848 card at the same time.
You will always get pixel errors when e.g. using more than 1 card in full
screen mode. Maybe we need something faster than the PCI bus ...
-- Some S3 cards and the Matrox Mystique will produce pixel erros with
- full resolution in 32bit mode.
+- Some S3 cards and the Matrox Mystique will produce pixel errors with
+ full resolution in 32-bit mode.
-- Some video cards have problems with Accelerated X 4.1
\ No newline at end of file
+- Some video cards have problems with Accelerated X 4.1
So you should have TV with (stereo) sound now. Radio does _not_ work.
It probably does not work with sat receivers. I can't test this and
-therefore hav'nt added support for it yet. If someone needs this and
+therefore have not added support for it yet. If someone needs this and
can help testing the sat stuff, drop me a note.
Gerd
--- /dev/null
+
+Support for the Leadtek WinView 601 TV/FM by Jon Tombs <jon@gte.esi.us.es>
+
+This card is basically the same as all the rest (Bt484A, Philips tuner),
+the main difference is that they have attached a programmable attenuator to 3
+GPIO lines in order to give some volume control. They have also stuck an
+infra-red remote control decoded on the board, I will add support for this
+when I get time (it simple generates an interrupt for each key press, with
+the key code is placed in the GPIO port).
+
+I don't yet have any application to test the radio support. The tuner
+frequency setting should work but it is possible that the audio multiplexer
+is wrong. If it doesn't work, send me email.
+
+
+- No Thanks to Leadtek they refused to answer any questions about their
+hardware. The driver was written by visual inspection of the card. If you
+use this driver, send an email insult to them, and tell them you won't
+continue buying their hardware unless they support Linux.
+
+- Little thanks to Princeton Technology Corp (http://www.princeton.com.tw)
+who make the audio attenuator. Their publicly available data-sheet available
+on their web site doesn't include the chip programming information! Hidden
+on their server are the full data-sheets, but don't ask how I found it.
+
+To use the driver I use the following options, the tuner and pll settings might
+be different in your country
+
+insmod videodev
+insmod i2c scan=1 i2c_debug=0 verbose=0
+insmod tuner type=1 debug=0
+insmod bttv pll=1 radio=1 card=17
+
components on their cards. (E.g. how the tuner type is detected)
Without their card I could not have debugged the NTSC mode.
-- Hauppauge for telling how the sound input is selected and what compenents
+- Hauppauge for telling how the sound input is selected and what components
they do and will use on their radio cards.
Also many thanks for faxing me the FM1216 data sheet.
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_KMOD=y
#
# General setup
#
-CONFIG_NATIVE=y
CONFIG_ALPHA_GENERIC=y
# CONFIG_ALPHA_ALCOR is not set
# CONFIG_ALPHA_XL is not set
# CONFIG_ALPHA_P2K is not set
# CONFIG_ALPHA_RAWHIDE is not set
# CONFIG_ALPHA_RUFFIAN is not set
+# CONFIG_ALPHA_RX164 is not set
# CONFIG_ALPHA_SX164 is not set
# CONFIG_ALPHA_SABLE is not set
# CONFIG_ALPHA_TAKARA is not set
-# CONFIG_SMP is not set
CONFIG_PCI=y
-CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y
+# CONFIG_SMP is not set
# CONFIG_PCI_QUIRKS is not set
CONFIG_PCI_OLD_PROC=y
CONFIG_NET=y
#
# Networking options
#
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
# CONFIG_NETLINK is not set
# CONFIG_FIREWALL is not set
# CONFIG_FILTER is not set
# (it is safe to leave these untouched)
#
# CONFIG_INET_RARP is not set
-CONFIG_IP_NOSR=y
CONFIG_SKB_LARGE=y
#
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
CONFIG_SCSI_QLOGIC_ISP=y
+# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_SEAGATE is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_EEXPRESS_PRO100 is not set
# CONFIG_NE2K_PCI is not set
# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
# CONFIG_NET_RADIO is not set
# CONFIG_TR is not set
# CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
+# CONFIG_RCPCI is not set
# CONFIG_WAN_DRIVERS is not set
# CONFIG_LAPBETHER is not set
# CONFIG_X25_ASY is not set
# CONFIG_ISDN is not set
#
-# CD-ROM drivers (not for SCSI or IDE/ATAPI drives)
+# Old CD-ROM drivers (not SCSI, not IDE)
#
# CONFIG_CD_NO_IDESCSI is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
CONFIG_MOUSE=y
+
+#
+# Mice
+#
# CONFIG_ATIXL_BUSMOUSE is not set
# CONFIG_BUSMOUSE is not set
# CONFIG_MS_BUSMOUSE is not set
CONFIG_PSMOUSE=y
# CONFIG_82C710_MOUSE is not set
# CONFIG_PC110_PAD is not set
-# CONFIG_UMISC is not set
# CONFIG_QIC02_TAPE is not set
# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
# CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
# CONFIG_JOYSTICK is not set
+# CONFIG_DTLK is not set
#
# Ftape, the floppy tape device driver
# Filesystems
#
# CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+# CONFIG_NFSD_SUN is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
# CONFIG_SMB_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_UFS_FS is not set
-CONFIG_DEVPTS_FS=y
+# CONFIG_NCP_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_BSD_DISKLABEL is not set
# CONFIG_MAC_PARTITION is not set
+# CONFIG_SMD_DISKLABEL is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
# CONFIG_NLS is not set
#
.end __smp_callin
#endif /* __SMP__ */
- .align 3
- .globl wrent
- .ent wrent
-wrent:
- .prologue 0
- call_pal PAL_wrent
- ret ($26)
- .end wrent
-
- .align 3
- .globl wrkgp
- .ent wrkgp
-wrkgp:
- .prologue 0
- call_pal PAL_wrkgp
- ret ($26)
- .end wrkgp
-
- .align 3
- .globl wrusp
- .ent wrusp
-wrusp:
- .prologue 0
- call_pal PAL_wrusp
- ret ($26)
- .end wrusp
-
- .align 3
- .globl rdusp
- .ent rdusp
-rdusp:
- .prologue 0
- call_pal PAL_rdusp
- ret ($26)
- .end rdusp
-
- .align 3
- .globl rdmces
- .ent rdmces
-rdmces:
- .prologue 0
- call_pal PAL_rdmces
- ret ($26)
- .end rdmces
-
- .align 3
- .globl wrmces
- .ent wrmces
-wrmces:
- .prologue 0
- call_pal PAL_wrmces
- ret ($26)
- .end wrmces
-
- .align 3
- .globl whami
- .ent whami
-whami:
- .prologue 0
- call_pal PAL_whami
- ret ($26)
- .end whami
-
- .align 3
- .globl wripir
- .ent wripir
-wripir:
- .prologue 0
- call_pal PAL_wripir
- ret ($26)
- .end wripir
-
- .align 3
- .globl wrvptptr
- .ent wrvptptr
-wrvptptr:
- .prologue 0
- call_pal PAL_wrvptptr
- ret ($26)
- .end wrvptptr
-
#
# The following two functions are needed for supporting SRM PALcode
# on the PC164 (at least), since that PALcode manages the interrupt
extern void wrmces(unsigned long mces);
extern void cserve_ena(unsigned long);
extern void cserve_dis(unsigned long);
-extern void __smp_callin(void);
+extern void __smp_callin(unsigned long);
/* entry.S */
extern void entArith(void);
#include "proto.h"
-#include "proto.h"
-
-
#define DEBUG_SIG 0
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
while (!smp_threads_ready)
barrier();
- printk(KERN_INFO "SMP: commencing CPU %d current %p\n",
- cpuid, current);
+ DBGS(("smp_callin: commencing CPU %d current %p\n",
+ cpuid, current));
/* Do nothing. */
cpu_idle(NULL);
+ hwrpb->processor_offset
+ i * hwrpb->processor_size);
- printk(KERN_INFO "recv_secondary_console_msg: on %d from %d"
- " HALT_REASON 0x%lx FLAGS 0x%lx\n",
- mycpu, i, cpu->halt_reason, cpu->flags);
+ DBGS(("recv_secondary_console_msg: on %d from %d"
+ " HALT_REASON 0x%lx FLAGS 0x%lx\n",
+ mycpu, i, cpu->halt_reason, cpu->flags));
cnt = cpu->ipc_buffer[0] >> 32;
if (cnt <= 0 || cnt >= 80)
void
smp_send_reschedule(int cpu)
{
+#if DEBUG_IPI_MSG
+ if (cpu == hard_smp_processor_id())
+ printk(KERN_WARNING
+ "smp_send_reschedule: Sending IPI to self.\n");
+#endif
send_ipi_message(1L << cpu, IPI_RESCHEDULE);
}
smp_send_stop(void)
{
unsigned long to_whom = cpu_present_mask ^ (1L << smp_processor_id());
+#if DEBUG_IPI_MSG
+ if (hard_smp_processor_id() != boot_cpu_id)
+ printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
+#endif
send_ipi_message(to_whom, IPI_CPU_STOP);
}
void
flush_tlb_all(void)
{
- tbia();
-
/* Although we don't have any data to pass, we do want to
synchronize with the other processors. */
if (smp_call_function(ipi_flush_tlb_all, NULL, 1, 1)) {
printk(KERN_CRIT "flush_tlb_all: timed out\n");
}
+
+ tbia();
}
static void
\f
#if DEBUG_SPINLOCK
-
-#ifdef MANAGE_SPINLOCK_IPL
-
-static inline long
-spinlock_raise_ipl(spinlock_t * lock)
-{
- long min_ipl = lock->target_ipl;
- long last_ipl = swpipl(7);
- if (last_ipl < 7 && min_ipl < 7)
- setipl(min_ipl < last_ipl ? last_ipl : min_ipl);
- return last_ipl;
-}
-
-static inline void
-spinlock_restore_ipl(long prev)
-{
- setipl(prev);
-}
-
-#else
-
-#define spinlock_raise_ipl(LOCK) ((void)(LOCK), 0)
-#define spinlock_restore_ipl(PREV) ((void)(PREV))
-
-#endif /* MANAGE_SPINLOCK_IPL */
-
void
spin_unlock(spinlock_t * lock)
{
- long old_ipl = lock->saved_ipl;
mb();
lock->lock = 0;
- spinlock_restore_ipl(old_ipl);
+
+ lock->on_cpu = -1;
+ lock->previous = NULL;
+ lock->task = NULL;
+ lock->base_file = "none";
+ lock->line_no = 0;
}
void
-spin_lock(spinlock_t * lock)
+debug_spin_lock(spinlock_t * lock, const char *base_file, int line_no)
{
long tmp;
long stuck;
unsigned long started = jiffies;
int printed = 0;
int cpu = smp_processor_id();
- long old_ipl = spinlock_raise_ipl(lock);
stuck = 1L << 28;
try_again:
if (stuck < 0) {
printk(KERN_WARNING
- "spinlock stuck at %p(%d) owner %s at %p(%d) st %ld\n",
- inline_pc, cpu, lock->task->comm, lock->previous,
- lock->task->processor, lock->task->state);
+ "%s:%d spinlock stuck in %s at %p(%d)"
+ " owner %s at %p(%d) %s:%d\n",
+ base_file, line_no,
+ current->comm, inline_pc, cpu,
+ lock->task->comm, lock->previous,
+ lock->on_cpu, lock->base_file, lock->line_no);
stuck = 1L << 36;
printed = 1;
goto try_again;
}
/* Exiting. Got the lock. */
- lock->saved_ipl = old_ipl;
lock->on_cpu = cpu;
lock->previous = inline_pc;
lock->task = current;
+ lock->base_file = base_file;
+ lock->line_no = line_no;
if (printed) {
- printk(KERN_WARNING "spinlock grabbed at %p(%d) %ld ticks\n",
- inline_pc, cpu, jiffies - started);
+ printk(KERN_WARNING
+ "%s:%d spinlock grabbed in %s at %p(%d) %ld ticks\n",
+ base_file, line_no, current->comm, inline_pc,
+ cpu, jiffies - started);
}
}
int
-spin_trylock(spinlock_t * lock)
+debug_spin_trylock(spinlock_t * lock, const char *base_file, int line_no)
{
- long old_ipl = spinlock_raise_ipl(lock);
int ret;
if ((ret = !test_and_set_bit(0, lock))) {
- mb();
- lock->saved_ipl = old_ipl;
lock->on_cpu = smp_processor_id();
lock->previous = __builtin_return_address(0);
lock->task = current;
} else {
- spinlock_restore_ipl(old_ipl);
+ lock->base_file = base_file;
+ lock->line_no = line_no;
}
return ret;
}
* linux/arch/alpha/kernel/sys_dp264.c
*
* Copyright (C) 1995 David A Rusling
- * Copyright (C) 1996 Jay A Estabrook
- * Copyright (C) 1998 Richard Henderson
+ * Copyright (C) 1996, 1999 Jay A Estabrook
+ * Copyright (C) 1998, 1999 Richard Henderson
*
* Code supporting the DP264 (EV6+TSUNAMI).
*/
#define dev2hose(d) (bus2hose[(d)->bus->number]->pci_hose_index)
/*
- * HACK ALERT! only CPU#0 is used currently
+ * HACK ALERT! only the boot cpu is used for interrupts.
*/
static void
#if 1
printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n");
#else
- unsigned long pld;
- unsigned int i;
-
- /* Read the interrupt summary register of TSUNAMI */
- pld = TSUNAMI_cchip->dir0.csr;
-
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 55) {
- isa_device_interrupt(vector, regs);
- } else { /* if not timer int */
- handle_irq(16 + i, 16 + i, regs);
- }
+ unsigned long pld;
+ unsigned int i;
+
+ /* Read the interrupt summary register of TSUNAMI */
+ pld = TSUNAMI_cchip->dir0.csr;
+
+ /*
+ * Now for every possible bit set, work through them and call
+ * the appropriate interrupt handler.
+ */
+ while (pld) {
+ i = ffz(~pld);
+ pld &= pld - 1; /* clear least bit set */
+ if (i == 55)
+ isa_device_interrupt(vector, regs);
+ else
+ handle_irq(16 + i, 16 + i, regs);
#if 0
TSUNAMI_cchip->dir0.csr = 1UL << i; mb();
tmp = TSUNAMI_cchip->dir0.csr;
#endif
- }
+ }
#endif
}
ack = irq = (vector - 0x800) >> 4;
- /*
- * The EV6 machines SRM console reports PCI interrupts with a vector
- * calculated by:
+ /*
+ * The SRM console reports PCI interrupts with a vector calculated by:
*
* 0x900 + (0x10 * DRIR-bit)
*
- * So bit 16 shows up as IRQ 32, etc, etc.
+ * So bit 16 shows up as IRQ 32, etc.
*
* On DP264/BRICK/MONET, we adjust it down by 16 because at least
* that many of the low order bits of the DRIR are not used, and
* so we don't count them.
- */
- if (irq >= 32)
- ack = irq = irq - 16;
+ */
+ if (irq >= 32)
+ ack = irq = irq - 16;
handle_irq(irq, ack, regs);
}
ack = irq = (vector - 0x800) >> 4;
- /*
- * The EV6 machines SRM console reports PCI interrupts with a vector
- * calculated by:
+ /*
+ * The SRM console reports PCI interrupts with a vector calculated by:
*
* 0x900 + (0x10 * DRIR-bit)
*
- * So bit 16 shows up as IRQ 32, etc, etc.
+ * So bit 16 shows up as IRQ 32, etc.
*
* CLIPPER uses bits 8-47 for PCI interrupts, so we do not need
* to scale down the vector reported, we just use it.
*
* Eg IRQ 24 is DRIR bit 8, etc, etc
- */
+ */
handle_irq(irq, ack, regs);
}
{ 32, 32, 33, 34, 35}, /* IdSel 13 slot 3 PCI0*/
{ 28, 28, 29, 30, 31}, /* IdSel 14 slot 4 PCI2*/
{ 24, 24, 25, 26, 27} /* IdSel 15 slot 5 PCI2*/
-};
+ };
const long min_idsel = 3, max_idsel = 15, irqs_per_slot = 5;
- int irq = COMMON_TABLE_LOOKUP;
-
- return irq;
+ return COMMON_TABLE_LOOKUP;
}
static int __init
monet_swizzle(struct pci_dev *dev, int *pinp)
{
- int slot, pin = *pinp;
-
- /* Check first for the built-in bridge on hose 1. */
- if (dev2hose(dev) == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) {
- slot = PCI_SLOT(dev->devfn);
- }
- else
- {
- /* Must be a card-based bridge. */
- do {
+ int slot, pin = *pinp;
+
+ /* Check first for the built-in bridge on hose 1. */
+ if (dev2hose(dev) == 1 && PCI_SLOT(dev->bus->self->devfn) == 8) {
+ slot = PCI_SLOT(dev->devfn);
+ } else {
+ /* Must be a card-based bridge. */
+ do {
/* Check for built-in bridge on hose 1. */
- if (dev2hose(dev) == 1 &&
+ if (dev2hose(dev) == 1 &&
PCI_SLOT(dev->bus->self->devfn) == 8) {
slot = PCI_SLOT(dev->devfn);
break;
- }
- pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ;
-
- /* Move up the chain of bridges. */
- dev = dev->bus->self;
- /* Slot of the next bridge. */
- slot = PCI_SLOT(dev->devfn);
- } while (dev->bus->self);
- }
- *pinp = pin;
- return slot;
+ }
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)) ;
+
+ /* Move up the chain of bridges. */
+ dev = dev->bus->self;
+ /* Slot of the next bridge. */
+ slot = PCI_SLOT(dev->devfn);
+ } while (dev->bus->self);
+ }
+ *pinp = pin;
+ return slot;
}
static int __init
{ 39, 39, 38, 37, 36}, /* IdSel 15 slot 1 */
{ 43, 43, 42, 41, 40}, /* IdSel 16 slot 2 */
{ 47, 47, 46, 45, 44}, /* IdSel 17 slot 3 */
-};
+ };
const long min_idsel = 7, max_idsel = 17, irqs_per_slot = 5;
- int irq = COMMON_TABLE_LOOKUP;
-
- return irq;
+ return COMMON_TABLE_LOOKUP;
}
static int __init
pci_fixup: webbrick_pci_fixup,
kill_arch: generic_kill_arch,
};
+
struct alpha_machine_vector clipper_mv __initmv = {
vector_name: "Clipper",
DO_EV6_MMU,
pci_fixup: clipper_pci_fixup,
kill_arch: generic_kill_arch,
};
+
/* No alpha_mv alias for webbrick/monet/clipper, since we compile them
in unconditionally with DP264; setup_arch knows how to cope. */
*
* Copyright (C) 1995 David A Rusling
* Copyright (C) 1996 Jay A Estabrook
- * Copyright (C) 1998 Richard Henderson
+ * Copyright (C) 1998, 1999 Richard Henderson
*
* Code supporting the TAKARA.
*/
#include "machvec.h"
-/*
- * WARNING WARNING WARNING
- *
- * This port is missing an update_irq_hw implementation.
- */
+static void
+takara_update_irq_hw(unsigned long irq, unsigned long mask, int unmask_p)
+{
+ unsigned int regaddr;
+
+ if (irq <= 15) {
+ if (irq <= 7)
+ outb(mask, 0x21); /* ISA PIC1 */
+ else
+ outb(mask >> 8, 0xA1); /* ISA PIC2 */
+ } else if (irq <= 31) {
+ regaddr = 0x510 + ((irq - 16) & 0x0c);
+ outl((mask >> ((irq - 16) & 0x0c)) & 0xf0000Ul, regaddr);
+ }
+}
static void
takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
if (intstatus & 4) handle_irq(16+2, 16+2, regs);
if (intstatus & 2) handle_irq(16+1, 16+1, regs);
if (intstatus & 1) handle_irq(16+0, 16+0, regs);
- } else
+ } else {
isa_device_interrupt (vector, regs);
+ }
+}
+
+static void
+takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+{
+ int irq = (vector - 0x800) >> 4;
+
+ if (irq > 15)
+ irq = ((vector - 0x800) >> 6) + 12;
+
+ handle_irq(irq, irq, regs);
}
static void __init
takara_init_irq(void)
{
- unsigned int ctlreg;
-
STANDARD_INIT_IRQ_PROLOG;
- ctlreg = inl(0x500);
- ctlreg &= ~0x8000; /* return to non-accelerated mode */
- outw(ctlreg >> 16, 0x502);
- outw(ctlreg & 0xFFFF, 0x500);
- ctlreg = 0x05107c00; /* enable the PCI interrupt register */
- outw(ctlreg >> 16, 0x502);
- outw(ctlreg & 0xFFFF, 0x500);
+ if (alpha_using_srm)
+ alpha_mv.device_interrupt = takara_srm_device_interrupt;
+
+ if (!alpha_using_srm) {
+ unsigned int ctlreg = inl(0x500);
+
+ /* Return to non-accelerated mode. */
+ ctlreg &= ~0x8000;
+ outl(ctlreg, 0x500);
+
+ /* Enable the PCI interrupt register. */
+ ctlreg = 0x05107c00;
+ outl(ctlreg, 0x500);
+ }
+
enable_irq(2);
}
-
/*
* The Takara has PCI devices 1, 2, and 3 configured to slots 20,
* 19, and 18 respectively, in the default configuration. They can
return COMMON_TABLE_LOOKUP;
}
+static int __init
+takara_swizzle(struct pci_dev *dev, int *pinp)
+{
+ int slot = PCI_SLOT(dev->devfn);
+ int pin = *pinp;
+ unsigned int ctlreg = inl(0x500);
+ unsigned int busslot = PCI_SLOT(dev->bus->self->devfn);
+
+ /* Check first for built-in bridges. */
+ if (busslot > 16 && ((1<<(36-busslot)) & ctlreg)) {
+ if (pin == 1)
+ pin += (20 - busslot);
+ else {
+ /* Must be a card-based bridge. */
+ printk(KERN_WARNING "takara_swizzle: cannot handle "
+ "card-bridge behind builtin bridge yet.\n");
+ }
+ }
+
+ *pinp = pin;
+ return slot;
+}
+
static void __init
takara_pci_fixup(void)
{
layout_all_busses(DEFAULT_IO_BASE, DEFAULT_MEM_BASE);
- common_pci_fixup(takara_map_irq, common_swizzle);
- enable_ide(0x26e);
+ common_pci_fixup(takara_map_irq, takara_swizzle);
+ /* enable_ide(0x26e); */
}
nr_irqs: 20,
irq_probe_mask: _PROBE_MASK(20),
- update_irq_hw: NULL,
+ update_irq_hw: takara_update_irq_hw,
ack_irq: generic_ack_irq,
device_interrupt: takara_device_interrupt,
/*
* linux/arch/alpha/kernel/time.c
*
- * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ * Copyright (C) 1991, 1992, 1995, 1999 Linus Torvalds
*
* This file contains the PC-specific time handling details:
* reading the RTC at bootup, etc..
#include "irq.h"
extern rwlock_t xtime_lock;
-extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
-
-extern rwlock_t xtime_lock;
-extern volatile unsigned long lost_ticks; /*kernel/sched.c*/
+extern volatile unsigned long lost_ticks; /* kernel/sched.c */
static int set_rtc_mmss(unsigned long);
! This routine checks that the keyboard command queue is empty
! (after emptying the output buffers)
!
-! No timeout is used - if this hangs there is something wrong with
-! the machine, and we probably couldn't proceed anyway.
+! Some machines have delusions that the keyboard buffer is always full
+! with no keyboard attached...
+
empty_8042:
+ push cx
+ mov cx,#0xFFFF
+
+empty_8042_loop:
+ dec cx
+ jz empty_8042_end_loop
+
call delay
in al,#0x64 ! 8042 status port
test al,#1 ! output buffer?
jz no_output
call delay
in al,#0x60 ! read it
- jmp empty_8042
+ jmp empty_8042_loop
no_output:
test al,#2 ! is input buffer full?
- jnz empty_8042 ! yes - loop
+ jnz empty_8042_loop ! yes - loop
+empty_8042_end_loop:
+ pop cx
ret
!
static ssize_t proc_mca_read(struct file*, char*, size_t, loff_t *);
static struct file_operations proc_mca_operations = {
- NULL, /* array_lseek */
- proc_mca_read, /* array_read */
- NULL, /* array_write */
- NULL, /* array_readdir */
- NULL, /* array_poll */
- NULL, /* array_ioctl */
+ NULL, /* llseek */
+ proc_mca_read, /* read */
+ NULL, /* write */
+ NULL, /* readdir */
+ NULL, /* poll */
+ NULL, /* ioctl */
NULL, /* mmap */
- NULL, /* no special open code */
+ NULL, /* open */
NULL, /* flush */
- NULL, /* no special release code */
- NULL /* can't fsync */
+ NULL, /* release */
+ NULL, /* fsync */
+ NULL, /* fascync */
+ NULL, /* check_media_change */
+ NULL, /* revalidate */
+ NULL /* lock */
};
static struct inode_operations proc_mca_inode_operations = {
- &proc_mca_operations, /* default base directory file-ops */
+ &proc_mca_operations, /* default file-ops */
NULL, /* create */
NULL, /* lookup */
NULL, /* link */
NULL, /* writepage */
NULL, /* bmap */
NULL, /* truncate */
- NULL /* permission */
+ NULL, /* permission */
+ NULL, /* smap */
+ NULL, /* updatepage */
+ NULL /* revalidate */
};
#endif
if(!MCA_bus)
return;
printk("Micro Channel bus detected.\n");
- save_flags(flags);
- cli();
/* Allocate MCA_info structure (at address divisible by 8) */
- mca_info = kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
+ mca_info = (struct MCA_info *)kmalloc(sizeof(struct MCA_info), GFP_KERNEL);
if(mca_info == NULL) {
printk("Failed to allocate memory for mca_info!");
- restore_flags(flags);
return;
}
+ memset(mca_info, 0, sizeof(struct MCA_info));
+
+ save_flags(flags);
+ cli();
/* Make sure adapter setup is off */
mca_info->slot[i].dev = 0;
if(!mca_isadapter(i)) continue;
- node = kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
+
+ node = (struct proc_dir_entry *)kmalloc(sizeof(struct proc_dir_entry), GFP_KERNEL);
if(node == NULL) {
printk("Failed to allocate memory for MCA proc-entries!");
return;
}
+ memset(node, 0, sizeof(struct proc_dir_entry));
+
if(i < MCA_MAX_SLOT_NR) {
node->low_ino = PROC_MCA_SLOT + i;
node->namelen = sprintf(mca_info->slot[i].procname,
type = inode->i_ino;
pid = type >> 16;
type &= 0x0000ffff;
- start = 0;
+ start = NULL;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
length = mca_fill((char *) page, pid, type,
&start, ppos, count);
free_page(page);
return length;
}
- if(start != 0) {
+ if(start != NULL) {
/* We have had block-adjusting processing! */
copy_to_user(buf, start, length);
*
* Force Centaur C6 processors to report MTRR capability.
* Bart Hartgers <bart@etpmod.phys.tue.nl>, May 199.
+ *
+ * Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
*/
/*
NULL, NULL, NULL, NULL }},
{ X86_VENDOR_INTEL, 6,
{ "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)",
- NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL,
+ NULL, "Pentium II (Deschutes)", "Mobile Pentium II", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
{ X86_VENDOR_AMD, 4,
{ NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
if (c->x86_model <= 16)
p = cpu_models[i].model_names[c->x86_model];
- /* Names for the Pentium II processors */
+ /* Names for the Pentium II Celeron processors
+ detectable only by also checking the cache size */
if ((cpu_models[i].vendor == X86_VENDOR_INTEL)
- && (cpu_models[i].x86 == 6)
- && (c->x86_model == 5)
- && (c->x86_cache_size == 0)) {
- p = "Celeron (Covington)";
- }
+ && (cpu_models[i].x86 == 6)){
+ if(c->x86_model == 6 && c->x86_cache_size == 128) {
+ p = "Celeron (Mendocino)";
+ }
+ else {
+ if (c->x86_model == 5 && c->x86_cache_size == 0) {
+ p = "Celeron (Covington)";
+ }
+ }
+ }
}
}
default:
lock_kernel();
sigaddset(¤t->signal, signr);
+ recalc_sigpending(current);
current->flags |= PF_SIGNALED;
do_exit(exit_code);
/* NOTREACHED */
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
static void floppy_ready(void)
{
- unsigned long flags;
-
CHECK_RESET;
if (start_motor(floppy_ready)) return;
if (fdc_dtr()) return;
if ((raw_cmd->flags & FD_RAW_READ) ||
(raw_cmd->flags & FD_RAW_WRITE))
{
- flags=claim_dma_lock();
+ unsigned long flags = claim_dma_lock();
fd_chose_dma_mode(raw_cmd->kernel_data,
raw_cmd->length);
release_dma_lock(flags);
+
/*
bttv - Bt848 frame grabber driver
{ 3, 4, 0, 2, 0x01e000, { 2, 0, 1, 1}, {0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 }},
/* "Leadtek WinView 601", */
{ 3, 1, 0, 2, 0x8300f8, { 2, 3, 1, 1,0}, {0x4fa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007,0xcfa007}},
+ /* AVEC Intercapture */
+ { 3, 1, 9, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0}},
};
#define TVCARDS (sizeof(tvcards)/sizeof(tvcard))
I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */
}
+static void init_tea6320(struct i2c_bus *bus)
+{
+ I2CWrite(bus, I2C_TEA6300, TEA6320_V, 0x28, 1); /* master volume */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FFL, 0x28, 1); /* volume left 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FFR, 0x28, 1); /* volume right 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FRL, 0x28, 1); /* volume rear left 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_FRR, 0x28, 1); /* volume rear right 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_BA, 0x11, 1); /* bass 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_TR, 0x11, 1); /* treble 0dB */
+ I2CWrite(bus, I2C_TEA6300, TEA6320_S, TEA6320_S_GMU, 1); /* mute off input A */
+}
+
static void init_tda8425(struct i2c_bus *bus)
{
I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */
if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
{
+ if(btv->type==BTTV_AVEC_INTERCAP)
+ {
+ printk(KERN_INFO "bttv%d: fader chip: TEA6320\n",btv->nr);
+ btv->audio_chip = TEA6320;
+ init_tea6320(&(btv->i2c));
+ } else {
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);
case BTTV_WINVIEW_601:
strcpy(btv->video_dev.name,"BT848(Leadtek WinView 601)");
break;
+ case BTTV_AVEC_INTERCAP:
+ strcpy(btv->video_dev.name,"(AVEC Intercapture)");
+ break;
}
printk("%s\n",btv->video_dev.name);
audio(btv, AUDIO_MUTE);
#define BTTV_ZOLTRIX 0x0f
#define BTTV_PIXVIEWPLAYTV 0x10
#define BTTV_WINVIEW_601 0x11
+#define BTTV_AVEC_INTERCAP 0x12
#define AUDIO_TUNER 0x00
#define AUDIO_RADIO 0x01
#define TDA8425 0x02
#define TDA9840 0x03
#define TEA6300 0x04
+#define TEA6320 0x05
#define I2C_TSA5522 0xc2
#define I2C_TDA9840 0x84
#define I2C_HAUPEE 0xa0
#define I2C_STBEE 0xae
#define I2C_VHX 0xc0
-#define I2C_TEA6300 0x80
+#define I2C_TEA6300 0x80 /* same as TEA6320 */
#define TDA9840_SW 0x00
#define TDA9840_LVADJ 0x02
#define TEA6300_FA 0x04 /* fader control */
#define TEA6300_SW 0x05 /* mute and source switch */
+
+#define TEA6320_V 0x00
+#define TEA6320_FFR 0x01 /* volume front right */
+#define TEA6320_FFL 0x02 /* volume front left */
+#define TEA6320_FRR 0x03 /* volume rear right */
+#define TEA6320_FRL 0x04 /* volume rear left */
+#define TEA6320_BA 0x05 /* bass */
+#define TEA6320_TR 0x06 /* treble */
+#define TEA6320_S 0x07 /* switch register */
+ /* values for those registers: */
+#define TEA6320_S_SA 0x01 /* stereo A input */
+#define TEA6320_S_SB 0x02 /* stereo B */
+#define TEA6320_S_SC 0x04 /* stereo C */
+#define TEA6320_S_GMU 0x80 /* general mute */
+
+
#define PT2254_L_CHANEL 0x10
#define PT2254_R_CHANEL 0x08
#define PT2254_DBS_IN_2 0x400
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
+ * ==FILEDATE 19990524==
*
* This code is released under the GNU General Public License (GPL)
*
*/
#define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "1.0"
+#define HDLC_VERSION "1.2"
#include <linux/version.h>
#include <linux/config.h>
{
struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
int error = 0;
+ int count;
+ unsigned long flags;
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
switch (cmd) {
case FIONREAD:
- {
- /* report count of read data available */
- /* in next available frame (if any) */
- int count;
- unsigned long flags;
- spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
- if (n_hdlc->rx_buf_list.head)
- count = n_hdlc->rx_buf_list.head->count;
- else
- count = 0;
- spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
- PUT_USER (error, count, (int *) arg);
- }
+ /* report count of read data available */
+ /* in next available frame (if any) */
+ spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
+ if (n_hdlc->rx_buf_list.head)
+ count = n_hdlc->rx_buf_list.head->count;
+ else
+ count = 0;
+ spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
+ PUT_USER (error, count, (int *) arg);
break;
-
+
+ case TIOCOUTQ:
+ /* get the pending tx byte count in the driver */
+ count = tty->driver.chars_in_buffer ?
+ tty->driver.chars_in_buffer(tty) : 0;
+ /* add size of next output frame in queue */
+ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
+ if (n_hdlc->tx_buf_list.head)
+ count += n_hdlc->tx_buf_list.head->count;
+ spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
+ PUT_USER (error, count, (int*)arg);
+ break;
+
default:
error = n_tty_ioctl (tty, file, cmd, arg);
break;
/* cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card
*
* by Fred Gleason <fredg@wava.com>
- * Version 0.3.1
+ * Version 0.3.2
*
* (Loosely) based on code for the Aztech radio card by
*
return -EINVAL;
request_region(io,2,"cadet");
- printk(KERN_INFO "ADS Cadet Radio Card at %x\n",io);
+ printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io);
return 0;
}
for(i=0;i<8;i++) {
io=iovals[i];
- if(check_region(io,2)) {
- return -1;
- }
- cadet_setfreq(1410);
- if(cadet_getfreq()==1410) {
- return io;
+ if(check_region(io,2)>=0) {
+ cadet_setfreq(1410);
+ if(cadet_getfreq()==1410) {
+ return io;
+ }
}
}
return -1;
/*
* linux/drivers/char/synclink.c
*
+ * ==FILEDATE 19990610==
+ *
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
*
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
#define BREAKPOINT() asm(" int $3");
#define MAX_ISA_DEVICES 10
-#include <linux/config.h>
+#include <linux/config.h>
#include <linux/module.h>
+#include <linux/version.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
-#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+#if LINUX_VERSION_CODE >= VERSION(2,1,0)
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <asm/serial.h>
} BH_EVENT, *BH_QUEUE; /* Queue of BH actions to be done. */
#define MAX_BH_QUEUE_ENTRIES 200
+#define IO_PIN_SHUTDOWN_LIMIT (MAX_BH_QUEUE_ENTRIES/4)
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+struct _input_signal_events {
+ int ri_up;
+ int ri_down;
+ int dsr_up;
+ int dsr_down;
+ int dcd_up;
+ int dcd_down;
+ int cts_up;
+ int cts_down;
+};
+
/*
* Device instance data structure
*/
int bh_running; /* Protection from multiple */
int isr_overflow;
int bh_requested;
+
+ int dcd_chkcount; /* check counts to prevent */
+ int cts_chkcount; /* too many IRQs if a signal */
+ int dsr_chkcount; /* is floating */
+ int ri_chkcount;
char *buffer_list; /* virtual address of Rx & Tx buffer lists */
unsigned long buffer_list_phys;
char flag_buf[HDLC_MAX_FRAME_SIZE];
char char_buf[HDLC_MAX_FRAME_SIZE];
BOOLEAN drop_rts_on_tx_done;
+
+ BOOLEAN loopmode_insert_requested;
+ BOOLEAN loopmode_send_done_requested;
+
+ struct _input_signal_events input_signal_events;
};
#define MGSL_MAGIC 0x5401
void mgsl_tx_timeout(unsigned long context);
+
+void usc_loopmode_cancel_transmit( struct mgsl_struct * info );
+void usc_loopmode_insert_request( struct mgsl_struct * info );
+int usc_loopmode_active( struct mgsl_struct * info);
+void usc_loopmode_send_done( struct mgsl_struct * info );
+int usc_loopmode_send_active( struct mgsl_struct * info );
+
/*
* Defines a BUS descriptor value for the PCI adapter
* local bus address ranges.
static int mgsl_txenable(struct mgsl_struct * info, int enable);
static int mgsl_txabort(struct mgsl_struct * info);
static int mgsl_rxenable(struct mgsl_struct * info, int enable);
-static int mgsl_wait_event(struct mgsl_struct * info, int mask);
+static int mgsl_wait_event(struct mgsl_struct * info, int * mask);
+static int mgsl_loopmode_send_done( struct mgsl_struct * info );
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
#endif
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "1.00";
+static char *driver_version = "1.7";
static struct tty_driver serial_driver, callout_driver;
static int serial_refcount;
/* As a safety measure, mark the end of the chain with a NULL */
info->free_bh_queue_tail->link = NULL;
+ info->isr_overflow=0;
} /* end of mgsl_format_bh_queue() */
spin_unlock_irqrestore(&info->irq_spinlock,flags);
return 1;
}
+
+ if ( info->isr_overflow ) {
+ if (debug_level >= DEBUG_LEVEL_BH)
+ printk("ISR overflow cleared.\n");
+ info->isr_overflow=0;
+ usc_EnableMasterIrqBit(info);
+ usc_EnableDmaInterrupts(info,DICR_MASTER);
+ }
/* Mark BH routine as complete */
info->bh_running = 0;
}
}
- if ( info->isr_overflow ) {
- printk("ISR overflow detected.\n");
- }
-
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):mgsl_bh_handler(%s) exit\n",
__FILE__,__LINE__,info->device_name);
void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount )
{
struct tty_struct *tty = info->tty;
+ unsigned long flags;
if ( debug_level >= DEBUG_LEVEL_BH )
printk( "%s(%d):mgsl_bh_transmit_data() entry on %s\n",
}
wake_up_interruptible(&tty->write_wait);
}
-
+
+ /* if transmitter idle and loopmode_send_done_requested
+ * then start echoing RxD to TxD
+ */
+ spin_lock_irqsave(&info->irq_spinlock,flags);
+ if ( !info->tx_active && info->loopmode_send_done_requested )
+ usc_loopmode_send_done( info );
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
} /* End Of mgsl_bh_transmit_data() */
/* mgsl_bh_status_handler()
printk( "%s(%d):mgsl_bh_status_handler() entry on %s\n",
__FILE__,__LINE__,info->device_name);
+ if (status & MISCSTATUS_RI_LATCHED) {
+ if (info->ri_chkcount)
+ (info->ri_chkcount)--;
+ }
+ if (status & MISCSTATUS_DSR_LATCHED) {
+ if (info->dsr_chkcount)
+ (info->dsr_chkcount)--;
+ }
+ if (status & MISCSTATUS_DCD_LATCHED) {
+ if (info->dcd_chkcount)
+ (info->dcd_chkcount)--;
+ }
+ if (status & MISCSTATUS_CTS_LATCHED) {
+ if (info->cts_chkcount)
+ (info->cts_chkcount)--;
+ }
+
} /* End Of mgsl_bh_status_handler() */
/* mgsl_isr_receive_status()
printk("%s(%d):mgsl_isr_receive_status status=%04X\n",
__FILE__,__LINE__,status);
- usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
- usc_UnlatchRxstatusBits( info, status );
+ if ( (status & RXSTATUS_ABORT_RECEIVED) &&
+ info->loopmode_insert_requested &&
+ usc_loopmode_active(info) )
+ {
+ ++info->icount.rxabort;
+ info->loopmode_insert_requested = FALSE;
+
+ /* clear CMR:13 to start echoing RxD to TxD */
+ info->cmr_value &= ~BIT13;
+ usc_OutReg(info, CMR, info->cmr_value);
+
+ /* disable received abort irq (no longer required) */
+ usc_OutReg(info, RICR,
+ (usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED));
+ }
if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {
if (status & RXSTATUS_EXITED_HUNT)
usc_RTCmd( info, RTCmd_PurgeRxFifo );
}
+ usc_ClearIrqPendingBits( info, RECEIVE_STATUS );
+ usc_UnlatchRxstatusBits( info, status );
+
} /* end of mgsl_isr_receive_status() */
/* mgsl_isr_transmit_status()
usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );
usc_UnlatchTxstatusBits( info, status );
-
+
if ( status & TXSTATUS_EOF_SENT )
info->icount.txok++;
else if ( status & TXSTATUS_UNDERRUN )
MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {
icount = &info->icount;
/* update input line counters */
- if (status & MISCSTATUS_RI_LATCHED)
+ if (status & MISCSTATUS_RI_LATCHED) {
+ if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_RI);
icount->rng++;
- if (status & MISCSTATUS_DSR_LATCHED)
+ if ( status & MISCSTATUS_RI )
+ info->input_signal_events.ri_up++;
+ else
+ info->input_signal_events.ri_down++;
+ }
+ if (status & MISCSTATUS_DSR_LATCHED) {
+ if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_DSR);
icount->dsr++;
+ if ( status & MISCSTATUS_DSR )
+ info->input_signal_events.dsr_up++;
+ else
+ info->input_signal_events.dsr_down++;
+ }
if (status & MISCSTATUS_DCD_LATCHED) {
+ if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_DCD);
icount->dcd++;
+ if ( status & MISCSTATUS_DCD )
+ info->input_signal_events.dcd_up++;
+ else
+ info->input_signal_events.dcd_down++;
#ifdef CONFIG_HARD_PPS
if ((info->flags & ASYNC_HARDPPS_CD) &&
(status & MISCSTATUS_DCD_LATCHED))
#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
+ {
+ if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)
+ usc_DisablestatusIrqs(info,SICR_CTS);
icount->cts++;
+ if ( status & MISCSTATUS_CTS )
+ info->input_signal_events.cts_up++;
+ else
+ info->input_signal_events.cts_down++;
+ }
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
}
}
+ mgsl_bh_queue_put(info, BH_TYPE_STATUS, status);
+
/* for diagnostics set IRQ flag */
if ( status & MISCSTATUS_TXC_LATCHED ){
usc_OutReg( info, SICR,
/* Post a receive event for BH processing. */
mgsl_bh_queue_put( info, BH_TYPE_RECEIVE_DMA, status );
- if ( status & BIT3 )
+ if ( status & BIT3 ) {
info->rx_overflow = 1;
+ info->icount.buf_overrun++;
+ }
} /* end of mgsl_isr_receive_dma() */
if ( info->isr_overflow ) {
printk(KERN_ERR"%s(%d):%s isr overflow irq=%d\n",
__FILE__,__LINE__,info->device_name, irq);
- /* Interrupt overflow. Reset adapter and exit. */
-// UscReset(info);
-// break;
+ usc_DisableMasterIrqBit(info);
+ usc_DisableDmaInterrupts(info,DICR_MASTER);
+ break;
}
}
usc_set_async_mode(info);
usc_set_serial_signals(info);
+
+ info->dcd_chkcount = 0;
+ info->cts_chkcount = 0;
+ info->ri_chkcount = 0;
+ info->dsr_chkcount = 0;
/* enable modem signal IRQs and read initial signal states */
usc_EnableStatusIrqs(info,SICR_CTS+SICR_DSR+SICR_DCD+SICR_RI);
if ( info->params.mode == MGSL_MODE_HDLC ) {
/* operating in synchronous (frame oriented) mode */
-
+
if (info->tx_active) {
ret = 0; goto cleanup;
}
-
+
+ /* if operating in HDLC LoopMode and the adapter */
+ /* has yet to be inserted into the loop, we can't */
+ /* transmit */
+
+ if ( (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) &&
+ !usc_loopmode_active(info) )
+ {
+ ret = 0;
+ goto cleanup;
+ }
+
if ( info->xmit_cnt ) {
/* Send accumulated from send_char() calls */
/* as frame and wait before accepting more data. */
ret = 0;
-
+
/* copy data from circular xmit_buf to */
/* transmit DMA buffer. */
mgsl_load_tx_dma_buffer(info,
spin_lock_irqsave(&info->irq_spinlock,flags);
if ( enable ) {
- if ( !info->tx_enabled )
+ if ( !info->tx_enabled ) {
+
usc_start_transmitter(info);
+ /*--------------------------------------------------
+ * if HDLC/SDLC Loop mode, attempt to insert the
+ * station in the 'loop' by setting CMR:13. Upon
+ * receipt of the next GoAhead (RxAbort) sequence,
+ * the OnLoop indicator (CCSR:7) should go active
+ * to indicate that we are on the loop
+ *--------------------------------------------------*/
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ usc_loopmode_insert_request( info );
+ }
} else {
if ( info->tx_enabled )
usc_stop_transmitter(info);
spin_lock_irqsave(&info->irq_spinlock,flags);
if ( info->tx_active && info->params.mode == MGSL_MODE_HDLC )
- usc_TCmd(info,TCmd_SendAbort);
+ {
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ usc_loopmode_cancel_transmit( info );
+ else
+ usc_TCmd(info,TCmd_SendAbort);
+ }
spin_unlock_irqrestore(&info->irq_spinlock,flags);
return 0;
/* mgsl_wait_event() wait for specified event to occur
*
* Arguments: info pointer to device instance data
- * mask bitmask of events to wait for
- * Return Value: bit mask of triggering event, otherwise error code
+ * mask pointer to bitmask of events to wait for
+ * Return Value: 0 if successful and bit mask updated with
+ * of events triggerred,
+ * otherwise error code
*/
-static int mgsl_wait_event(struct mgsl_struct * info, int mask)
+static int mgsl_wait_event(struct mgsl_struct * info, int * mask_ptr)
{
unsigned long flags;
int s;
int rc=0;
u16 regval;
struct mgsl_icount cprev, cnow;
+ int events = 0;
+ int mask;
+ struct _input_signal_events signal_events_prev, signal_events_now;
+
+ COPY_FROM_USER(rc,&mask, mask_ptr, sizeof(int));
+ if (rc) {
+ return -EFAULT;
+ }
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_wait_event(%s,%d)\n", __FILE__,__LINE__,
info->device_name, mask);
-
+
spin_lock_irqsave(&info->irq_spinlock,flags);
-
+
+ usc_get_serial_signals(info);
+ s = info->serial_signals;
+
/* note the counters on entry */
cprev = info->icount;
+ signal_events_prev = info->input_signal_events;
if (mask & MgslEvent_ExitHuntMode) {
/* enable exit hunt mode IRQ */
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- while(!rc) {
+ /* Determine if any user requested events for input signals is currently TRUE */
+
+ events |= (mask & ((s & SerialSignal_DSR) ?
+ MgslEvent_DsrActive:MgslEvent_DsrInactive));
+
+ events |= (mask & ((s & SerialSignal_DCD) ?
+ MgslEvent_DcdActive:MgslEvent_DcdInactive));
+
+ events |= (mask & ((s & SerialSignal_CTS) ?
+ MgslEvent_CtsActive:MgslEvent_CtsInactive));
+
+ events |= (mask & ((s & SerialSignal_RI) ?
+ MgslEvent_RiActive:MgslEvent_RiInactive));
+
+
+ while(!events) {
/* sleep until event occurs */
interruptible_sleep_on(&info->event_wait_q);
}
spin_lock_irqsave(&info->irq_spinlock,flags);
+
/* get icount and serial signal states */
cnow = info->icount;
- s = info->serial_signals;
+ signal_events_now = info->input_signal_events;
spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+ if (signal_events_now.dsr_up != signal_events_prev.dsr_up &&
+ mask & MgslEvent_DsrActive )
+ events |= MgslEvent_DsrActive;
- rc = 0;
+ if (signal_events_now.dsr_down != signal_events_prev.dsr_down &&
+ mask & MgslEvent_DsrInactive )
+ events |= MgslEvent_DsrInactive;
+
+ if (signal_events_now.dcd_up != signal_events_prev.dcd_up &&
+ mask & MgslEvent_DcdActive )
+ events |= MgslEvent_DcdActive;
- if (cnow.dsr != cprev.dsr)
- rc |= (mask & ((s & SerialSignal_DSR) ?
- MgslEvent_DsrActive:MgslEvent_DsrInactive));
+ if (signal_events_now.dcd_down != signal_events_prev.dcd_down &&
+ mask & MgslEvent_DcdInactive )
+ events |= MgslEvent_DcdInactive;
+
+ if (signal_events_now.cts_up != signal_events_prev.cts_up &&
+ mask & MgslEvent_CtsActive )
+ events |= MgslEvent_CtsActive;
+
+ if (signal_events_now.cts_down != signal_events_prev.cts_down &&
+ mask & MgslEvent_CtsInactive )
+ events |= MgslEvent_CtsInactive;
+
+ if (signal_events_now.ri_up != signal_events_prev.ri_up &&
+ mask & MgslEvent_RiActive )
+ events |= MgslEvent_RiActive;
+
+ if (signal_events_now.ri_down != signal_events_prev.ri_down &&
+ mask & MgslEvent_RiInactive )
+ events |= MgslEvent_RiInactive;
- if (cnow.dcd != cprev.dcd)
- rc |= (mask & ((s & SerialSignal_DCD) ?
- MgslEvent_DcdActive:MgslEvent_DcdInactive));
-
- if (cnow.cts != cprev.cts)
- rc |= (mask & ((s & SerialSignal_CTS) ?
- MgslEvent_CtsActive:MgslEvent_CtsInactive));
-
- if (cnow.rng != cprev.rng)
- rc |= (mask & ((s & SerialSignal_RI) ?
- MgslEvent_RiActive:MgslEvent_RiInactive));
-
if (cnow.exithunt != cprev.exithunt)
- rc |= (mask & MgslEvent_ExitHuntMode);
-
+ events |= (mask & MgslEvent_ExitHuntMode);
+
if (cnow.rxidle != cprev.rxidle)
- rc |= (mask & MgslEvent_ExitHuntMode);
-
- if (!rc)
- rc = -EIO; /* no change => error */
-
+ events |= (mask & MgslEvent_IdleReceived);
+
cprev = cnow;
+ signal_events_prev = signal_events_now;
}
if (mask & (MgslEvent_ExitHuntMode + MgslEvent_IdleReceived)) {
spin_lock_irqsave(&info->irq_spinlock,flags);
- if (!info->event_wait_q) {
+ if (!waitqueue_active(&info->event_wait_q)) {
/* disable enable exit hunt mode/idle rcvd IRQs */
regval = usc_InReg(info,RICR);
usc_OutReg(info, RICR, regval &
}
spin_unlock_irqrestore(&info->irq_spinlock,flags);
}
-
+
+ if ( rc == 0 )
+ PUT_USER(rc, events, mask_ptr);
+
return rc;
} /* end of mgsl_wait_event() */
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_get_modem_info %s value=%08X\n",
- __FILE__,__LINE__, info->device_name, *value );
+ __FILE__,__LINE__, info->device_name, result );
PUT_USER(err,result,value);
return err;
case MGSL_IOCGSTATS:
return mgsl_get_stats(info,(struct mgsl_icount*)arg);
case MGSL_IOCWAITEVENT:
- return mgsl_wait_event(info,(int)arg);
+ return mgsl_wait_event(info,(int*)arg);
+ case MGSL_IOCLOOPTXDONE:
+ return mgsl_loopmode_send_done(info);
case MGSL_IOCCLRMODCOUNT:
while(MOD_IN_USE)
MOD_DEC_USE_COUNT;
}
spin_unlock_irqrestore(&info->irq_spinlock,flags);
-#if 0 && LINUX_VERSION_CODE >= VERSION(2,1,0)
- ret += sprintf(buf+ret, "irq_spinlock=%08X\n",
- info->irq_spinlock.lock );
-#endif
-
return ret;
} /* end of line_info() */
if ( PCIBIOS_SUCCESSFUL == pcibios_find_device(
MICROGATE_VENDOR_ID, SYNCLINK_DEVICE_ID, i, &bus, &func) ) {
+#if LINUX_VERSION_CODE >= VERSION(2,1,0)
+ struct pci_dev *pdev = pci_find_slot(bus,func);
+ irq_line = pdev->irq;
+#else
+ if (pcibios_read_config_byte(bus,func,
+ PCI_INTERRUPT_LINE,&irq_line) ) {
+ printk( "%s(%d):USC I/O addr not set.\n",
+ __FILE__,__LINE__);
+ continue;
+ }
+#endif
+
if (pcibios_read_config_dword(bus,func,
PCI_BASE_ADDRESS_3,&shared_mem_base) ) {
printk( "%s(%d):Shared mem addr not set.\n",
continue;
}
- if (pcibios_read_config_byte(bus,func,
- PCI_INTERRUPT_LINE,&irq_line) ) {
- printk( "%s(%d):USC I/O addr not set.\n",
- __FILE__,__LINE__);
- continue;
- }
-
info = mgsl_allocate_device();
if ( !info ) {
/* error allocating device instance data */
{
u16 RegValue;
- /* Channel mode Register (CMR)
- *
- * <15..14> 00 Tx Sub modes, Underrun Action
- * <13> 0 1 = Send Preamble before opening flag
- * <12> 0 1 = Consecutive Idles share common 0
- * <11..8> 0110 Transmitter mode = HDLC/SDLC
- * <7..4> 0000 Rx Sub modes, addr/ctrl field handling
- * <3..0> 0110 Receiver mode = HDLC/SDLC
- *
- * 0000 0110 0000 0110 = 0x0606
- */
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ {
+ /*
+ ** Channel Mode Register (CMR)
+ **
+ ** <15..14> 10 Tx Sub Modes, Send Flag on Underrun
+ ** <13> 0 0 = Transmit Disabled (initially)
+ ** <12> 0 1 = Consecutive Idles share common 0
+ ** <11..8> 1110 Transmitter Mode = HDLC/SDLC Loop
+ ** <7..4> 0000 Rx Sub Modes, addr/ctrl field handling
+ ** <3..0> 0110 Receiver Mode = HDLC/SDLC
+ **
+ ** 1000 1110 0000 0110 = 0x8e06
+ */
+ RegValue = 0x8e06;
+
+ /*--------------------------------------------------
+ * ignore user options for UnderRun Actions and
+ * preambles
+ *--------------------------------------------------*/
+ }
+ else
+ {
+ /* Channel mode Register (CMR)
+ *
+ * <15..14> 00 Tx Sub modes, Underrun Action
+ * <13> 0 1 = Send Preamble before opening flag
+ * <12> 0 1 = Consecutive Idles share common 0
+ * <11..8> 0110 Transmitter mode = HDLC/SDLC
+ * <7..4> 0000 Rx Sub modes, addr/ctrl field handling
+ * <3..0> 0110 Receiver mode = HDLC/SDLC
+ *
+ * 0000 0110 0000 0110 = 0x0606
+ */
- RegValue = 0x0606;
+ RegValue = 0x0606;
- if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 )
- RegValue |= BIT14;
- else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
- RegValue |= BIT15;
- else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
- RegValue |= BIT15 + BIT14;
+ if ( info->params.flags & HDLC_FLAG_UNDERRUN_ABORT15 )
+ RegValue |= BIT14;
+ else if ( info->params.flags & HDLC_FLAG_UNDERRUN_FLAG )
+ RegValue |= BIT15;
+ else if ( info->params.flags & HDLC_FLAG_UNDERRUN_CRC )
+ RegValue |= BIT15 + BIT14;
- if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
- RegValue |= BIT13;
+ if ( info->params.preamble != HDLC_PREAMBLE_PATTERN_NONE )
+ RegValue |= BIT13;
+ }
if ( info->params.flags & HDLC_FLAG_SHARE_ZERO )
RegValue |= BIT12;
RegValue |= 0x0003; /* RxCLK from DPLL */
else if ( info->params.flags & HDLC_FLAG_RXC_BRG )
RegValue |= 0x0004; /* RxCLK from BRG0 */
+ else if ( info->params.flags & HDLC_FLAG_RXC_TXCPIN)
+ RegValue |= 0x0006; /* RxCLK from TXC Input */
else
RegValue |= 0x0007; /* RxCLK from Port1 */
RegValue |= 0x0018; /* TxCLK from DPLL */
else if ( info->params.flags & HDLC_FLAG_TXC_BRG )
RegValue |= 0x0020; /* TxCLK from BRG0 */
+ else if ( info->params.flags & HDLC_FLAG_TXC_RXCPIN)
+ RegValue |= 0x0038; /* RxCLK from TXC Input */
else
RegValue |= 0x0030; /* TxCLK from Port0 */
/* of rounding up and then subtracting 1 we just don't subtract */
/* the one in this case. */
- Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed);
- if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2)
- / info->params.clock_speed) )
- Tc--;
+ /*--------------------------------------------------
+ * ejz: for DPLL mode, application should use the
+ * same clock speed as the partner system, even
+ * though clocking is derived from the input RxData.
+ * In case the user uses a 0 for the clock speed,
+ * default to 0xffffffff and don't try to divide by
+ * zero
+ *--------------------------------------------------*/
+ if ( info->params.clock_speed )
+ {
+ Tc = (u16)((XtalSpeed/DpllDivisor)/info->params.clock_speed);
+ if ( !((((XtalSpeed/DpllDivisor) % info->params.clock_speed) * 2)
+ / info->params.clock_speed) )
+ Tc--;
+ }
+ else
+ Tc = -1;
+
/* Write 16-bit Time Constant for BRG1 */
usc_OutReg( info, TC1R, Tc );
if ( debug_level >= DEBUG_LEVEL_DATA )
mgsl_trace_block(info,Buffer,BufferSize,1);
+ if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
+ /* set CMR:13 to start transmit when
+ * next GoAhead (abort) is received
+ */
+ info->cmr_value |= BIT13;
+ }
+
/* Setup the status and RCC (Frame Size) fields of the 1st */
/* buffer entry in the transmit DMA buffer list. */
unsigned int i;
BOOLEAN rc = TRUE;
unsigned long flags;
-
+
spin_lock_irqsave(&info->irq_spinlock,flags);
usc_reset(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
usc_reset(info);
spin_unlock_irqrestore(&info->irq_spinlock,flags);
- if ( !info->irq_occurred )
+ if ( !info->irq_occurred )
return FALSE;
else
return TRUE;
volatile unsigned long EndTime;
unsigned long flags;
MGSL_PARAMS tmp_params;
-
+
/* save current port options */
memcpy(&tmp_params,&info->params,sizeof(MGSL_PARAMS));
/* load default port options */
/**********************************/
/* WAIT FOR TRANSMIT FIFO TO FILL */
/**********************************/
-
+
/* Wait 100ms */
EndTime = jiffies + jiffies_from_ms(100);
if ( rc == TRUE ){
/* CHECK FOR TRANSMIT ERRORS */
- if ( status & (BIT5 + BIT1) )
+ if ( status & (BIT5 + BIT1) )
rc = FALSE;
}
if(info->tx_active && info->params.mode == MGSL_MODE_HDLC) {
info->icount.txtimeout++;
}
-
spin_lock_irqsave(&info->irq_spinlock,flags);
info->tx_active = 0;
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ if ( info->params.flags & HDLC_FLAG_HDLC_LOOPMODE )
+ usc_loopmode_cancel_transmit( info );
+
spin_unlock_irqrestore(&info->irq_spinlock,flags);
mgsl_bh_transmit_data(info,0);
} /* end of mgsl_tx_timeout() */
+/* signal that there are no more frames to send, so that
+ * line is 'released' by echoing RxD to TxD when current
+ * transmission is complete (or immediately if no tx in progress).
+ */
+static int mgsl_loopmode_send_done( struct mgsl_struct * info )
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->irq_spinlock,flags);
+ if (info->params.flags & HDLC_FLAG_HDLC_LOOPMODE) {
+ if (info->tx_active)
+ info->loopmode_send_done_requested = TRUE;
+ else
+ usc_loopmode_send_done(info);
+ }
+ spin_unlock_irqrestore(&info->irq_spinlock,flags);
+
+ return 0;
+}
+
+/* release the line by echoing RxD to TxD
+ * upon completion of a transmit frame
+ */
+void usc_loopmode_send_done( struct mgsl_struct * info )
+{
+ info->loopmode_send_done_requested = FALSE;
+ /* clear CMR:13 to 0 to start echoing RxData to TxData */
+ info->cmr_value &= ~BIT13;
+ usc_OutReg(info, CMR, info->cmr_value);
+}
+
+/* abort a transmit in progress while in HDLC LoopMode
+ */
+void usc_loopmode_cancel_transmit( struct mgsl_struct * info )
+{
+ /* reset tx dma channel and purge TxFifo */
+ usc_RTCmd( info, RTCmd_PurgeTxFifo );
+ usc_DmaCmd( info, DmaCmd_ResetTxChannel );
+ usc_loopmode_send_done( info );
+}
+
+/* for HDLC/SDLC LoopMode, setting CMR:13 after the transmitter is enabled
+ * is an Insert Into Loop action. Upon receipt of a GoAhead sequence (RxAbort)
+ * we must clear CMR:13 to begin repeating TxData to RxData
+ */
+void usc_loopmode_insert_request( struct mgsl_struct * info )
+{
+ info->loopmode_insert_requested = TRUE;
+
+ /* enable RxAbort irq. On next RxAbort, clear CMR:13 to
+ * begin repeating TxData on RxData (complete insertion)
+ */
+ usc_OutReg( info, RICR,
+ (usc_InReg( info, RICR ) | RXSTATUS_ABORT_RECEIVED ) );
+
+ /* set CMR:13 to insert into loop on next GoAhead (RxAbort) */
+ info->cmr_value |= BIT13;
+ usc_OutReg(info, CMR, info->cmr_value);
+}
+
+/* return 1 if station is inserted into the loop, otherwise 0
+ */
+int usc_loopmode_active( struct mgsl_struct * info)
+{
+ return usc_InReg( info, CCSR ) & BIT7 ? 1 : 0 ;
+}
+
+/* return 1 if USC is in loop send mode, otherwise 0
+ */
+int usc_loopmode_send_active( struct mgsl_struct * info )
+{
+ return usc_InReg( info, CCSR ) & BIT6 ? 1 : 0 ;
+}
+
// 16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,0xc2,623},
16*170.00,16*450.00,0x02,0x04,0x01,0x8e,0xc2,623},
{"Temic 4036 FY5 NTSC", TEMIC, NTSC,
- 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+ 16*157.25,16*463.25,0xa0,0x90,0x30,0x8e,0xc2,732},
+ {"Alps HSBH1", TEMIC, NTSC,
+ 16*137.25,16*385.25,0x01,0x02,0x08,0x8e,0xc2,732},
};
/* ---------------------------------------------------------------------- */
#define TUNER_TEMIC_NTSC 6
#define TUNER_TEMIC_PAL_I 7
#define TUNER_TEMIC_4036FY5_NTSC 8
+#define TUNER_ALPS_TSBH1_NTSC 9
#define NOTUNER 0
#define PAL 1
port = dev->port;
if (port->cad == dev) {
- printk(KERN_WARNING "%s: refused to unregister "
- "currently active device %s.\n", port->name, dev->name);
- return;
+ printk(KERN_DEBUG "%s: %s forgot to release port\n",
+ port->name, dev->name);
+ parport_release (dev);
}
spin_lock(&port->pardevice_lock);
outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
}
}
+ vp->stats.tx_bytes+=skb->len;
return 0;
}
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
+ vp->stats.rx_bytes+=skb->len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
+ vp->stats.rx_bytes+=pkt_len;
if (vortex_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
fi
if [ "$CONFIG_MCA" = "y" ]; then
tristate 'NE/2 (ne2000 MCA version) support' CONFIG_NE2_MCA
+ tristate 'SKnet MCA support' CONFIG_SKMC
fi
bool 'EISA, VLB, PCI and on board controllers' CONFIG_NET_EISA
if [ "$CONFIG_NET_EISA" = "y" ]; then
endif
endif
+ifeq ($(CONFIG_SKMC),y)
+L_OBJS += sk_mca.o
+else
+ ifeq ($(CONFIG_SKMC),m)
+ M_OBJS += sk_mca.o
+ endif
+endif
+
ifeq ($(CONFIG_ELMC_II),y)
L_OBJS += 3c527.o
else
extern int wavelan_probe(struct device *);
extern int el16_probe(struct device *);
extern int elmc_probe(struct device *);
+extern int skmca_probe(struct device *);
extern int elplus_probe(struct device *);
extern int ac3200_probe(struct device *);
extern int es_probe(struct device *);
#endif
#ifdef CONFIG_ELMC /* 3c523 */
{elmc_probe, 0},
+#endif
+#ifdef CONFIG_SKMC /* SKnet Microchannel */
+ {skmca_probe, 0},
#endif
{NULL, 0},
};
-/* $Id: cosa.c,v 1.21 1999/02/06 19:49:18 kas Exp $ */
+/* $Id: cosa.c,v 1.24 1999/05/28 17:28:34 kas Exp $ */
/*
* Copyright (C) 1995-1997 Jan "Yenya" Kasprzak <kas@fi.muni.cz>
* The Comtrol Hostess SV11 driver by Alan Cox
* The Sync PPP/Cisco HDLC layer (syncppp.c) ported to Linux by Alan Cox
*/
+/*
+ * 5/25/1999 : Marcelo Tosatti <marcelo@conectiva.com.br>
+ * fixed a deadlock in cosa_sppp_open
+ */
\f
/* ---------- Headers, macros, data structures ---------- */
static void chardev_channel_init(struct channel_data *chan)
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1)
chan->rsem = MUTEX;
chan->wsem = MUTEX;
+#else
+ init_MUTEX(&chan->rsem);
+ init_MUTEX(&chan->wsem);
+#endif
}
static long long cosa_lseek(struct file * file,
debug_status_out(cosa, 0);
#endif
}
+ cosa_putdata8(cosa, 0);
cosa_putdata8(cosa, status);
#ifdef DEBUG_IO
+ debug_data_cmd(cosa, 0);
debug_data_cmd(cosa, status);
#endif
}
printk(KERN_WARNING
"%s: No channel wants data in TX IRQ\n",
cosa->name);
+ put_driver_status_nolock(cosa);
clear_bit(TXBIT, &cosa->rxtx);
spin_unlock_irqrestore(&cosa->lock, flags);
return;
if (tickssofar < 5)
return 1;
if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
+ tx_done(dev) ? "IRQ conflict ?" : "network cable problem");
/* Try to restart the adaptor. */
dev->tbusy=0;
dev->trans_start = jiffies;
dep_tristate 'Winbond W83977AF (IR)' CONFIG_WINBOND_FIR $CONFIG_IRDA
dep_tristate 'Sharp UIRCC' CONFIG_SHARP_FIR $CONFIG_IRDA
dep_tristate 'Toshiba Type-O IR Port' CONFIG_TOSHIBA_FIR $CONFIG_IRDA
+dep_tristate 'SMC IrCC' CONFIG_SMC_IRCC_FIR $CONFIG_IRDA
comment 'Dongle support'
bool 'Serial dongle support' CONFIG_DONGLE
endif
endif
+ifeq ($(CONFIG_IRPORT_SIR),y)
+L_OBJS += irport.o
+else
+ ifeq ($(CONFIG_IRPORT_SIR),m)
+ M_OBJS += irport.o
+ endif
+endif
+
+ifeq ($(CONFIG_IRPORT_SIR),y)
+L_OBJS += irport.o
+else
+ ifeq ($(CONFIG_IRPORT_SIR),m)
+ M_OBJS += irport.o
+ endif
+endif
+
ifeq ($(CONFIG_NSC_FIR),y)
L_OBJS += pc87108.o
else
endif
endif
+ifeq ($(CONFIG_TOSHIBA_FIR),y)
+L_OBJS += toshoboe.o
+else
+ ifeq ($(CONFIG_TOSHIBA_FIR),m)
+ M_OBJS += toshoboe.o
+ endif
+endif
+
+ifeq ($(CONFIG_TOSHIBA_FIR),y)
+L_OBJS += toshoboe.o
+else
+ ifeq ($(CONFIG_TOSHIBA_FIR),m)
+ M_OBJS += toshoboe.o
+ endif
+endif
+
+ifeq ($(CONFIG_SMC_IRCC_FIR),y)
+L_OBJS += irport.o smc-ircc.o
+else
+ ifeq ($(CONFIG_SMC_IRCC_FIR),m)
+ M_OBJS += irport.o smc-ircc.o
+ endif
+endif
+
ifeq ($(CONFIG_ESI_DONGLE),y)
L_OBJS += esi.o
else
endif
endif
+ifeq ($(CONFIG_LITELINK_DONGLE),y)
+L_OBJS += litelink.o
+else
+ ifeq ($(CONFIG_LITELINK_DONGLE),m)
+ M_OBJS += litelink.o
+ endif
+endif
+
+ifeq ($(CONFIG_LITELINK_DONGLE),y)
+L_OBJS += litelink.o
+else
+ ifeq ($(CONFIG_LITELINK_DONGLE),m)
+ M_OBJS += litelink.o
+ endif
+endif
+
include $(TOPDIR)/Rules.make
clean:
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Wed Oct 21 20:02:35 1998
- * Modified at: Mon May 10 15:12:54 1999
+ * Modified at: Sun May 16 14:35:11 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
#include <net/irda/irda_device.h>
#include <net/irda/dongle.h>
-static void actisys_reset(struct irda_device *dev, int unused);
+static void actisys_reset(struct irda_device *dev);
static void actisys_open(struct irda_device *idev, int type);
static void actisys_close(struct irda_device *dev);
static void actisys_change_speed( struct irda_device *dev, int baudrate);
-static void actisys_reset(struct irda_device *dev, int unused);
static void actisys_init_qos(struct irda_device *idev, struct qos_info *qos);
/* These are the baudrates supported */
* 1. Clear DTR for a few ms.
*
*/
-static void actisys_reset(struct irda_device *idev, int unused)
+static void actisys_reset(struct irda_device *idev)
{
ASSERT(idev != NULL, return;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
* Status: Experimental.
* Author: Thomas Davis, <ratbert@radiks.net>
* Created at: Sat Feb 21 18:54:38 1998
- * Modified at: Mon May 10 15:13:12 1999
+ * Modified at: Sun May 16 14:35:21 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: esi.c
*
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
#include <net/irda/irda_device.h>
static void esi_open(struct irda_device *idev, int type);
static void esi_close(struct irda_device *driver);
static void esi_change_speed(struct irda_device *idev, int baud);
-static void esi_reset(struct irda_device *idev, int unused);
+static void esi_reset(struct irda_device *idev);
static void esi_qos_init(struct irda_device *idev, struct qos_info *qos);
static struct dongle dongle = {
irda_device_set_dtr_rts(idev, dtr, rts);
}
-static void esi_reset( struct irda_device *idev, int unused)
+static void esi_reset( struct irda_device *idev)
{
/* Empty */
}
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Feb 6 21:02:33 1999
- * Modified at: Mon May 10 16:01:33 1999
+ * Modified at: Tue Jun 1 08:47:41 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#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 girbil_reset(struct irda_device *dev, int unused);
+static void girbil_reset(struct irda_device *dev);
static void girbil_open(struct irda_device *dev, int type);
static void girbil_close(struct irda_device *dev);
static void girbil_change_speed(struct irda_device *dev, int baud);
* 0. set RTS, and wait at least 5 ms
* 1. clear RTS
*/
-void girbil_reset(struct irda_device *idev, int unused)
+void girbil_reset(struct irda_device *idev)
{
__u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
/* Sleep at least 5 ms */
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(2);
+ schedule_timeout(MSECS_TO_JIFFIES(20));
/* Set DTR and clear RTS to enter command mode */
irda_device_set_dtr_rts(idev, FALSE, TRUE);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(2);
+ schedule_timeout(MSECS_TO_JIFFIES(20));
/* Write control byte */
irda_device_raw_write(idev, &control, 1);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(2);
+ schedule_timeout(MSECS_TO_JIFFIES(20));
/* Go back to normal mode */
irda_device_set_dtr_rts(idev, TRUE, TRUE);
+
+ /* Make sure the IrDA chip also goes to defalt speed */
+ if (idev->change_speed)
+ idev->change_speed(idev, 9600);
}
/*
static void girbil_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 &= 0x03;
}
#ifdef MODULE
/*********************************************************************
- *
+ *
* Filename: irport.c
- * Version: 0.9
- * Description: Serial driver for IrDA.
+ * Version: 1.0
+ * Description: Half duplex serial port SIR driver for IrDA.
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 3 13:49:59 1997
- * Modified at: Sat May 23 23:15:20 1998
+ * Modified at: Tue Jun 1 10:02:42 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: serial.c by Linus Torvalds
*
- * Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
- * All Rights Reserved.
+ * Copyright (c) 1997, 1998, 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.
- *
- * NOTICE:
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
*
* 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
- * code into this file. Instead you should code your FIR driver in a
- * separate file, and then call the functions in this file if
- * necessary. This is becase it is difficult to use the Linux serial
- * driver with a FIR driver becase they must share interrupts etc. Most
- * FIR chipsets can function in advanced SIR mode, and you should
- * probably use that mode instead of the UART compatibility mode (and
- * then just forget about this file)
+ * used for IR-chipsets that has a UART (16550) compatibility mode.
+ * Eventually it will replace irtty, because of irtty has some
+ * problems that is hard to get around when we don't have control
+ * over the serial driver. This driver may also be used by FIR
+ * drivers to handle SIR mode for them.
*
********************************************************************/
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
+#include <linux/skbuff.h>
+#include <linux/serial_reg.h>
#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/serial_reg.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/spinlock.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
static int irport_net_init(struct device *dev);
static int irport_net_open(struct device *dev);
static int irport_net_close(struct device *dev);
-static void irport_wait_until_sent(struct irda_device *idev);
static int irport_is_receiving(struct irda_device *idev);
static void irport_set_dtr_rts(struct irda_device *idev, int dtr, int rts);
static int irport_raw_write(struct irda_device *idev, __u8 *buf, int len);
idev->io.io_ext = IO_EXTENT;
idev->io.fifo_size = 16;
+ idev->netdev.base_addr = iobase;
+ idev->netdev.irq = irq;
+
/* Lock the port that we need */
ret = check_region(idev->io.iobase2, idev->io.io_ext);
if (ret < 0) {
- DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- idev->io.iobase2);
- /* w83977af_cleanup( self->idev); */
+ DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+ idev->io.iobase2);
+ /* irport_cleanup(self->idev); */
return -ENODEV;
}
request_region(idev->io.iobase2, idev->io.io_ext, idev->name);
static int irport_close(struct irda_device *idev)
{
- DEBUG(0, __FUNCTION__ "()\n");
-
ASSERT(idev != NULL, return -1;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
- /* Release the PORT that this driver is using */
+ /* Release the IO-port that this driver is using */
DEBUG(0 , __FUNCTION__ "(), Releasing Region %03x\n",
idev->io.iobase2);
release_region(idev->io.iobase2, idev->io.io_ext);
return 0;
}
-void irport_start(int iobase)
+void irport_start(struct irda_device *idev, int iobase)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&idev->lock, flags);
+
+ irport_stop(idev, iobase);
+
/* Initialize UART */
outb(UART_LCR_WLEN8, iobase+UART_LCR); /* Reset DLAB */
outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase+UART_MCR);
/* Turn on interrups */
- outb((UART_IER_RLSI | UART_IER_RDI), iobase+UART_IER);
+ outb(UART_IER_RLSI | UART_IER_RDI |UART_IER_THRI, iobase+UART_IER);
+ spin_unlock_irqrestore(&idev->lock, flags);
}
-void irport_stop(int iobase)
+void irport_stop(struct irda_device *idev, int iobase)
{
+ unsigned long flags;
+
+ spin_lock_irqsave(&idev->lock, flags);
+
/* Reset UART */
outb(0, iobase+UART_MCR);
/* Turn off interrupts */
outb(0, iobase+UART_IER);
+
+ spin_unlock_irqrestore(&idev->lock, flags);
}
/*
{
DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
-
return 0;
}
/*
* Function irport_change_speed (idev, speed)
*
- * Set speed of port to specified baudrate
+ * Set speed of IrDA port to specified baudrate
*
*/
void irport_change_speed(struct irda_device *idev, int speed)
{
+ unsigned long flags;
int iobase;
int fcr; /* FIFO control reg */
int lcr; /* Line control reg */
int divisor;
- DEBUG( 0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
+ DEBUG(0, __FUNCTION__ "(), Setting speed to: %d\n", speed);
ASSERT(idev != NULL, return;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
/* Update accounting for new speed */
idev->io.baudrate = speed;
+ spin_lock_irqsave(&idev->lock, flags);
+
/* Turn off interrupts */
outb(0, iobase+UART_IER);
divisor = SPEED_MAX/speed;
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+ fcr = UART_FCR_ENABLE_FIFO;
+
+ /*
+ * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
+ * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
+ * about this timeout since it will always be fast enough.
+ */
+ if (idev->io.baudrate < 38400)
+ fcr |= UART_FCR_TRIGGER_1;
+ else
+ fcr |= UART_FCR_TRIGGER_14;
/* IrDA ports use 8N1 */
lcr = UART_LCR_WLEN8;
outb(lcr, iobase+UART_LCR); /* Set 8N1 */
outb(fcr, iobase+UART_FCR); /* Enable FIFO's */
- /* Turn on receive interrups */
- outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER);
+ /* Turn on interrups */
+ outb(UART_IER_RLSI|UART_IER_RDI|UART_IER_THRI, iobase+UART_IER);
+
+ spin_unlock_irqrestore(&self->lock, flags);
}
/*
{
int actual = 0;
int iobase;
+ int fcr;
ASSERT(idev != NULL, return;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+ DEBUG(4, __FUNCTION__ "()\n");
+
/* Finished with frame? */
if (idev->tx_buff.len > 0) {
/* Write data left in transmit buffer */
/* Schedule network layer, so we can get some more frames */
mark_bh(NET_BH);
- outb(UART_FCR_ENABLE_FIFO |
- UART_FCR_TRIGGER_14 |
- UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR;
+
+ if (idev->io.baudrate < 38400)
+ fcr |= UART_FCR_TRIGGER_1;
+ else
+ fcr |= UART_FCR_TRIGGER_14;
+
+ /*
+ * Reset Rx FIFO to make sure that all reflected transmit data
+ * will be discarded
+ */
+ outb(fcr, iobase+UART_FCR);
/* Turn on receive interrupts */
outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER);
/*
* Function irport_write (driver)
*
- *
+ * Fill Tx FIFO with transmit data
*
*/
static int irport_write(int iobase, int fifo_size, __u8 *buf, int len)
/* Tx FIFO should be empty! */
if (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
- DEBUG( 0, __FUNCTION__ "(), failed, fifo not empty!\n");
+ DEBUG(0, __FUNCTION__ "(), failed, fifo not empty!\n");
return -1;
}
/* Fill FIFO with current frame */
- while (( fifo_size-- > 0) && (actual < len)) {
+ while ((fifo_size-- > 0) && (actual < len)) {
/* Transmit next byte */
- outb( buf[actual], iobase+UART_TX);
+ outb(buf[actual], iobase+UART_TX);
actual++;
}
- DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n",
- fifo_size, actual, len);
-
return actual;
}
int irport_hard_xmit(struct sk_buff *skb, struct device *dev)
{
struct irda_device *idev;
+ unsigned long flags;
int actual = 0;
int iobase;
- DEBUG(5, __FUNCTION__ "(), dev=%p\n", dev);
-
ASSERT(dev != NULL, return 0;);
idev = (struct irda_device *) dev->priv;
iobase = idev->io.iobase2;
/* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE)
- return -EBUSY;
+ if (irda_lock((void *) &dev->tbusy) == FALSE) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return -EBUSY;
+
+ WARNING("%s: transmit timed out\n", dev->name);
+ irport_start(idev, iobase);
+ irport_change_speed(idev, idev->io.baudrate);
+
+ dev->trans_start = jiffies;
+ }
+
+ spin_lock_irqsave(&idev->lock, flags);
/* Init tx buffer */
idev->tx_buff.data = idev->tx_buff.head;
/* Turn on transmit finished interrupt. Will fire immediately! */
outb(UART_IER_THRI, iobase+UART_IER);
+ spin_unlock_irqrestore(&idev->lock, flags);
+
dev_kfree_skb(skb);
return 0;
int iobase;
int boguscount = 0;
- if (!idev)
- return;
-
- DEBUG(4, __FUNCTION__ "()\n");
+ ASSERT(idev != NULL, return;);
iobase = idev->io.iobase2;
int boguscount = 0;
if (!idev) {
- printk(KERN_WARNING __FUNCTION__
- "() irq %d for unknown device.\n", irq);
+ WARNING(__FUNCTION__ "() irq %d for unknown device.\n", irq);
return;
}
+ spin_lock(&idev->lock);
+
idev->netdev.interrupt = 1;
iobase = idev->io.iobase2;
- iir = inb(iobase + UART_IIR) & UART_IIR_ID;
+ iir = inb(iobase+UART_IIR) & UART_IIR_ID;
while (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);
- } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
- /* Receive interrupt */
- irport_receive(idev);
- }
+ DEBUG(4, __FUNCTION__ "(), iir=%02x, lsr=%02x, iobase=%#x\n",
+ iir, lsr, iobase);
+
+ switch (iir) {
+ case UART_IIR_RLSI:
+ DEBUG(0, __FUNCTION__ "(), RLSI\n");
+ break;
+ case UART_IIR_RDI:
+ if (lsr & UART_LSR_DR)
+ /* Receive interrupt */
+ irport_receive(idev);
+ break;
+ case UART_IIR_THRI:
+ if (lsr & UART_LSR_THRE)
+ /* Transmitter ready for data */
+ irport_write_wakeup(idev);
+ break;
+ default:
+ DEBUG(0, __FUNCTION__ "(), unhandled IIR=%#x\n", iir);
+ break;
+ }
/* Make sure we don't stay here to long */
if (boguscount++ > 32)
iir = inb(iobase + UART_IIR) & UART_IIR_ID;
}
idev->netdev.interrupt = 0;
+
+ spin_unlock(&idev->lock);
}
static int irport_net_init(struct device *dev)
iobase = idev->io.iobase2;
if (request_irq(idev->io.irq2, irport_interrupt, 0, idev->name,
- (void *) idev)) {
+ (void *) idev))
return -EAGAIN;
- }
+
+ irport_start(idev, iobase);
+
+ MOD_INC_USE_COUNT;
/* Ready to play! */
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
- MOD_INC_USE_COUNT;
-
- irport_start(iobase);
+ /* Change speed to make sure dongles follow us again */
+ if (idev->change_speed)
+ idev->change_speed(idev, 9600);
return 0;
}
iobase = idev->io.iobase2;
- irport_stop(iobase);
-
/* Stop device */
dev->tbusy = 1;
dev->start = 0;
+ irport_stop(idev, iobase);
+
free_irq(idev->io.irq2, idev);
MOD_DEC_USE_COUNT;
return 0;
}
-static void irport_wait_until_sent(struct irda_device *idev)
+/*
+ * Function irport_wait_until_sent (idev)
+ *
+ * Delay exectution until finished transmitting
+ *
+ */
+void irport_wait_until_sent(struct irda_device *idev)
{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(60*HZ/1000);
+ int iobase;
+
+ iobase = idev->io.iobase2;
+
+ /* Wait until Tx FIFO is empty */
+ while (!(inb(iobase+UART_LSR) & UART_LSR_THRE)) {
+ DEBUG(2, __FUNCTION__ "(), waiting!\n");
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(MSECS_TO_JIFFIES(60));
+ }
}
+/*
+ * Function irport_is_receiving (idev)
+ *
+ * Returns true is we are currently receiving data
+ *
+ */
static int irport_is_receiving(struct irda_device *idev)
{
return (idev->rx_buff.state != OUTSIDE_FRAME);
MODULE_PARM(io, "1-4i");
MODULE_PARM(irq, "1-4i");
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Half duplex serial driver for IrDA SIR mode");
+
/*
* Function cleanup_module (void)
*
* Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Fri May 7 12:50:33 1999
- * Modified at: Mon May 10 15:12:18 1999
+ * Modified at: Wed May 19 07:25:15 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/uaccess.h>
#include <net/irda/irda.h>
#include <net/irda/irmod.h>
#include <net/irda/irda_device.h>
#include <net/irda/dongle.h>
-static void litelink_reset(struct irda_device *dev, int unused);
+#define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000 /* 1 ms */
+
static void litelink_open(struct irda_device *idev, int type);
static void litelink_close(struct irda_device *dev);
-static void litelink_change_speed( struct irda_device *dev, int baudrate);
-static void litelink_reset(struct irda_device *dev, int unused);
+static void litelink_change_speed(struct irda_device *dev, int baudrate);
+static void litelink_reset(struct irda_device *dev);
static void litelink_init_qos(struct irda_device *idev, struct qos_info *qos);
/* These are the baudrates supported */
irda_device_set_dtr_rts(idev, TRUE, FALSE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
/* Go back to normal mode */
irda_device_set_dtr_rts(idev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
/* Cycle through avaiable baudrates until we reach the correct one */
for (i=0; i<5 && baud_rates[i] != baudrate; i++) {
irda_device_set_dtr_rts(idev, FALSE, TRUE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
/* Set DTR, Set RTS */
irda_device_set_dtr_rts(idev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
}
}
* called with a process context!
*
*/
-static void litelink_reset(struct irda_device *idev, int unused)
+static void litelink_reset(struct irda_device *idev)
{
- struct irtty_cb *self;
- struct tty_struct *tty;
-
ASSERT(idev != NULL, return;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
irda_device_set_dtr_rts(idev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
/* Clear RTS to reset dongle */
irda_device_set_dtr_rts(idev, TRUE, FALSE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
/* Go back to normal mode */
irda_device_set_dtr_rts(idev, TRUE, TRUE);
/* Sleep a minimum of 15 us */
- udelay(15);
+ udelay(MIN_DELAY);
/* This dongles speed defaults to 115200 bps */
idev->qos.baud_rate.value = 115200;
* Initialize QoS capabilities
*
*/
-static void litelink_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void litelink_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 &= 0x40; /* Needs 0.01 ms */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Nov 7 21:43:15 1998
- * Modified at: Sun May 9 12:57:46 1999
+ * Modified at: Mon May 24 15:19:21 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
#define CHIP_IO_EXTENT 8
static unsigned int io[] = { 0x2f8, ~0, ~0, ~0 };
-static unsigned int io2[] = { 0x150, 0, 0, 0};
+static unsigned int io2[] = { 0x150, 0, 0, 0 };
static unsigned int irq[] = { 3, 0, 0, 0 };
static unsigned int dma[] = { 0, 0, 0, 0 };
};
/* Some prototypes */
-static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr,
- unsigned int irq, unsigned int dma);
+static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr,
+ unsigned int irq, unsigned int dma);
#ifdef MODULE
-static int pc87108_close( struct irda_device *idev);
+static int pc87108_close(struct irda_device *idev);
#endif /* MODULE */
-static int pc87108_probe( int iobase, int board_addr, int irq, int dma);
-static void pc87108_pio_receive( struct irda_device *idev);
-static int pc87108_dma_receive( struct irda_device *idev);
+static int pc87108_probe(int iobase, int board_addr, int irq, int dma);
+static void pc87108_pio_receive(struct irda_device *idev);
+static int pc87108_dma_receive(struct irda_device *idev);
static int pc87108_dma_receive_complete(struct irda_device *idev, int iobase);
-static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev);
-static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size);
-static void pc87108_dma_write( struct irda_device *idev, int iobase);
-static void pc87108_change_speed( struct irda_device *idev, int baud);
+static int pc87108_hard_xmit(struct sk_buff *skb, struct device *dev);
+static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size);
+static void pc87108_dma_write(struct irda_device *idev, int iobase);
+static void pc87108_change_speed(struct irda_device *idev, int baud);
static void pc87108_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void pc87108_wait_until_sent( struct irda_device *idev);
-static int pc87108_is_receiving( struct irda_device *idev);
-static int pc87108_read_dongle_id ( int iobase);
-static void pc87108_init_dongle_interface ( int iobase, int dongle_id);
+static void pc87108_wait_until_sent(struct irda_device *idev);
+static int pc87108_is_receiving(struct irda_device *idev);
+static int pc87108_read_dongle_id (int iobase);
+static void pc87108_init_dongle_interface (int iobase, int dongle_id);
-static int pc87108_net_init( struct device *dev);
-static int pc87108_net_open( struct device *dev);
-static int pc87108_net_close( struct device *dev);
+static int pc87108_net_init(struct device *dev);
+static int pc87108_net_open(struct device *dev);
+static int pc87108_net_close(struct device *dev);
/*
* Function pc87108_init ()
{
int i;
- for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+ for (i=0; (io[i] < 2000) && (i < 4); i++) {
int ioaddr = io[i];
if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
continue;
- if (pc87108_open( i, io[i], io2[i], irq[i], dma[i]) == 0)
+ if (pc87108_open(i, io[i], io2[i], irq[i], dma[i]) == 0)
return 0;
}
return -ENODEV;
* Open driver instance
*
*/
-static int pc87108_open( int i, unsigned int iobase, unsigned int board_addr,
- unsigned int irq, unsigned int dma)
+static int pc87108_open(int i, unsigned int iobase, unsigned int board_addr,
+ unsigned int irq, unsigned int dma)
{
struct pc87108 *self;
struct irda_device *idev;
int ret;
int dongle_id;
- DEBUG( 0, __FUNCTION__ "()\n");
+ DEBUG(0, __FUNCTION__ "()\n");
- if (( dongle_id = pc87108_probe( iobase, board_addr, irq, dma)) == -1)
+ if ((dongle_id = pc87108_probe(iobase, board_addr, irq, dma)) == -1)
return -1;
/*
* Allocate new instance of the driver
*/
- self = kmalloc( sizeof(struct pc87108), GFP_KERNEL);
- if ( self == NULL) {
- printk( KERN_ERR "IrDA: Can't allocate memory for "
- "IrDA control block!\n");
+ self = kmalloc(sizeof(struct pc87108), 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 pc87108));
+ memset(self, 0, sizeof(struct pc87108));
/* Need to store self somewhere */
dev_self[i] = self;
idev->io.fifo_size = 32;
/* Lock the port that we need */
- ret = check_region( idev->io.iobase, idev->io.io_ext);
- if ( ret < 0) {
- DEBUG( 0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
- idev->io.iobase);
+ ret = check_region(idev->io.iobase, idev->io.io_ext);
+ if (ret < 0) {
+ DEBUG(0, __FUNCTION__ "(), can't get iobase of 0x%03x\n",
+ idev->io.iobase);
/* pc87108_cleanup( self->idev); */
return -ENODEV;
}
- request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+ request_region(idev->io.iobase, idev->io.io_ext, idev->name);
/* Initialize QoS for this device */
- irda_init_max_qos_capabilies( &idev->qos);
+ irda_init_max_qos_capabilies(&idev->qos);
/* 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);
idev->qos.min_turn_time.bits = qos_mtt_bits;
- irda_qos_bits_to_value( &idev->qos);
+ irda_qos_bits_to_value(&idev->qos);
idev->flags = IFF_FIR|IFF_MIR|IFF_SIR|IFF_DMA|IFF_PIO|IFF_DONGLE;
idev->netdev.stop = pc87108_net_close;
idev->io.dongle_id = dongle_id;
- pc87108_init_dongle_interface( iobase, dongle_id);
+ pc87108_init_dongle_interface(iobase, dongle_id);
/* Open the IrDA device */
- irda_device_open( idev, driver_name, self);
+ irda_device_open(idev, driver_name, self);
return 0;
}
DEBUG( 4, __FUNCTION__ "()\n");
- ASSERT( idev != NULL, return -1;);
- ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+ ASSERT(idev != NULL, return -1;);
+ ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return -1;);
iobase = idev->io.iobase;
self = (struct pc87108 *) idev->priv;
/* Release the PORT that this driver is using */
- DEBUG( 4, __FUNCTION__ "(), Releasing Region %03x\n",
- idev->io.iobase);
+ DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
release_region(idev->io.iobase, idev->io.io_ext);
irda_device_close(idev);
* Returns non-negative on success.
*
*/
-static int pc87108_probe( int iobase, int board_addr, int irq, int dma)
+static int pc87108_probe(int iobase, int board_addr, int irq, int dma)
{
int version;
__u8 temp=0;
int dongle_id;
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
/* Base Address and Interrupt Control Register BAIC */
outb(0, board_addr);
- switch ( iobase) {
- case 0x3E8: outb( 0x14, board_addr+1); break;
- case 0x2E8: outb( 0x15, board_addr+1); break;
- case 0x3F8: outb( 0x16, board_addr+1); break;
- case 0x2F8: outb( 0x17, board_addr+1); break;
- default: DEBUG(0, __FUNCTION__ "(), invalid base_address");
+ switch (iobase) {
+ case 0x3E8: outb(0x14, board_addr+1); break;
+ case 0x2E8: outb(0x15, board_addr+1); break;
+ case 0x3F8: outb(0x16, board_addr+1); break;
+ case 0x2F8: outb(0x17, board_addr+1); break;
+ default: ERROR(__FUNCTION__ "(), invalid base_address");
}
/* Control Signal Routing Register CSRT */
case 9: temp = 0x05; break;
case 11: temp = 0x06; break;
case 15: temp = 0x07; break;
- default: DEBUG( 0, __FUNCTION__ "(), invalid irq");
+ default: ERROR(__FUNCTION__ "(), invalid irq");
}
- outb( 1, board_addr);
-
+ outb(1, board_addr);
+
switch (dma) {
- case 0: outb( 0x08+temp, board_addr+1); break;
- case 1: outb( 0x10+temp, board_addr+1); break;
- case 3: outb( 0x18+temp, board_addr+1); break;
+ case 0: outb(0x08+temp, board_addr+1); break;
+ case 1: outb(0x10+temp, board_addr+1); break;
+ case 3: outb(0x18+temp, board_addr+1); break;
default: DEBUG( 0, __FUNCTION__ "(), invalid dma");
}
/* Mode Control Register MCTL */
- outb( 2, board_addr);
- outb( 0x03, board_addr+1);
+ outb(2, board_addr);
+ outb(0x03, board_addr+1);
/* read the Module ID */
- switch_bank( iobase, BANK3);
- version = inb( iobase+MID);
+ switch_bank(iobase, BANK3);
+ version = inb(iobase+MID);
/* should be 0x2? */
- if (0x20 != (version & 0xf0))
- {
- DEBUG( 0, __FUNCTION__ "(), Wrong chip version");
+ if (0x20 != (version & 0xf0)) {
+ ERROR(__FUNCTION__ "(), Wrong chip version %02x\n", version);
return -1;
}
/* Switch to advanced mode */
switch_bank( iobase, BANK2);
- outb( ECR1_EXT_SL, iobase+ECR1);
- switch_bank( iobase, BANK0);
+ outb(ECR1_EXT_SL, iobase+ECR1);
+ switch_bank(iobase, BANK0);
- dongle_id = pc87108_read_dongle_id( iobase);
- DEBUG( 0, __FUNCTION__ "(), Found dongle: %s\n",
- dongle_types[ dongle_id]);
+ dongle_id = pc87108_read_dongle_id(iobase);
+ DEBUG(0, __FUNCTION__ "(), Found dongle: %s\n",
+ dongle_types[ dongle_id]);
/* Set FIFO threshold to TX17, RX16, reset and enable FIFO's */
- switch_bank( iobase, BANK0);
- outb( FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
+ switch_bank(iobase, BANK0);
+ outb(FCR_RXTH|FCR_TXTH|FCR_TXSR|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
/* Set FIFO size to 32 */
- switch_bank( iobase, BANK2);
- outb( EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
+ switch_bank(iobase, BANK2);
+ outb(EXCR2_RFSIZ|EXCR2_TFSIZ, iobase+EXCR2);
/* IRCR2: FEND_MD is set */
- switch_bank( iobase, BANK5);
- outb( 0x2a, iobase+4);
+ switch_bank(iobase, BANK5);
+ outb(0x2a, iobase+4);
/* Make sure that some defaults are OK */
- switch_bank( iobase, BANK6);
- outb( 0x20, iobase+0); /* Set 32 bits FIR CRC */
- outb( 0x0a, iobase+1); /* Set MIR pulse width */
- outb( 0x0d, iobase+2); /* Set SIR pulse width */
- outb( 0x2a, iobase+4); /* Set beginning frag, and preamble length */
+ switch_bank(iobase, BANK6);
+ outb(0x20, iobase+0); /* Set 32 bits FIR CRC */
+ outb(0x0a, iobase+1); /* Set MIR pulse width */
+ outb(0x0d, iobase+2); /* Set SIR pulse width */
+ outb(0x2a, iobase+4); /* Set beginning frag, and preamble length */
/* Receiver frame length */
- switch_bank( iobase, BANK4);
- outb( 2048 & 0xff, iobase+6);
- outb(( 2048 >> 8) & 0x1f, iobase+7);
+ switch_bank(iobase, BANK4);
+ outb(2048 & 0xff, iobase+6);
+ outb((2048 >> 8) & 0x1f, iobase+7);
/* Transmitter frame length */
- outb( 2048 & 0xff, iobase+4);
- outb(( 2048 >> 8) & 0x1f, iobase+5);
+ outb(2048 & 0xff, iobase+4);
+ outb((2048 >> 8) & 0x1f, iobase+5);
- DEBUG( 0, "PC87108 driver loaded. Version: 0x%02x\n", version);
+ DEBUG(0, "PC87108 driver loaded. Version: 0x%02x\n", version);
/* Enable receive interrupts */
- switch_bank( iobase, BANK0);
- outb( IER_RXHDL_IE, iobase+IER);
+ switch_bank(iobase, BANK0);
+ outb(IER_RXHDL_IE, iobase+IER);
return dongle_id;
}
bank = inb( iobase+BSR);
/* Select Bank 7 */
- switch_bank( iobase, BANK7);
+ switch_bank(iobase, BANK7);
/* IRCFG4: IRSL0_DS and IRSL21_DS are cleared */
- outb( 0x00, iobase+7);
+ outb(0x00, iobase+7);
/* ID0, 1, and 2 are pulled up/down very slowly */
udelay(50);
dongle_id = inb( iobase+4) & 0x0f;
#ifdef BROKEN_DONGLE_ID
- if ( dongle_id == 0x0a)
+ if (dongle_id == 0x0a)
dongle_id = 0x09;
#endif
-
+
/* Go back to bank 0 before returning */
- switch_bank( iobase, BANK0);
+ switch_bank(iobase, BANK0);
- DEBUG( 0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
+ DEBUG(0, __FUNCTION__ "(), Dongle = %#x\n", dongle_id);
- outb( bank, iobase+BSR);
+ outb(bank, iobase+BSR);
return dongle_id;
}
* power-on/reset. It also needs to be used whenever you suspect that
* the dongle is changed.
*/
-static void pc87108_init_dongle_interface ( int iobase, int dongle_id)
+static void pc87108_init_dongle_interface (int iobase, int dongle_id)
{
int bank;
iobase+ECR1);
/* Enable DMA */
- switch_bank( iobase, BANK0);
- outb( inb( iobase+MCR)|MCR_DMA_EN, iobase+MCR);
+ switch_bank(iobase, BANK0);
+ outb(inb(iobase+MCR)|MCR_DMA_EN, iobase+MCR);
/* Restore bank register */
- outb( bsr, iobase+BSR);
+ outb(bsr, iobase+BSR);
}
/*
* got transfered
*
*/
-static int pc87108_pio_write( int iobase, __u8 *buf, int len, int fifo_size)
+static int pc87108_pio_write(int iobase, __u8 *buf, int len, int fifo_size)
{
int actual = 0;
__u8 bank;
}
/* Fill FIFO with current frame */
- while (( fifo_size-- > 0) && (actual < len)) {
+ while ((fifo_size-- > 0) && (actual < len)) {
/* Transmit next byte */
- outb( buf[actual++], iobase+TXD);
+ outb(buf[actual++], iobase+TXD);
}
- DEBUG( 4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n",
- fifo_size, actual, len);
+ DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n",
+ fifo_size, actual, len);
/* Restore bank */
- outb( bank, iobase+BSR);
+ outb(bank, iobase+BSR);
return actual;
}
MODULE_DESCRIPTION("NSC PC87108 IrDA Device Driver");
MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM(io, "1-4i");
+MODULE_PARM(io2, "1-4i");
+MODULE_PARM(irq, "1-4i");
/*
* Function init_module (void)
--- /dev/null
+/*********************************************************************
+ *
+ * Filename: smc-ircc.c
+ * Version: 0.1
+ * Description: Driver for the SMC Infrared Communications Controller (SMC)
+ * Status: Experimental.
+ * Author: Thomas Davis (tadavis@jps.net)
+ * Created at:
+ * Modified at: Wed May 19 15:30:08 1999
+ * Modified by: Dag Brattli <dagb@cs.uit.no>
+ *
+ * Copyright (c) 1998-1999 Thomas Davis, 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.
+ *
+ * I, Thomas Davis, admit no liability nor provide warranty for any
+ * of this software. This material is provided "AS-IS" and at no charge.
+ *
+ * Applicable Models : Fujitsu Lifebook 635t
+ * Sony PCG-505TX (gets DMA wrong.)
+ *
+ ********************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/malloc.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/byteorder.h>
+
+#include <net/irda/wrapper.h>
+#include <net/irda/irda.h>
+#include <net/irda/irmod.h>
+#include <net/irda/irlap_frame.h>
+#include <net/irda/irda_device.h>
+
+#include <net/irda/smc-ircc.h>
+#include <net/irda/irport.h>
+
+static char *driver_name = "smc-ircc";
+
+#define CHIP_IO_EXTENT 8
+
+static unsigned int io[] = { 0x2e8, 0x140, ~0, ~0 };
+static unsigned int io2[] = { 0x2f8, 0x3e8, 0, 0};
+
+static struct ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL};
+
+/* Some prototypes */
+static int ircc_open( int i, unsigned int iobase, unsigned int board_addr);
+static int ircc_close( struct irda_device *idev);
+static int ircc_probe( int iobase, int board_addr);
+static int ircc_dma_receive( struct irda_device *idev);
+static int ircc_dma_receive_complete(struct irda_device *idev, int iobase);
+static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev);
+static void ircc_dma_write( struct irda_device *idev, int iobase);
+static void ircc_change_speed( struct irda_device *idev, int baud);
+static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void ircc_wait_until_sent( struct irda_device *idev);
+static int ircc_is_receiving( struct irda_device *idev);
+
+static int ircc_net_init( struct device *dev);
+static int ircc_net_open( struct device *dev);
+static int ircc_net_close( struct device *dev);
+
+static int ircc_debug=3;
+static int ircc_irq=255;
+static int ircc_dma=255;
+
+static inline void register_bank(int port, int bank)
+{
+ outb(((inb(port+UART_MASTER) & 0xF0) | (bank & 0x07)),
+ port+UART_MASTER);
+}
+
+static inline unsigned int serial_in(int port, int offset)
+{
+ return inb(port+offset);
+}
+
+static inline void serial_out(int port, int offset, int value)
+{
+ outb(value, port+offset);
+}
+
+/*
+ * Function ircc_init ()
+ *
+ * Initialize chip. Just try to find out how many chips we are dealing with
+ * and where they are
+ */
+__initfunc(int ircc_init(void))
+{
+ int i;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+ for ( i=0; (io[i] < 2000) && (i < 4); i++) {
+ int ioaddr = io[i];
+ if (check_region(ioaddr, CHIP_IO_EXTENT))
+ continue;
+ if (ircc_open( i, io[i], io2[i]) == 0)
+ return 0;
+ }
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+ return -ENODEV;
+}
+
+/*
+ * Function ircc_cleanup ()
+ *
+ * Close all configured chips
+ *
+ */
+#ifdef MODULE
+static void ircc_cleanup(void)
+{
+ int i;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ for ( i=0; i < 4; i++) {
+ if ( dev_self[i])
+ ircc_close( &(dev_self[i]->idev));
+ }
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+#endif /* MODULE */
+
+/*
+ * Function ircc_open (iobase, irq)
+ *
+ * Open driver instance
+ *
+ */
+static int ircc_open( int i, unsigned int iobase, unsigned int iobase2)
+{
+ struct ircc_cb *self;
+ struct irda_device *idev;
+ int ret;
+ int config;
+
+ DEBUG( ircc_debug, __FUNCTION__ " -->\n");
+
+ if ((config = ircc_probe( iobase, iobase2)) == -1) {
+ DEBUG(ircc_debug,
+ __FUNCTION__ ": addr 0x%04x - no device found!\n", iobase);
+ return -1;
+ }
+
+ /*
+ * Allocate new instance of the driver
+ */
+ self = kmalloc( sizeof(struct ircc_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 ircc_cb));
+
+ /* Need to store self somewhere */
+ dev_self[i] = self;
+
+ idev = &self->idev;
+
+ /* Initialize IO */
+ idev->io.iobase = iobase;
+ idev->io.iobase2 = iobase2; /* Used by irport */
+ idev->io.irq = config >> 4 & 0x0f;
+ if (ircc_irq < 255) {
+ printk(KERN_INFO "smc: Overriding IRQ - chip says %d, using %d\n",
+ idev->io.irq, ircc_irq);
+ idev->io.irq = ircc_irq;
+ }
+ idev->io.io_ext = CHIP_IO_EXTENT;
+ idev->io.io_ext2 = 8; /* Used by irport */
+ idev->io.dma = config & 0x0f;
+ if (ircc_dma < 255) {
+ printk(KERN_INFO "smc: Overriding DMA - chip says %d, using %d\n",
+ idev->io.dma, ircc_dma);
+ idev->io.dma = ircc_dma;
+ }
+ idev->io.fifo_size = 16;
+
+ /* Lock the port that we need */
+ ret = check_region( idev->io.iobase, idev->io.io_ext);
+ if ( ret < 0) {
+ DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
+ idev->io.iobase);
+ /* ircc_cleanup( self->idev); */
+ return -ENODEV;
+ }
+ ret = check_region( idev->io.iobase2, idev->io.io_ext2);
+ if ( ret < 0) {
+ DEBUG( 0, __FUNCTION__ ": can't get iobase of 0x%03x\n",
+ idev->io.iobase2);
+ /* ircc_cleanup( self->idev); */
+ return -ENODEV;
+ }
+ request_region( idev->io.iobase, idev->io.io_ext, idev->name);
+ request_region( idev->io.iobase2, idev->io.io_ext2, idev->name);
+
+ /* Initialize QoS for this device */
+ irda_init_max_qos_capabilies( &idev->qos);
+
+#if 1
+ /* 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);
+#else
+ /* The only value we must override it the baudrate */
+ idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+ IR_115200;
+#endif
+
+ idev->qos.min_turn_time.bits = 0x07;
+ irda_qos_bits_to_value( &idev->qos);
+
+ idev->flags = IFF_FIR|IFF_SIR|IFF_DMA|IFF_PIO;
+
+ /* Specify which buffer allocation policy we need */
+ idev->rx_buff.flags = GFP_KERNEL | GFP_DMA;
+ idev->tx_buff.flags = GFP_KERNEL | GFP_DMA;
+
+ /* Max DMA buffer size needed = (data_size + 6) * (window_size) + 6; */
+ idev->rx_buff.truesize = 4000;
+ idev->tx_buff.truesize = 4000;
+
+ /* Initialize callbacks */
+ idev->change_speed = ircc_change_speed;
+ idev->wait_until_sent = ircc_wait_until_sent;
+ idev->is_receiving = ircc_is_receiving;
+
+ /* Override the network functions we need to use */
+ idev->netdev.init = ircc_net_init;
+ idev->netdev.hard_start_xmit = ircc_hard_xmit;
+ idev->netdev.open = ircc_net_open;
+ idev->netdev.stop = ircc_net_close;
+
+ irport_start(idev, iobase2);
+
+ /* Open the IrDA device */
+ irda_device_open( idev, driver_name, self);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+/*
+ * Function ircc_close (idev)
+ *
+ * Close driver instance
+ *
+ */
+static int ircc_close( struct irda_device *idev)
+{
+ int iobase;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ ASSERT( idev != NULL, return -1;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+ iobase = idev->io.iobase;
+
+ irport_stop(idev, idev->io.iobase2);
+
+ register_bank(iobase, 0);
+ serial_out(iobase, UART_IER, 0);
+ serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+
+ register_bank(iobase, 1);
+
+ serial_out(iobase, UART_SCE_CFGA,
+ UART_CFGA_IRDA_SIR_A | UART_CFGA_TX_POLARITY);
+ serial_out(iobase, UART_SCE_CFGB, UART_CFGB_IR);
+
+ /* Release the PORT that this driver is using */
+ DEBUG( ircc_debug,
+ __FUNCTION__ ": releasing 0x%03x\n", idev->io.iobase);
+
+ release_region( idev->io.iobase, idev->io.io_ext);
+
+ if ( idev->io.iobase2) {
+ DEBUG( ircc_debug, __FUNCTION__ ": releasing 0x%03x\n",
+ idev->io.iobase2);
+ release_region( idev->io.iobase2, idev->io.io_ext2);
+ }
+
+ irda_device_close( idev);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+/*
+ * Function ircc_probe (iobase, board_addr, irq, dma)
+ *
+ * Returns non-negative on success.
+ *
+ */
+static int ircc_probe( int iobase, int iobase2)
+{
+ int version = 1;
+ int low, high, chip, config, dma, irq;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ register_bank(iobase, 3);
+ high = serial_in(iobase, UART_ID_HIGH);
+ low = serial_in(iobase, UART_ID_LOW);
+ chip = serial_in(iobase, UART_CHIP_ID);
+ version = serial_in(iobase, UART_VERSION);
+ config = serial_in(iobase, UART_INTERFACE);
+ irq = config >> 4 & 0x0f;
+ dma = config & 0x0f;
+
+ if (high == 0x10 && low == 0xb8 && chip == 0xf1) {
+ DEBUG(0, "SMC IrDA Controller found; version = %d, "
+ "port 0x%04x, dma %d, interrupt %d\n",
+ version, iobase, dma, irq);
+ } else {
+ return -1;
+ }
+
+ serial_out(iobase, UART_MASTER, 0);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+ return config;
+}
+
+/*
+ * Function ircc_change_speed (idev, baud)
+ *
+ * Change the speed of the device
+ *
+ */
+static void ircc_change_speed( struct irda_device *idev, int speed)
+{
+ struct ircc_cb *self;
+ int iobase, ir_mode, select, fast;
+
+ DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+
+ ASSERT(idev != NULL, return;);
+ ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+ self = idev->priv;
+ iobase = idev->io.iobase;
+
+ /* Update accounting for new speed */
+ idev->io.baudrate = speed;
+
+ switch ( speed) {
+ case 9600:
+ case 19200:
+ case 37600:
+ case 57600:
+ case 115200:
+ DEBUG(ircc_debug+1,
+ __FUNCTION__ ": using irport to change speed to %d\n",
+ speed);
+ register_bank(iobase, 0);
+ serial_out(iobase, UART_IER, 0);
+ serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+ serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+ irport_start(idev, idev->io.iobase2);
+ irport_change_speed( idev, speed);
+ return;
+ break;
+
+ case 576000:
+ ir_mode = UART_CFGA_IRDA_HDLC;
+ select = 0;
+ fast = 0;
+ DEBUG( ircc_debug, __FUNCTION__ ": handling baud of 576000\n");
+ break;
+ case 1152000:
+ ir_mode = UART_CFGA_IRDA_HDLC;
+ select = UART_1152;
+ fast = 0;
+ DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 1152000\n");
+ break;
+ case 4000000:
+ ir_mode = UART_CFGA_IRDA_4PPM;
+ select = 0;
+ fast = UART_LCR_A_FAST;
+ DEBUG(ircc_debug, __FUNCTION__ ": handling baud of 4000000\n");
+ break;
+ default:
+ DEBUG( 0, __FUNCTION__ ": unknown baud rate of %d\n", speed);
+ return;
+ }
+
+#if 0
+ serial_out(idev->io.iobase2, 4, 0x08);
+#endif
+
+ serial_out(iobase, UART_MASTER, UART_MASTER_RESET);
+
+ register_bank(iobase, 0);
+ serial_out(iobase, UART_IER, 0);
+
+ irport_stop(idev, idev->io.iobase2);
+
+ idev->netdev.tbusy = 0;
+
+ register_bank(iobase, 1);
+
+ serial_out(iobase, UART_SCE_CFGA,
+ ((serial_in(iobase, UART_SCE_CFGA) & 0x87) | ir_mode));
+
+ serial_out(iobase, UART_SCE_CFGB,
+ ((serial_in(iobase, UART_SCE_CFGB) & 0x3f) | UART_CFGB_IR));
+
+ (void) serial_in(iobase, UART_FIFO_THRESHOLD);
+ serial_out(iobase, UART_FIFO_THRESHOLD, 64);
+
+ register_bank(iobase, 4);
+
+ serial_out(iobase, UART_CONTROL,
+ (serial_in(iobase, UART_CONTROL) & 0x30)
+ | select | UART_CRC );
+
+ register_bank(iobase, 0);
+
+ serial_out(iobase, UART_LCR_A, fast);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_hard_xmit (skb, dev)
+ *
+ * Transmit the frame!
+ *
+ */
+static int ircc_hard_xmit( struct sk_buff *skb, struct device *dev)
+{
+ struct irda_device *idev;
+ int iobase;
+ int mtt;
+
+ DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+ idev = (struct irda_device *) dev->priv;
+
+ ASSERT( idev != NULL, return 0;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+ iobase = idev->io.iobase;
+
+ DEBUG(ircc_debug+1, __FUNCTION__ "(%ld), skb->len=%d\n", jiffies, (int) skb->len);
+
+ /* Use irport for SIR speeds */
+ if (idev->io.baudrate <= 115200) {
+ DEBUG(ircc_debug+1, __FUNCTION__ ": calling irport_hard_xmit\n");
+ return irport_hard_xmit(skb, dev);
+ }
+
+ DEBUG(ircc_debug, __FUNCTION__ ": using dma; len=%d\n", skb->len);
+
+ /* Lock transmit buffer */
+ if (irda_lock((void *) &dev->tbusy) == FALSE)
+ return -EBUSY;
+
+ memcpy( idev->tx_buff.head, skb->data, skb->len);
+
+ /* Make sure that the length is a multiple of 16 bits */
+ if ( skb->len & 0x01)
+ skb->len++;
+
+ idev->tx_buff.len = skb->len;
+ idev->tx_buff.data = idev->tx_buff.head;
+#if 0
+ idev->tx_buff.offset = 0;
+#endif
+
+ mtt = irda_get_mtt( skb);
+
+ /* Use udelay for delays less than 50 us. */
+ if (mtt)
+ udelay( mtt);
+
+ ircc_dma_write( idev, iobase);
+
+ dev_kfree_skb( skb);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+/*
+ * Function ircc_dma_xmit (idev, iobase)
+ *
+ * Transmit data using DMA
+ *
+ */
+static void ircc_dma_write( struct irda_device *idev, int iobase)
+{
+ struct ircc_cb *self;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ ASSERT( idev != NULL, return;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+ self = idev->priv;
+ iobase = idev->io.iobase;
+
+ setup_dma( idev->io.dma, idev->tx_buff.data, idev->tx_buff.len,
+ DMA_MODE_WRITE);
+
+ idev->io.direction = IO_XMIT;
+
+ serial_out(idev->io.iobase2, 4, 0x08);
+
+ register_bank(iobase, 4);
+ serial_out(iobase, UART_CONTROL,
+ (serial_in(iobase, UART_CONTROL) & 0xF0));
+
+ serial_out(iobase, UART_BOF_COUNT_LO, 2);
+ serial_out(iobase, UART_BRICKWALL_CNT_LO, 0);
+#if 1
+ serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, idev->tx_buff.len >> 8);
+ serial_out(iobase, UART_TX_SIZE_LO, idev->tx_buff.len & 0xff);
+#else
+ serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
+ serial_out(iobase, UART_TX_SIZE_LO, 0);
+#endif
+
+ register_bank(iobase, 1);
+ serial_out(iobase, UART_SCE_CFGB,
+ serial_in(iobase, UART_SCE_CFGB) | UART_CFGB_DMA_ENABLE);
+
+ register_bank(iobase, 0);
+
+ serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME | UART_IER_EOM);
+ serial_out(iobase, UART_LCR_B,
+ UART_LCR_B_SCE_TRANSMIT|UART_LCR_B_SIP_ENABLE);
+
+ serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_dma_xmit_complete (idev)
+ *
+ * The transfer of a frame in finished. This function will only be called
+ * by the interrupt handler
+ *
+ */
+static void ircc_dma_xmit_complete( struct irda_device *idev, int underrun)
+{
+ struct ircc_cb *self;
+ int iobase, d;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ ASSERT( idev != NULL, return;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+
+ register_bank(idev->io.iobase, 1);
+
+ serial_out(idev->io.iobase, UART_SCE_CFGB,
+ serial_in(idev->io.iobase, UART_SCE_CFGB) &
+ ~UART_CFGB_DMA_ENABLE);
+
+ d = get_dma_residue(idev->io.dma);
+
+ DEBUG(ircc_debug, __FUNCTION__ ": dma residue = %d, len=%d, sent=%d\n",
+ d, idev->tx_buff.len, idev->tx_buff.len - d);
+
+ self = idev->priv;
+
+ iobase = idev->io.iobase;
+
+ /* Check for underrrun! */
+ if ( underrun) {
+ idev->stats.tx_errors++;
+ idev->stats.tx_fifo_errors++;
+ } else {
+ idev->stats.tx_packets++;
+ idev->stats.tx_bytes += idev->tx_buff.len;
+ }
+
+ /* Unlock tx_buff and request another frame */
+ idev->netdev.tbusy = 0; /* Unlock */
+ idev->media_busy = FALSE;
+
+ /* Tell the network layer, that we can accept more frames */
+ mark_bh( NET_BH);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_dma_receive (idev)
+ *
+ * Get ready for receiving a frame. The device will initiate a DMA
+ * if it starts to receive a frame.
+ *
+ */
+static int ircc_dma_receive( struct irda_device *idev)
+{
+ struct ircc_cb *self;
+ int iobase;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ ASSERT( idev != NULL, return -1;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return -1;);
+
+ self = idev->priv;
+ iobase= idev->io.iobase;
+
+ setup_dma( idev->io.dma, idev->rx_buff.data, idev->rx_buff.truesize,
+ DMA_MODE_READ);
+
+ /* driver->media_busy = FALSE; */
+ idev->io.direction = IO_RECV;
+ idev->rx_buff.data = idev->rx_buff.head;
+#if 0
+ idev->rx_buff.offset = 0;
+#endif
+
+ register_bank(iobase, 4);
+ serial_out(iobase, UART_CONTROL,
+ (serial_in(iobase, UART_CONTROL) &0xF0));
+ serial_out(iobase, UART_BOF_COUNT_LO, 2);
+ serial_out(iobase, UART_BRICKWALL_CNT_LO, 0);
+ serial_out(iobase, UART_BRICKWALL_TX_CNT_HI, 0);
+ serial_out(iobase, UART_TX_SIZE_LO, 0);
+ serial_out(iobase, UART_RX_SIZE_HI, 0);
+ serial_out(iobase, UART_RX_SIZE_LO, 0);
+
+ register_bank(iobase, 0);
+ serial_out(iobase,
+ UART_LCR_B, UART_LCR_B_SCE_RECEIVE | UART_LCR_B_SIP_ENABLE);
+
+ register_bank(iobase, 1);
+ serial_out(iobase, UART_SCE_CFGB,
+ serial_in(iobase, UART_SCE_CFGB) |
+ UART_CFGB_DMA_ENABLE | UART_CFGB_DMA_BURST);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+/*
+ * Function ircc_dma_receive_complete (idev)
+ *
+ * Finished with receiving frames
+ *
+ *
+ */
+static int ircc_dma_receive_complete( struct irda_device *idev, int iobase)
+{
+ struct sk_buff *skb;
+ struct ircc_cb *self;
+ int len, msgcnt;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ self = idev->priv;
+
+ msgcnt = serial_in(idev->io.iobase, UART_LCR_B) & 0x08;
+
+ DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
+ get_dma_residue(idev->io.dma));
+
+ len = idev->rx_buff.truesize - get_dma_residue(idev->io.dma) - 4;
+
+ DEBUG(ircc_debug, __FUNCTION__ ": msgcnt = %d, len=%d\n", msgcnt, len);
+
+ skb = dev_alloc_skb( len+1);
+
+ if (skb == NULL) {
+ printk( KERN_INFO __FUNCTION__
+ ": memory squeeze, dropping frame.\n");
+ return FALSE;
+ }
+
+ /* Make sure IP header gets aligned */
+ skb_reserve( skb, 1);
+ skb_put( skb, len);
+
+ memcpy(skb->data, idev->rx_buff.data, len);
+ idev->stats.rx_packets++;
+
+ skb->dev = &idev->netdev;
+ skb->mac.raw = skb->data;
+ skb->protocol = htons(ETH_P_IRDA);
+ netif_rx( skb);
+
+ register_bank(idev->io.iobase, 1);
+ serial_out(idev->io.iobase, UART_SCE_CFGB,
+ serial_in(idev->io.iobase, UART_SCE_CFGB) &
+ ~UART_CFGB_DMA_ENABLE);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return TRUE;
+}
+
+/*
+ * Function ircc_interrupt (irq, dev_id, regs)
+ *
+ * An interrupt from the chip has arrived. Time to do some work
+ *
+ */
+static void ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int iobase, iir;
+
+ struct irda_device *idev = (struct irda_device *) dev_id;
+
+ DEBUG(ircc_debug+1, __FUNCTION__ " -->\n");
+
+ if (idev == NULL) {
+ printk( KERN_WARNING "%s: irq %d for unknown device.\n",
+ driver_name, irq);
+ return;
+ }
+
+ if (idev->io.baudrate <= 115200) {
+ DEBUG(ircc_debug+1, __FUNCTION__
+ ": routing interrupt to irport_interrupt\n");
+ return irport_interrupt( irq, dev_id, regs);
+ }
+
+ iobase = idev->io.iobase;
+
+ idev->netdev.interrupt = 1;
+
+ serial_out(iobase, UART_MASTER, 0);
+
+ register_bank(iobase, 0);
+
+ iir = serial_in(iobase, UART_IIR);
+
+ serial_out(iobase, UART_IER, 0);
+
+ DEBUG(ircc_debug, __FUNCTION__ ": iir = 0x%02x\n", iir);
+
+ if (iir & UART_IIR_EOM) {
+ DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_EOM\n");
+ if (idev->io.direction == IO_RECV) {
+ ircc_dma_receive_complete(idev, iobase);
+ } else {
+ ircc_dma_xmit_complete(idev, iobase);
+ }
+ ircc_dma_receive(idev);
+ }
+
+ if (iir & UART_IIR_ACTIVE_FRAME) {
+ DEBUG(ircc_debug, __FUNCTION__ ": UART_IIR_ACTIVE_FRAME\n");
+ idev->rx_buff.state = INSIDE_FRAME;
+#if 0
+ ircc_dma_receive(idev);
+#endif
+ }
+
+ if (iir & UART_IIR_RAW_MODE) {
+ DEBUG(ircc_debug, __FUNCTION__ ": IIR RAW mode interrupt.\n");
+ }
+
+ idev->netdev.interrupt = 0;
+
+ register_bank(iobase, 0);
+ serial_out(iobase, UART_IER, UART_IER_ACTIVE_FRAME|UART_IER_EOM);
+ serial_out(iobase, UART_MASTER, UART_MASTER_INT_EN);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_wait_until_sent (idev)
+ *
+ * This function should put the current thread to sleep until all data
+ * have been sent, so it is safe to change the speed.
+ */
+static void ircc_wait_until_sent( struct irda_device *idev)
+{
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ /* Just delay 60 ms */
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(6);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+}
+
+/*
+ * Function ircc_is_receiving (idev)
+ *
+ * Return TRUE is we are currently receiving a frame
+ *
+ */
+static int ircc_is_receiving( struct irda_device *idev)
+{
+ int status = FALSE;
+ /* int iobase; */
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ ASSERT( idev != NULL, return FALSE;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+
+ DEBUG(ircc_debug, __FUNCTION__ ": dma count = %d\n",
+ get_dma_residue(idev->io.dma));
+
+ status = ( idev->rx_buff.state != OUTSIDE_FRAME);
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+
+ return status;
+}
+
+/*
+ * Function ircc_net_init (dev)
+ *
+ * Initialize network device
+ *
+ */
+static int ircc_net_init( struct device *dev)
+{
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ /* Setup to be a normal IrDA network device driver */
+ irda_device_setup( dev);
+
+ /* Insert overrides below this line! */
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+
+/*
+ * Function ircc_net_open (dev)
+ *
+ * Start the device
+ *
+ */
+static int ircc_net_open( struct device *dev)
+{
+ struct irda_device *idev;
+ int iobase;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ ASSERT( dev != NULL, return -1;);
+ idev = (struct irda_device *) dev->priv;
+
+ ASSERT( idev != NULL, return 0;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+ iobase = idev->io.iobase;
+
+ if (request_irq( idev->io.irq, ircc_interrupt, 0, idev->name,
+ (void *) idev)) {
+ return -EAGAIN;
+ }
+ /*
+ * Always allocate the DMA channel after the IRQ,
+ * and clean up on failure.
+ */
+ if (request_dma(idev->io.dma, idev->name)) {
+ free_irq( idev->io.irq, idev);
+ return -EAGAIN;
+ }
+
+ /* Ready to play! */
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+
+ /* turn on interrupts */
+
+ MOD_INC_USE_COUNT;
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+/*
+ * Function ircc_net_close (dev)
+ *
+ * Stop the device
+ *
+ */
+static int ircc_net_close(struct device *dev)
+{
+ struct irda_device *idev;
+ int iobase;
+
+ DEBUG(ircc_debug, __FUNCTION__ " -->\n");
+
+ /* Stop device */
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ ASSERT( dev != NULL, return -1;);
+ idev = (struct irda_device *) dev->priv;
+
+ ASSERT( idev != NULL, return 0;);
+ ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return 0;);
+
+ iobase = idev->io.iobase;
+
+ disable_dma( idev->io.dma);
+
+ /* Disable interrupts */
+
+ free_irq( idev->io.irq, idev);
+ free_dma( idev->io.dma);
+
+ MOD_DEC_USE_COUNT;
+
+ DEBUG( ircc_debug, "--> " __FUNCTION__ "\n");
+ return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Thomas Davis <tadavis@jps.net>");
+MODULE_DESCRIPTION("SMC IrCC controller driver");
+MODULE_PARM(ircc_debug,"1i");
+MODULE_PARM(ircc_dma, "1i");
+MODULE_PARM(ircc_irq, "1i");
+
+/*
+ * Function init_module (void)
+ *
+ *
+ *
+ */
+int init_module(void)
+{
+ return ircc_init();
+}
+
+/*
+ * Function cleanup_module (void)
+ *
+ *
+ *
+ */
+void cleanup_module(void)
+{
+ ircc_cleanup();
+}
+
+#endif
/*********************************************************************
*
* Filename: tekram.c
- * Version: 1.1
+ * Version: 1.2
* 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 May 10 16:10:17 1999
+ * Modified at: Sun May 16 14:33:42 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/ioctls.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-
#include <net/irda/irda.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_reset(struct irda_device *dev);
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);
#define TEKRAM_19200 0x03
#define TEKRAM_9600 0x04
-#define TEKRAM_PW 0x10 /* Pulse select bit */
+#define TEKRAM_PW 0x10 /* Pulse select bit */
static struct dongle dongle = {
TEKRAM_DONGLE,
ASSERT(idev != NULL, return;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
-
+
switch (baud) {
default:
case 9600:
case 19200:
byte = TEKRAM_PW|TEKRAM_19200;
break;
- case 34800:
+ case 38400:
byte = TEKRAM_PW|TEKRAM_38400;
break;
case 57600:
break;
}
+ /* Need to reset the dongle and go to 9600 bps before programming */
+ tekram_reset(idev);
+
/* Set DTR, Clear RTS */
irda_device_set_dtr_rts(idev, TRUE, FALSE);
* 3. clear DTR to SPACE state, wait at least 50 us for further
* operation
*/
-void tekram_reset(struct irda_device *idev, int unused)
+void tekram_reset(struct irda_device *idev)
{
ASSERT(idev != NULL, return;);
ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
irda_device_set_dtr_rts(idev, TRUE, TRUE);
udelay(50);
-
- /* Finished! */
+
+ /* Make sure the IrDA chip also goes to defalt speed */
+ if (idev->change_speed)
+ idev->change_speed(idev, 9600);
}
/*
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Dec 26 10:59:03 1998
- * Modified at: Mon May 10 22:11:09 1999
+ * Modified at: Wed May 19 15:29:56 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
idev->netdev.open = uircc_net_open;
idev->netdev.stop = uircc_net_close;
- irport_start(iobase2);
+ irport_start(idev, iobase2);
/* Open the IrDA device */
irda_device_open(idev, driver_name, self);
/* Disable modem */
outb(0x00, iobase+UIRCC_CR10);
- irport_stop(idev->io.iobase2);
+ irport_stop(idev, idev->io.iobase2);
/* Release the PORT that this driver is using */
DEBUG(4, __FUNCTION__ "(), Releasing Region %03x\n", idev->io.iobase);
case 37600:
case 57600:
case 115200:
- irport_start(idev->io.iobase2);
+ irport_start(idev, idev->io.iobase2);
irport_change_speed(idev, speed);
/* Some magic to disable FIR and enable SIR */
DEBUG(0, __FUNCTION__ "(), handling baud of 1152000\n");
break;
case 4000000:
- irport_stop(idev->io.iobase2);
+ irport_stop(idev, idev->io.iobase2);
/* Some magic to disable SIR and enable FIR */
uircc_toshiba_cmd(&status, 0xffff, 0x001b, 0x0001);
* Status: Experimental.
* Author: Paul VanderSpek
* Created at: Wed Nov 4 11:46:16 1998
- * Modified at: Thu May 13 08:03:27 1999
+ * Modified at: Fri May 21 22:18:19 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
static struct w83977af_ir *dev_self[] = { NULL, NULL, NULL, NULL};
-static struct st_fifo_entry prev;
-
/* Some prototypes */
static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
unsigned int dma);
DEBUG(0, __FUNCTION__ "()\n");
- prev.status = 0;
-
for (i=0; (io[i] < 2000) && (i < 4); i++) {
int ioaddr = io[i];
if (check_region(ioaddr, CHIP_IO_EXTENT) < 0)
* same Gnu Public License that covers that work.
*
* Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
- * Copyrights (c) 1994,1995,1996 by M.Hipp (Michael.Hipp@student.uni-tuebingen.de)
+ * Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
* [feel free to mail ....]
*
* when using as module: (no autoprobing!)
* This is an extension to the Linux operating system, and is covered by the
* same Gnu Public License that covers that work.
*
- * copyrights (c) 1994 by Michael Hipp (mhipp@student.uni-tuebingen.de)
+ * copyrights (c) 1994 by Michael Hipp (hippm@informatik.uni-tuebingen.de)
*
* I have done a look in the following sources:
* crynwr-packet-driver by Russ Nelson
*
* comments/bugs/suggestions can be sent to:
* Michael Hipp
- * email: Michael.Hipp@student.uni-tuebingen.de
+ * email: hippm@informatik.uni-tuebingen.de
*
* sources:
* some things are from the 'ni6510-packet-driver for dos by Russ Nelson'
*/
/*
+ * 99.Jun.8: added support for /proc/net/dev byte count for xosview (HK)
* 96.Sept.29: virt_to_bus stuff added for new memory modell
* 96.April.29: Added Harald Koenig's Patches (MH)
* 96.April.13: enhanced error handling .. more tests (MH)
p->stats.tx_errors++;
tmdp->status2 = 0;
}
- else
+ else {
+ p->stats.tx_bytes -= (short)(tmdp->blen);
p->stats.tx_packets++;
+ }
#ifdef XMT_VIA_SKB
if(p->tmd_skb[p->tmdlast]) {
eth_copy_and_sum(skb, (unsigned char *) p->recvbounce[p->rmdnum],len,0);
#endif
p->stats.rx_packets++;
+ p->stats.rx_bytes += len;
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
--- /dev/null
+/*
+net-3-driver for the SKNET MCA-based cards
+
+This is an extension to the Linux operating system, and is covered by the
+same Gnu Public License that covers that work.
+
+Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de, aarnold@elsa.de)
+
+This driver is based both on the 3C523 driver and the SK_G16 driver.
+
+paper sources:
+ 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
+ Hans-Peter Messmer for the basic Microchannel stuff
+
+ 'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
+ for help on Ethernet driver programming
+
+ 'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
+ for documentation on the AM7990 LANCE
+
+ 'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
+ for documentation on the Junior board
+
+ 'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
+ documentation on the MC2 bord
+
+ A big thank you to the S&K support for providing me so quickly with
+ documentation!
+
+ Also see http://www.syskonnect.com/
+
+ Missing things:
+
+ -> set debug level via ioctl instead of compile-time switches
+ -> I didn't follow the development of the 2.1.x kernels, so my
+ assumptions about which things changed with which kernel version
+ are probably nonsense
+
+History:
+ May 16th, 1999
+ startup
+ May 22st, 1999
+ added private structure, methods
+ begun building data structures in RAM
+ May 23nd, 1999
+ can receive frames, send frames
+ May 24th, 1999
+ modularized intialization of LANCE
+ loadable as module
+ still Tx problem :-(
+ May 26th, 1999
+ MC2 works
+ support for multiple devices
+ display media type for MC2+
+ May 28th, 1999
+ fixed problem in GetLANCE leaving interrupts turned off
+ increase TX queue to 4 packets to improve send performance
+ May 29th, 1999
+ a few corrections in statistics, caught rcvr overruns
+ reinitialization of LANCE/board in critical situations
+ MCA info implemented
+ implemented LANCE multicast filter
+ Jun 6th, 1999
+ additions for Linux 2.2
+
+ *************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/time.h>
+#include <linux/mca.h>
+#include <asm/processor.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#define _SK_MCA_DRIVER_
+#include "sk_mca.h"
+
+/* ------------------------------------------------------------------------
+ * global static data - not more since we can handle multiple boards and
+ * have to pack all state info into the device struct!
+ * ------------------------------------------------------------------------ */
+
+static char *MediaNames[Media_Count]=
+ {"10Base2", "10BaseT", "10Base5", "Unknown"};
+
+static unsigned char poly[] =
+ {1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0};
+
+/* ------------------------------------------------------------------------
+ * private subfunctions
+ * ------------------------------------------------------------------------ */
+
+/* dump parts of shared memory - only needed during debugging */
+
+#ifdef DEBUG
+static void dumpmem(struct device *dev, u32 start, u32 len)
+{
+ int z;
+
+ for (z = 0; z < len; z++)
+ {
+ if ((z & 15) == 0)
+ printk("%04x:", z);
+ printk(" %02x", readb(dev->mem_start + start + z));
+ if ((z & 15) == 15)
+ printk("\n");
+ }
+}
+
+/* print exact time - ditto */
+
+static void PrTime(void)
+{
+ struct timeval tv;
+
+ do_gettimeofday(&tv);
+ printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
+}
+#endif
+
+/* deduce resources out of POS registers */
+
+static void getaddrs(int slot, int junior, int *base, int *irq,
+ skmca_medium *medium)
+{
+ u_char pos0, pos1, pos2;
+
+ if (junior)
+ {
+ pos0 = mca_read_stored_pos(slot, 2);
+ *base = ((pos0 & 0x0e) << 13) + 0xc0000;
+ *irq = ((pos0 & 0x10) >> 4) + 10;
+ *medium = Media_Unknown;
+ }
+ else
+ {
+ /* reset POS 104 Bits 0+1 so the shared memory region goes to the
+ configured area between 640K and 1M. Afterwards, enable the MC2.
+ I really don't know what rode SK to do this... */
+
+ mca_write_pos(slot, 4, mca_read_stored_pos(slot, 4) & 0xfc);
+ mca_write_pos(slot, 2, mca_read_stored_pos(slot, 2) | 0x01);
+
+ pos1 = mca_read_stored_pos(slot, 3);
+ pos2 = mca_read_stored_pos(slot, 4);
+ *base = ((pos1 & 0x07) << 14) + 0xc0000;
+ switch (pos2 & 0x0c)
+ {
+ case 0: *irq = 3; break;
+ case 4: *irq = 5; break;
+ case 8: *irq = 10; break;
+ case 12: *irq = 11; break;
+ }
+ *medium = (pos2 >> 6) & 3;
+ }
+}
+
+/* check for both cards:
+ When the MC2 is turned off, it was configured for more than 15MB RAM,
+ is disabled and won't get detected using the standard probe. We
+ therefore have to scan the slots manually :-( */
+
+static int dofind(int *junior, int firstslot)
+{
+ int slot;
+ unsigned int id;
+
+ for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++)
+ {
+ id = mca_read_stored_pos(slot, 0)
+ + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
+
+ *junior = 0;
+ if (id == SKNET_MCA_ID)
+ return slot;
+ *junior = 1;
+ if (id == SKNET_JUNIOR_MCA_ID)
+ return slot;
+ }
+ return MCA_NOTFOUND;
+}
+
+/* reset the whole board */
+
+static void ResetBoard(struct device *dev)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+
+ writeb(CTRL_RESET_ON, priv->ctrladdr);
+ udelay(10);
+ writeb(CTRL_RESET_OFF, priv->ctrladdr);
+}
+
+/* set LANCE register - must be atomic */
+
+static void SetLANCE(struct device *dev, u16 addr, u16 value)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+ unsigned long flags;
+
+ /* disable interrupts */
+
+ save_flags(flags);
+ cli();
+
+ /* wait until no transfer is pending */
+
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+ /* transfer register address to RAP */
+
+ writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+ writew(addr, priv->ioregaddr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+ /* transfer data to register */
+
+ writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
+ writew(value, priv->ioregaddr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+ /* reenable interrupts */
+
+ restore_flags(flags);
+}
+
+/* get LANCE register */
+
+static u16 GetLANCE(struct device *dev, u16 addr)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+ unsigned long flags;
+ unsigned int res;
+
+ /* disable interrupts */
+
+ save_flags(flags);
+ cli();
+
+ /* wait until no transfer is pending */
+
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+ /* transfer register address to RAP */
+
+ writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
+ writew(addr, priv->ioregaddr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+
+ /* transfer data from register */
+
+ writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
+ writeb(IOCMD_GO, priv->cmdaddr);
+ udelay(1);
+ while ((readb(priv->ctrladdr) & STAT_IO_BUSY) == STAT_IO_BUSY);
+ res = readw(priv->ioregaddr);
+
+ /* reenable interrupts */
+
+ restore_flags(flags);
+
+ return res;
+}
+
+/* build up descriptors in shared RAM */
+
+static void InitDscrs(struct device *dev)
+{
+ u32 bufaddr;
+
+ /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
+ are always 0. */
+
+ bufaddr = RAM_DATABASE;
+ {
+ LANCE_TxDescr descr;
+ int z;
+
+ for (z = 0; z < TXCOUNT; z++)
+ {
+ descr.LowAddr = bufaddr;
+ descr.Flags = 0;
+ descr.Len = 0xf000;
+ descr.Status = 0;
+ memcpy_toio(dev->mem_start + RAM_TXBASE + (z * sizeof(LANCE_TxDescr)),
+ &descr, sizeof(LANCE_TxDescr));
+ memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
+ bufaddr += RAM_BUFSIZE;
+ }
+ }
+
+ /* do the same for the Rx descriptors */
+
+ {
+ LANCE_RxDescr descr;
+ int z;
+
+ for (z = 0; z < RXCOUNT; z++)
+ {
+ descr.LowAddr = bufaddr;
+ descr.Flags = RXDSCR_FLAGS_OWN;
+ descr.MaxLen = -RAM_BUFSIZE;
+ descr.Len = 0;
+ memcpy_toio(dev->mem_start + RAM_RXBASE + (z * sizeof(LANCE_RxDescr)),
+ &descr, sizeof(LANCE_RxDescr));
+ memset_io(dev->mem_start + bufaddr, 0, RAM_BUFSIZE);
+ bufaddr += RAM_BUFSIZE;
+ }
+ }
+}
+
+/* calculate the hash bit position for a given multicast address
+ taken more or less directly from the AMD datasheet... */
+
+static void UpdateCRC(unsigned char *CRC, int bit)
+{
+ int j;
+
+ /* shift CRC one bit */
+
+ memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
+ CRC[0] = 0;
+
+ /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
+
+ if (bit ^ CRC[32])
+ for (j = 0; j < 32; j++)
+ CRC[j] ^= poly[j];
+}
+
+static unsigned int GetHash(char *address)
+{
+ unsigned char CRC[33];
+ int i, byte, hashcode;
+
+ /* a multicast address has bit 0 in the first byte set */
+
+ if ((address[0] & 1) == 0)
+ return -1;
+
+ /* initialize CRC */
+
+ memset(CRC, 1, sizeof(CRC));
+
+ /* loop through address bits */
+
+ for (byte = 0; byte < 6; byte++)
+ for (i = 0; i < 8; i++)
+ UpdateCRC(CRC, (address[byte] >> i) & 1);
+
+ /* hashcode is the 6 least significant bits of the CRC */
+
+ hashcode = 0;
+ for (i = 0; i < 6; i++)
+ hashcode = (hashcode << 1) + CRC[i];
+ return hashcode;
+}
+
+/* feed ready-built initialization block into LANCE */
+
+static void InitLANCE(struct device *dev)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+
+ /* build up descriptors. */
+
+ InitDscrs(dev);
+
+ /* next RX descriptor to be read is the first one. Since the LANCE
+ will start from the beginning after initialization, we have to
+ reset out pointers too. */
+
+ priv->nextrx = 0;
+
+ /* no TX descriptors active */
+
+ priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
+
+ /* set up the LANCE bus control register - constant for SKnet boards */
+
+ SetLANCE(dev, LANCE_CSR3, CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
+
+ /* write address of initialization block into LANCE */
+
+ SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
+ SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
+
+ /* we don't get ready until the LANCE has read the init block */
+
+ dev->tbusy = 1;
+
+ /* let LANCE read the initialization block. LANCE is ready
+ when we receive the corresponding interrupt. */
+
+ SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
+}
+
+/* stop the LANCE so we can reinitialize it */
+
+static void StopLANCE(struct device *dev)
+{
+ /* can't take frames any more */
+
+ dev->tbusy = 1;
+
+ /* disable interrupts, stop it */
+
+ SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
+}
+
+/* initialize card and LANCE for proper operation */
+
+static void InitBoard(struct device *dev)
+{
+ LANCE_InitBlock block;
+
+ /* Lay out the shared RAM - first we create the init block for the LANCE.
+ We do not overwrite it later because we need it again when we switch
+ promiscous mode on/off. */
+
+ block.Mode = 0;
+ if (dev->flags & IFF_PROMISC)
+ block.Mode |= LANCE_INIT_PROM;
+ memcpy(block.PAdr, dev->dev_addr, 6);
+ memset(block.LAdrF, 0, sizeof(block.LAdrF));
+ block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
+ block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
+
+ memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+
+ /* initialize LANCE. Implicitly sets up other structures in RAM. */
+
+ InitLANCE(dev);
+}
+
+/* deinitialize card and LANCE */
+
+static void DeinitBoard(struct device *dev)
+{
+ /* stop LANCE */
+
+ StopLANCE(dev);
+
+ /* reset board */
+
+ ResetBoard(dev);
+}
+
+/* ------------------------------------------------------------------------
+ * interrupt handler(s)
+ * ------------------------------------------------------------------------ */
+
+/* LANCE has read initializazion block -> start it */
+
+static u16 irqstart_handler(struct device *dev, u16 oldcsr0)
+{
+ /* now we're ready to transmit */
+
+ dev->tbusy = 0;
+
+ /* reset IDON bit, start LANCE */
+
+ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
+ return GetLANCE(dev, LANCE_CSR0);
+}
+
+/* receive interrupt */
+
+static u16 irqrx_handler(struct device *dev, u16 oldcsr0)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+ LANCE_RxDescr descr;
+ unsigned int descraddr;
+
+ /* did we loose blocks due to a FIFO overrun ? */
+
+ if (oldcsr0 & CSR0_MISS)
+ priv->stat.rx_fifo_errors++;
+
+ /* run through queue until we reach a descriptor we do not own */
+
+ descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
+ while (1)
+ {
+ /* read descriptor */
+ memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_RxDescr));
+
+ /* if we reach a descriptor we do not own, we're done */
+ if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
+ break;
+
+#ifdef DEBUG
+ PrTime(); printk("Receive packet on descr %d len %d\n", priv->nextrx, descr.Len);
+#endif
+
+ /* erroneous packet ? */
+ if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0)
+ {
+ priv->stat.rx_errors++;
+ if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+ priv->stat.rx_crc_errors++;
+ else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
+ priv->stat.rx_frame_errors++;
+ else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
+ priv->stat.rx_fifo_errors++;
+ }
+
+ /* good packet ? */
+ else
+ {
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(descr.Len + 2);
+ if (skb == NULL)
+ priv->stat.rx_dropped++;
+ else
+ {
+ memcpy_fromio(skb_put(skb, descr.Len),
+ dev->mem_start + descr.LowAddr, descr.Len);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_NONE;
+ priv->stat.rx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119 /* byte counters for >= 2.1.25 */
+ priv->stat.rx_bytes += descr.Len;
+#endif
+ netif_rx(skb);
+ }
+ }
+
+ /* give descriptor back to LANCE */
+ descr.Len = 0;
+ descr.Flags |= RXDSCR_FLAGS_OWN;
+
+ /* update descriptor in shared RAM */
+ memcpy_toio(dev->mem_start + descraddr, &descr, sizeof(LANCE_RxDescr));
+
+ /* go to next descriptor */
+ priv->nextrx++; descraddr += sizeof(LANCE_RxDescr);
+ if (priv->nextrx >= RXCOUNT)
+ {
+ priv->nextrx = 0;
+ descraddr = RAM_RXBASE;
+ }
+ }
+
+ /* reset RINT bit */
+
+ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
+ return GetLANCE(dev, LANCE_CSR0);
+}
+
+/* transmit interrupt */
+
+static u16 irqtx_handler(struct device *dev, u16 oldcsr0)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+ LANCE_TxDescr descr;
+ unsigned int descraddr;
+
+ /* check descriptors at most until no busy one is left */
+
+ descraddr = RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
+ while (priv->txbusy > 0)
+ {
+ /* read descriptor */
+ memcpy_fromio(&descr, dev->mem_start + descraddr, sizeof(LANCE_TxDescr));
+
+ /* if the LANCE still owns this one, we've worked out all sent packets */
+ if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
+ break;
+
+#ifdef DEBUG
+ PrTime(); printk("Send packet done on descr %d\n", priv->nexttxdone);
+#endif
+
+ /* update statistics */
+ if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0)
+ {
+ priv->stat.tx_packets++;
+#if LINUX_VERSION_CODE >= 0x020119 /* byte counters for >= 2.1.25 */
+ priv->stat.tx_bytes++;
+#endif
+ }
+ else
+ {
+ priv->stat.tx_errors++;
+ if ((descr.Status & TXDSCR_STATUS_UFLO) != 0)
+ {
+ priv->stat.tx_fifo_errors++;
+ InitLANCE(dev);
+ }
+ else if ((descr.Status & TXDSCR_STATUS_LCOL) != 0)
+ priv->stat.tx_window_errors++;
+ else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
+ priv->stat.tx_carrier_errors++;
+ else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
+ priv->stat.tx_aborted_errors++;
+ }
+
+ /* go to next descriptor */
+ priv->nexttxdone++;
+ descraddr += sizeof(LANCE_TxDescr);
+ if (priv->nexttxdone >= TXCOUNT)
+ {
+ priv->nexttxdone = 0;
+ descraddr = RAM_TXBASE;
+ }
+ priv->txbusy--;
+ }
+
+ /* reset TX interrupt bit */
+
+ SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
+ oldcsr0 = GetLANCE(dev, LANCE_CSR0);
+
+ /* at least one descriptor is freed. Therefore we can accept
+ a new one */
+
+ dev->tbusy = 0;
+
+ /* inform upper layers we're in business again */
+
+ mark_bh(NET_BH);
+
+ return oldcsr0;
+}
+
+/* general interrupt entry */
+
+static void irq_handler(int irq, void *device, struct pt_regs *regs)
+{
+ struct device *dev = (struct device*) device;
+ u16 csr0val;
+
+ /* read CSR0 to get interrupt cause */
+
+ csr0val = GetLANCE(dev, LANCE_CSR0);
+
+ /* in case we're not meant... */
+
+ if ((csr0val & CSR0_INTR) == 0)
+ return;
+
+ dev->interrupt = 1;
+
+ /* loop through the interrupt bits until everything is clear */
+
+ do
+ {
+ if ((csr0val & CSR0_IDON) != 0)
+ csr0val = irqstart_handler(dev, csr0val);
+ if ((csr0val & CSR0_RINT) != 0)
+ csr0val = irqrx_handler(dev, csr0val);
+ if ((csr0val & CSR0_TINT) != 0)
+ csr0val = irqtx_handler(dev, csr0val);
+ }
+ while ((csr0val & CSR0_INTR) != 0);
+
+ dev->interrupt = 0;
+}
+
+/* ------------------------------------------------------------------------
+ * driver methods
+ * ------------------------------------------------------------------------ */
+
+/* MCA info */
+
+static int skmca_getinfo(char *buf, int slot, void *d)
+{
+ int len = 0, i;
+ struct device *dev = (struct device*) d;
+ skmca_priv *priv;
+
+ /* can't say anything about an uninitialized device... */
+
+ if (dev == NULL)
+ return len;
+ if (dev->priv == NULL)
+ return len;
+ priv = (skmca_priv*) dev->priv;
+
+ /* print info */
+
+ len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
+ len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
+ dev->mem_end - 1);
+ len += sprintf(buf + len, "Transceiver: %s\n", MediaNames[priv->medium]);
+ len += sprintf(buf + len, "Device: %s\n", dev->name);
+ len += sprintf(buf + len, "MAC address:");
+ for (i = 0; i < 6; i ++ )
+ len += sprintf( buf+len, " %02x", dev->dev_addr[i] );
+ buf[len++] = '\n';
+ buf[len] = 0;
+
+ return len;
+}
+
+/* open driver. Means also initialization and start of LANCE */
+
+static int skmca_open(struct device *dev)
+{
+ int result;
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+
+ /* register resources - only necessary for IRQ */
+ result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM,
+ "sk_mca", dev);
+ if (result != 0)
+ {
+ printk("%s: failed to register irq %d\n", dev->name, dev->irq);
+ return result;
+ }
+ dev->irq = priv->realirq;
+
+ /* set up the card and LANCE */
+ InitBoard(dev);
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ return 0;
+}
+
+/* close driver. Shut down board and free allocated resources */
+
+static int skmca_close(struct device *dev)
+{
+ /* turn off board */
+ DeinitBoard(dev);
+
+ /* release resources */
+ if (dev->irq != 0)
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
+
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
+ return 0;
+}
+
+/* transmit a block. */
+
+static int skmca_tx(struct sk_buff *skb, struct device *dev)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+ LANCE_TxDescr descr;
+ unsigned int address;
+ int tmplen, retval = 0;
+ unsigned long flags;
+
+ /* if we get called with a NULL descriptor, the Ethernet layer thinks
+ our card is stuck an we should reset it. We'll do this completely: */
+
+ if (skb == NULL)
+ {
+ DeinitBoard(dev);
+ InitBoard(dev);
+ return 0; /* don't try to free the block here ;-) */
+ }
+
+ /* is there space in the Tx queue ? If no, the upper layer gave us a
+ packet in spite of us not being ready and is really in trouble.
+ We'll do the dropping for him: */
+ if (priv->txbusy >= TXCOUNT)
+ {
+ priv->stat.tx_dropped++;
+ retval = -EIO;
+ goto tx_done;
+ }
+
+ /* get TX descriptor */
+ address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
+ memcpy_fromio(&descr, dev->mem_start + address, sizeof(LANCE_TxDescr));
+
+ /* enter packet length as 2s complement - assure minimum length */
+ tmplen = skb->len;
+ if (tmplen < 60)
+ tmplen = 60;
+ descr.Len = 65536 - tmplen;
+
+ /* copy filler into RAM - in case we're filling up...
+ we're filling a bit more than necessary, but that doesn't harm
+ since the buffer is far larger... */
+ if (tmplen > skb->len)
+ {
+ char *fill = "NetBSD is a nice OS too! ";
+ unsigned int destoffs = 0, l = strlen(fill);
+
+ while (destoffs < tmplen)
+ {
+ memcpy_toio(dev->mem_start + descr.LowAddr + destoffs, fill, l);
+ destoffs += l;
+ }
+ }
+
+ /* do the real data copying */
+ memcpy_toio(dev->mem_start + descr.LowAddr, skb->data, skb->len);
+
+ /* hand descriptor over to LANCE - this is the first and last chunk */
+ descr.Flags = TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
+
+#ifdef DEBUG
+ PrTime(); printk("Send packet on descr %d len %d\n", priv->nexttxput, skb->len);
+#endif
+
+ /* one more descriptor busy */
+ save_flags(flags);
+ cli();
+ priv->nexttxput++;
+ if (priv->nexttxput >= TXCOUNT)
+ priv->nexttxput = 0;
+ priv->txbusy++;
+ dev->tbusy = (priv->txbusy >= TXCOUNT);
+
+ /* write descriptor back to RAM */
+ memcpy_toio(dev->mem_start + address, &descr, sizeof(LANCE_TxDescr));
+
+ /* if no descriptors were active, give the LANCE a hint to read it
+ immediately */
+
+ if (priv->txbusy == 0)
+ SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
+
+ restore_flags(flags);
+
+tx_done:
+
+ /* When did that change exactly ? */
+
+#if LINUX_VERSION_CODE >= 0x020200
+ dev_kfree_skb(skb);
+#else
+ dev_kfree_skb(skb, FREE_WRITE);
+#endif
+ return retval;
+}
+
+/* return pointer to Ethernet statistics */
+
+static struct enet_statistics *skmca_stats(struct device *dev)
+{
+ skmca_priv *priv = (skmca_priv*) dev->priv;
+
+ return &(priv->stat);
+}
+
+/* we don't support runtime reconfiguration, since am MCA card can
+ be unambigously identified by its POS registers. */
+
+static int skmca_config(struct device *dev, struct ifmap *map)
+{
+ return 0;
+}
+
+/* switch receiver mode. We use the LANCE's multicast filter to prefilter
+ multicast addresses. */
+
+static void skmca_set_multicast_list(struct device *dev)
+{
+ LANCE_InitBlock block;
+
+ /* first stop the LANCE... */
+ StopLANCE(dev);
+
+ /* ...then modify the initialization block... */
+ memcpy_fromio(&block, dev->mem_start + RAM_INITBASE, sizeof(block));
+ if (dev->flags & IFF_PROMISC)
+ block.Mode |= LANCE_INIT_PROM;
+ else
+ block.Mode &= ~LANCE_INIT_PROM;
+
+ if (dev->flags & IFF_ALLMULTI) /* get all multicasts */
+ {
+ memset(block.LAdrF, 8, 0xff);
+ }
+ else /* get selected/no multicasts */
+ {
+ struct dev_mc_list *mptr;
+ int code;
+
+ memset(block.LAdrF, 8, 0x00);
+ for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next)
+ {
+ code = GetHash(mptr->dmi_addr);
+ block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
+ }
+ }
+
+ memcpy_toio(dev->mem_start + RAM_INITBASE, &block, sizeof(block));
+
+ /* ...then reinit LANCE with the correct flags */
+ InitLANCE(dev);
+}
+
+/* ------------------------------------------------------------------------
+ * hardware check
+ * ------------------------------------------------------------------------ */
+
+#ifdef MODULE
+static int startslot; /* counts through slots when probing multiple devices */
+#else
+#define startslot 0 /* otherwise a dummy, since there is only eth0 in-kern*/
+#endif
+
+int skmca_probe(struct device *dev)
+{
+ int force_detect = 0;
+ int junior, slot, i;
+ int base = 0, irq = 0;
+ skmca_priv *priv;
+ skmca_medium medium;
+
+ /* can't work without an MCA bus ;-) */
+
+ if (MCA_bus == 0)
+ return ENODEV;
+
+ /* start address of 1 --> forced detection */
+
+ if (dev->mem_start == 1)
+ force_detect = 1;
+
+ /* search through slots */
+
+ if (dev != NULL)
+ {
+ base = dev->mem_start;
+ irq = dev->irq;
+ }
+ slot = dofind(&junior, startslot);
+
+ while (slot != -1)
+ {
+ /* deduce card addresses */
+
+ getaddrs(slot, junior, &base, &irq, &medium);
+
+#if 0
+ /* this should work, but it doesn't with 2.2.9 :-(
+ somehow 'mca_is_adapter_used()' is missing in kernel syms... */
+#if LINUX_VERSION_CODE >= 0x020200
+ /* slot already in use ? */
+
+ if (mca_is_adapter_used(slot))
+ {
+ slot = dofind(&junior, slot + 1);
+ continue;
+ }
+#endif
+#endif
+
+ /* were we looking for something different ? */
+
+ if ((dev->irq != 0) || (dev->mem_start != 0))
+ {
+ if ((dev->irq != 0) && (dev->irq != irq))
+ {
+ slot = dofind(&junior, slot + 1);
+ continue;
+ }
+ if ((dev->mem_start != 0) && (dev->mem_start != base))
+ {
+ slot = dofind(&junior, slot + 1);
+ continue;
+ }
+ }
+
+ /* found something that matches */
+
+ break;
+ }
+
+ /* nothing found ? */
+
+ if (slot == -1)
+ return ((base != 0) || (irq != 0)) ? ENXIO : ENODEV;
+
+ /* make procfs entries */
+
+ if (junior)
+ mca_set_adapter_name(slot, "SKNET junior MC2 Ethernet Adapter");
+ else
+ mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
+ mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
+
+#if LINUX_VERSION_CODE >= 0x020200
+ mca_mark_as_used(slot);
+#endif
+
+ /* announce success */
+ printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
+ junior ? "Junior MC2" : "MC2+", slot + 1);
+
+ /* allocate structure */
+ priv = dev->priv = (skmca_priv*) kmalloc(sizeof(skmca_priv), GFP_KERNEL);
+ priv->slot = slot;
+ priv->macbase = base + 0x3fc0;
+ priv->ioregaddr = base + 0x3ff0;
+ priv->ctrladdr = base + 0x3ff2;
+ priv->cmdaddr = base + 0x3ff3;
+ priv->realirq = irq;
+ priv->medium = medium;
+ memset(&(priv->stat), 0, sizeof(struct enet_statistics));
+
+ /* set base + irq for this device (irq not allocated so far) */
+ dev->irq = 0;
+ dev->mem_start = base;
+ dev->mem_end = base + 0x4000;
+
+ /* set methods */
+ dev->open = skmca_open;
+ dev->stop = skmca_close;
+ dev->set_config = skmca_config;
+ dev->hard_start_xmit = skmca_tx;
+ dev->do_ioctl = NULL;
+ dev->get_stats = skmca_stats;
+ dev->set_multicast_list = skmca_set_multicast_list;
+ dev->flags |= IFF_MULTICAST;
+
+ /* generic setup */
+ ether_setup(dev);
+ dev->interrupt = 0;
+ dev->tbusy = 0;
+ dev->start = 0;
+
+ /* copy out MAC address */
+ for (i = 0; i < 6; i++)
+ dev->dev_addr[i] = readb(priv->macbase + (i << 1));
+
+ /* print config */
+ printk("%s: IRQ %d, memory %#lx-%#lx, "
+ "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+ dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
+
+ /* reset board */
+
+ ResetBoard(dev);
+
+#ifdef MODULE
+ startslot = slot + 1;
+#endif
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------------
+ * modularization support
+ * ------------------------------------------------------------------------ */
+
+#ifdef MODULE
+
+#define DEVMAX 5
+
+static char NameSpace[8 * DEVMAX];
+static struct device moddevs[DEVMAX] =
+ {{NameSpace + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+ {NameSpace + 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+ {NameSpace + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+ {NameSpace + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe},
+ {NameSpace + 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, skmca_probe}};
+
+int irq=0;
+int io=0;
+
+int init_module(void)
+{
+ int z, res;
+
+ startslot = 0;
+ for (z = 0; z < DEVMAX; z++)
+ {
+ strcpy(moddevs[z].name, " ");
+ res = register_netdev(moddevs + z);
+ if (res != 0)
+ return (z > 0) ? 0 : -EIO;
+ }
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ struct device *dev;
+ skmca_priv *priv;
+ int z;
+
+ if (MOD_IN_USE)
+ {
+ printk("cannot unload, module in use\n");
+ return;
+ }
+
+ for (z = 0; z < DEVMAX; z++)
+ {
+ dev = moddevs + z;
+ if (dev->priv != NULL)
+ {
+ priv = (skmca_priv*) dev->priv;
+ DeinitBoard(dev);
+ if (dev->irq != 0)
+ free_irq(dev->irq, dev);
+ dev->irq = 0;
+ unregister_netdev(dev);
+#if LINUX_VERSION_CODE >= 0x020200
+ mca_mark_as_unused(priv->slot);
+#endif
+ mca_set_adapter_procfn(priv->slot, NULL, NULL);
+ kfree_s(dev->priv, sizeof(skmca_priv));
+ dev->priv = NULL;
+ }
+ }
+}
+#endif /* MODULE */
--- /dev/null
+#ifndef _SK_MCA_INCLUDE_
+#define _SK_MCA_INCLUDE_
+
+#ifdef _SK_MCA_DRIVER_
+
+/* Adapter ID's */
+#define SKNET_MCA_ID 0x6afd
+#define SKNET_JUNIOR_MCA_ID 0x6be9
+
+/* media enumeration - defined in a way that it fits onto the MC2+'s
+ POS registers... */
+
+typedef enum {Media_10Base2, Media_10BaseT,
+ Media_10Base5, Media_Unknown, Media_Count} skmca_medium;
+
+/* private structure */
+typedef struct
+ {
+ unsigned int slot; /* MCA-Slot-# */
+ unsigned int macbase; /* base address of MAC address PROM */
+ unsigned int ioregaddr; /* address of I/O-register (Lo) */
+ unsigned int ctrladdr; /* address of control/stat register */
+ unsigned int cmdaddr; /* address of I/O-command register */
+ int nextrx; /* index of next RX descriptor to
+ be read */
+ int nexttxput; /* index of next free TX descriptor */
+ int nexttxdone; /* index of next TX descriptor to
+ be finished */
+ int txbusy; /* # of busy TX descriptors */
+ struct enet_statistics stat; /* packet statistics */
+ int realirq; /* memorizes actual IRQ, even when
+ currently not allocated */
+ skmca_medium medium; /* physical cannector */
+ } skmca_priv;
+
+/* card registers: control/status register bits */
+
+#define CTRL_ADR_DATA 0 /* Bit 0 = 0 ->access data register */
+#define CTRL_ADR_RAP 1 /* Bit 0 = 1 ->access RAP register */
+#define CTRL_RW_WRITE 0 /* Bit 1 = 0 ->write register */
+#define CTRL_RW_READ 2 /* Bit 1 = 1 ->read register */
+#define CTRL_RESET_ON 0 /* Bit 3 = 0 ->reset board */
+#define CTRL_RESET_OFF 8 /* Bit 3 = 1 ->no reset of board */
+
+#define STAT_ADR_DATA 0 /* Bit 0 of ctrl register read back */
+#define STAT_ADR_RAP 1
+#define STAT_RW_WRITE 0 /* Bit 1 of ctrl register read back */
+#define STAT_RW_READ 2
+#define STAT_RESET_ON 0 /* Bit 3 of ctrl register read back */
+#define STAT_RESET_OFF 8
+#define STAT_IRQ_ACT 0 /* interrupt pending */
+#define STAT_IRQ_NOACT 16 /* no interrupt pending */
+#define STAT_IO_NOBUSY 0 /* no transfer busy */
+#define STAT_IO_BUSY 32 /* transfer busy */
+
+/* I/O command register bits */
+
+#define IOCMD_GO 128 /* Bit 7 = 1 -> start register xfer */
+
+/* LANCE registers */
+
+#define LANCE_CSR0 0 /* Status/Control */
+
+#define CSR0_ERR 0x8000 /* general error flag */
+#define CSR0_BABL 0x4000 /* transmitter timeout */
+#define CSR0_CERR 0x2000 /* collision error */
+#define CSR0_MISS 0x1000 /* lost Rx block */
+#define CSR0_MERR 0x0800 /* memory access error */
+#define CSR0_RINT 0x0400 /* receiver interrupt */
+#define CSR0_TINT 0x0200 /* transmitter interrupt */
+#define CSR0_IDON 0x0100 /* initialization done */
+#define CSR0_INTR 0x0080 /* general interrupt flag */
+#define CSR0_INEA 0x0040 /* interrupt enable */
+#define CSR0_RXON 0x0020 /* receiver enabled */
+#define CSR0_TXON 0x0010 /* transmitter enabled */
+#define CSR0_TDMD 0x0008 /* force transmission now */
+#define CSR0_STOP 0x0004 /* stop LANCE */
+#define CSR0_STRT 0x0002 /* start LANCE */
+#define CSR0_INIT 0x0001 /* read initialization block */
+
+#define LANCE_CSR1 1 /* addr bit 0..15 of initialization */
+#define LANCE_CSR2 2 /* 16..23 block */
+
+#define LANCE_CSR3 3 /* Bus control */
+#define CSR3_BCON_HOLD 0 /* Bit 0 = 0 -> BM1,BM0,HOLD */
+#define CSR3_BCON_BUSRQ 1 /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ */
+#define CSR3_ALE_HIGH 0 /* Bit 1 = 0 -> ALE asserted high */
+#define CSR3_ALE_LOW 2 /* Bit 1 = 1 -> ALE asserted low */
+#define CSR3_BSWAP_OFF 0 /* Bit 2 = 0 -> no byte swap */
+#define CSR3_BSWAP_ON 0 /* Bit 2 = 1 -> byte swap */
+
+/* LANCE structures */
+
+typedef struct /* LANCE initialization block */
+ {
+ u16 Mode; /* mode flags */
+ u8 PAdr[6]; /* MAC address */
+ u8 LAdrF[8]; /* Multicast filter */
+ u32 RdrP; /* Receive descriptor */
+ u32 TdrP; /* Transmit descriptor */
+ } LANCE_InitBlock;
+
+/* Mode flags init block */
+
+#define LANCE_INIT_PROM 0x8000 /* enable promiscous mode */
+#define LANCE_INIT_INTL 0x0040 /* internal loopback */
+#define LANCE_INIT_DRTY 0x0020 /* disable retry */
+#define LANCE_INIT_COLL 0x0010 /* force collision */
+#define LANCE_INIT_DTCR 0x0008 /* disable transmit CRC */
+#define LANCE_INIT_LOOP 0x0004 /* loopback */
+#define LANCE_INIT_DTX 0x0002 /* disable transmitter */
+#define LANCE_INIT_DRX 0x0001 /* disable receiver */
+
+typedef struct /* LANCE Tx descriptor */
+ {
+ u16 LowAddr; /* bit 0..15 of address */
+ u16 Flags; /* bit 16..23 of address + Flags */
+ u16 Len; /* 2s complement of packet length */
+ u16 Status; /* Result of transmission */
+ } LANCE_TxDescr;
+
+#define TXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
+#define TXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
+#define TXDSCR_FLAGS_MORE 0x1000 /* more than one retry needed? */
+#define TXDSCR_FLAGS_ONE 0x0800 /* one retry? */
+#define TXDSCR_FLAGS_DEF 0x0400 /* transmission deferred? */
+#define TXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
+#define TXDSCR_FLAGS_ENP 0x0100 /* last packet in chain? */
+
+#define TXDSCR_STATUS_BUFF 0x8000 /* buffer error? */
+#define TXDSCR_STATUS_UFLO 0x4000 /* silo underflow during transmit? */
+#define TXDSCR_STATUS_LCOL 0x1000 /* late collision? */
+#define TXDSCR_STATUS_LCAR 0x0800 /* loss of carrier? */
+#define TXDSCR_STATUS_RTRY 0x0400 /* retry error? */
+
+typedef struct /* LANCE Rx descriptor */
+ {
+ u16 LowAddr; /* bit 0..15 of address */
+ u16 Flags; /* bit 16..23 of address + Flags */
+ u16 MaxLen; /* 2s complement of buffer length */
+ u16 Len; /* packet length */
+ } LANCE_RxDescr;
+
+#define RXDSCR_FLAGS_OWN 0x8000 /* LANCE owns descriptor */
+#define RXDSCR_FLAGS_ERR 0x4000 /* summary error flag */
+#define RXDSCR_FLAGS_FRAM 0x2000 /* framing error flag */
+#define RXDSCR_FLAGS_OFLO 0x1000 /* FIFO overflow? */
+#define RXDSCR_FLAGS_CRC 0x0800 /* CRC error? */
+#define RXDSCR_FLAGS_BUFF 0x0400 /* buffer error? */
+#define RXDSCR_FLAGS_STP 0x0200 /* first packet in chain? */
+#define RXDCSR_FLAGS_ENP 0x0100 /* last packet in chain? */
+
+/* RAM layout */
+
+#define TXCOUNT 4 /* length of TX descriptor queue */
+#define LTXCOUNT 2 /* log2 of it */
+#define RXCOUNT 4 /* length of RX descriptor queue */
+#define LRXCOUNT 2 /* log2 of it */
+
+#define RAM_INITBASE 0 /* LANCE init block */
+#define RAM_TXBASE 24 /* Start of TX descriptor queue */
+#define RAM_RXBASE \
+(RAM_TXBASE + (TXCOUNT * 8)) /* Start of RX descriptor queue */
+#define RAM_DATABASE \
+(RAM_RXBASE + (RXCOUNT * 8)) /* Start of data area for frames */
+#define RAM_BUFSIZE 1580 /* max. frame size - should never be
+ reached */
+
+#endif /* _SK_MCA_DRIVER_ */
+
+extern int skmca_probe(struct device *);
+
+
+#endif /* _SK_MCA_INCLUDE_ */
\ No newline at end of file
DEVICE( INTEL, INTEL_82450GX, "82450GX Orion P6"),
DEVICE( KTI, KTI_ET32P2, "ET32P2"),
DEVICE( ADAPTEC, ADAPTEC_7810, "AIC-7810 RAID"),
+ DEVICE( ADAPTEC, ADAPTEC_7821, "AIC-7860"),
DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"),
DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"),
DEVICE( ADAPTEC, ADAPTEC_5800, "AIC-5800"),
+ DEVICE( ADAPTEC, ADAPTEC_3860, "AIC-7860"),
DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"),
DEVICE( ADAPTEC, ADAPTEC_7861, "AIC-7861"),
DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"),
DEVICE( ADAPTEC, ADAPTEC_7882, "AIC-7882U"),
DEVICE( ADAPTEC, ADAPTEC_7883, "AIC-7883U"),
DEVICE( ADAPTEC, ADAPTEC_7884, "AIC-7884U"),
+ DEVICE( ADAPTEC, ADAPTEC_7885, "AIC-7885U"),
+ DEVICE( ADAPTEC, ADAPTEC_7886, "AIC-7886U"),
+ DEVICE( ADAPTEC, ADAPTEC_7887, "AIC-7887U"),
+ DEVICE( ADAPTEC, ADAPTEC_7888, "AIC-7888U"),
DEVICE( ADAPTEC, ADAPTEC_1030, "ABA-1030 DVB receiver"),
DEVICE( ADAPTEC2, ADAPTEC2_2940U2,"AHA-2940U2"),
- DEVICE( ADAPTEC2, ADAPTEC2_78902, "AIC-7890/1"),
+ DEVICE( ADAPTEC2, ADAPTEC2_2930U2,"AHA-2930U2"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7890B, "AIC-7890/1"),
DEVICE( ADAPTEC2, ADAPTEC2_7890, "AIC-7890/1"),
DEVICE( ADAPTEC2, ADAPTEC2_3940U2,"AHA-3940U2"),
DEVICE( ADAPTEC2, ADAPTEC2_3950U2D,"AHA-3950U2D"),
DEVICE( ADAPTEC2, ADAPTEC2_7896, "AIC-7896/7"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892A, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892B, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892D, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7892P, "AIC-7892"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899A, "AIC-7899"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899B, "AIC-7899"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899D, "AIC-7899"),
+ DEVICE( ADAPTEC2, ADAPTEC2_7899P, "AIC-7899"),
DEVICE( ATRONICS, ATRONICS_2015, "IDE-2015PL"),
DEVICE( TIGERJET, TIGERJET_300, "Tiger300 ISDN"),
DEVICE( ARK, ARK_STING, "Stingray"),
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/config.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
- bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
- if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
- int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 24
- fi
+ bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+ int ' Maximum number of TCQ commands per device' CONFIG_AIC7XXX_CMDS_PER_DEVICE 8
bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 5
fi
AHA-274xT
AHA-2842
AHA-2910B
+ AHA-2920C
+ AHA-2930
+ AHA-2930U
+ AHA-2930U2
AHA-2940
AHA-2940W
AHA-2940U
Adaptec Cards
----------------------------
AHA-2920 (Only the cards that use the Future Domain chipset are not
- supported, any 2920 cards based on Adaptec AIC chipsets are
- supported)
+ supported, any 2920 cards based on Adaptec AIC chipsets,
+ such as the 2920C, are supported)
AAA-13x Raid Adapters
AAA-113x Raid Port Card
Jess Johnson jester@frenzy.com
(AIC7xxx FAQ author)
Doug Ledford dledford@redhat.com
- (Current Linux aic7xxx-5.x.x Driver/Patch/FTP/FAQ maintainer)
+ (Current Linux aic7xxx-5.x.x Driver/Patch/FTP maintainer)
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
author of the driver. John has since retired from the project. Thanks
list and someone can help you out.
"aic7xxx=tag_info:{{8,8..},{8,8..},..}" - This option is used to disable
- tagged queueing on specific devices. As of driver version 5.1.8, we
- now globally enable tagged queueing by default. In order to
- disable tagged queueing for certian devices at boot time, a user may
- use this boot param. The driver will then parse this message out
- and disable the specific device entries that are present based upon
+ or enable Tagged Command Queueing (TCQ) on specific devices. As of
+ driver version 5.1.11, TCQ is now either on or off by default
+ according to the setting you choose during the make config process.
+ In order to en/disable TCQ for certian devices at boot time, a user
+ may use this boot param. The driver will then parse this message out
+ and en/disable the specific device entries that are present based upon
the value given. The param line is parsed in the following manner:
{ - first instance indicates the start of this parameter values
see this documentation, you need to use one of the advanced configuration
programs (menuconfig and xconfig). If you are using the "make menuconfig"
method of configuring your kernel, then you would simply highlight the
- option in question and hit the F1 key. If you are using the "make xconfig"
- method of configuring your kernel, then simply click on the help button next
- to the option you have questions about. The help information from the
- Configure.help file will then get automatically displayed.
+ option in question and hit the ? key. If you are using the "make xconfig"
+ method of configuring your kernel, then simply click on the help button
+ next to the option you have questions about. The help information from
+ the Configure.help file will then get automatically displayed.
/proc support
------------------------------
* under normal conditions.
*/
-/*
- * AIC7XXX_FAKE_NEGOTIATION_CMDS
- * We now have two distinctly different methods of device negotiation
- * in this code. The two methods are selected by either defining or not
- * defining this option. The difference is as follows:
- *
- * With AIC7XXX_FAKE_NEGOTIATION_CMDS not set (commented out)
- * When the driver is in need of issuing a negotiation command for any
- * given device, it will add the negotiation message on to part of a
- * regular SCSI command for the device. In the process, if the device
- * is configured for and using tagged queueing, then the code will
- * also issue that single command as a non-tagged command, attach the
- * negotiation message to that one command, and use a temporary
- * queue depth of one to keep the untagged and tagged commands from
- * overlapping.
- * Pros: This doesn't use any extra SCB structures, it's simple, it
- * works most of the time (if not all of the time now), and
- * since we get the device capability info frmo the INQUIRY data
- * now, shouldn't cause any problems.
- * Cons: When we need to send a negotiation command to a device, we
- * must use a command that is being sent to LUN 0 of the device.
- * If we try sending one to high LUN numbers, then some devices
- * get noticeably upset. Since we have to wait for a command with
- * LUN == 0 to come along, we may not be able to renegotiate when
- * we want if the user is actually using say LUN 1 of a CD Changer
- * instead of using LUN 0 for an extended period of time.
- *
- * With AIC7XXX_FAKE_NEGOTIATION_CMDS defined
- * When we need to negotiate with a device, instead of attaching our
- * negotiation message to an existing command, we insert our own
- * fictional Scsi_Cmnd into the chain that has the negotiation message
- * attached to it. We send this one command as untagged regardless
- * of the device type, and we fiddle with the queue depth the same as
- * we would with the option unset to avoid overlapping commands. The
- * primary difference between this and the unset option is that the
- * negotiation message is no longer attached to a specific command,
- * instead it is its own command and is merely triggered by a
- * combination of both A) We need to negotiate and B) The mid level
- * SCSI code has sent us a command. We still don't do any negotiation
- * unless there is a valid SCSI command to be processed.
- * Pros: This fixes the problem above in the Cons section. Since we
- * issue our own fake command, we can set the LUN to 0 regardless
- * of what the LUN is in the real command. It also means that if
- * the device get's nasty over negotiation issues, it won't be
- * showing up on a regular command, so we won't get any SENSE buffer
- * data or STATUS_BYTE returns to the mid level code that are caused
- * by snits in the negotiation code.
- * Cons: We add more code, and more complexity. This means more ways
- * in which things could break. It means a larger driver. It means
- * more resource consumption for the fake commands. However, the
- * biggest problem is this. Take a system where there is a CD-ROM
- * on the SCSI bus. Someone has a CD in the CD-ROM and is using it.
- * For some reason the SCSI bus gets reset. We don't touch the
- * CD-ROM again for quite a period of time (so we don't renegotiate
- * after the reset until we do touch the CD-ROM again). In the
- * time while we aren't using the CD-ROM, the current disc is
- * removed and a new one put in. When we go to check that disc, we
- * will first have to renegotiate. In so doing, we issue our fake
- * SCSI command, which happens to be TEST_UNIT_READY. The CD-ROM
- * negotiates with us, then responds to our fake command with a
- * CHECK_CONDITION status. We REQUEST_SENSE from the CD-ROM, it
- * then sends the SENSE data to our fake command to tell it that
- * it has been through a disc change. There, now we've cleared out
- * the SENSE data along with our negotiation command, and when the
- * real command executes, it won't pick up that the CD was changed.
- * That's the biggest Con to this approach. In the future, I could
- * probably code around this problem though, so this option is still
- * viable.
- *
- * So, which command style should you use? I would appreciate it if people
- * could try out both types. I want to know about any cases where one
- * method works and the other doesn't. If one method works on significantly
- * more systems than another, then it will become the default. If the second
- * option turns out to work best, then I'll find a way to work around that
- * big con I listed.
- *
- * -- July 7, 02:33
- * OK...I just added some code that should make the Con listed for the
- * fake commands a non issue now. However, it needs testing. For now,
- * I'm going to make the default to use the fake commands, we'll see how
- * it goes.
- */
-
-#define AIC7XXX_FAKE_NEGOTIATION_CMDS
-
/*
* AIC7XXX_STRICT_PCI_SETUP
* Should we assume the PCI config options on our controllers are set with
#include "aic7xxx/sequencer.h"
#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
+#include <scsi/scsicam.h>
#include <linux/stat.h>
#include <linux/malloc.h> /* for kmalloc() */
0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "5.1.10"
+#define AIC7XXX_C_VERSION "5.1.17"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
*/
-#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
-#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
#else
-#define AIC7XXX_CMDS_PER_LUN 24
+#define AIC7XXX_CMDS_PER_DEVICE 8
#endif
/* Set this to the delay in seconds after SCSI bus reset. */
*
* *** Determining commands per LUN ***
*
- * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
* own algorithm to determine the commands/LUN. If SCB paging is
* enabled, which is always now, the default is 8 commands per lun
* that indicates it supports tagged queueing. All non-tagged devices
* Make a define that will tell the driver not to use tagged queueing
* by default.
*/
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+ 0, 0, 0, 0, 0, 0, 0, 0}
+#else
#define DEFAULT_TAG_COMMANDS {255, 255, 255, 255, 255, 255, 255, 255,\
255, 255, 255, 255, 255, 255, 255, 255}
+#endif
/*
* Modify this as you see fit for your system. By setting tag_commands
};
*/
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS},
+ {DEFAULT_TAG_COMMANDS}
+};
+
+
/*
* Define an array of board names that can be indexed by aha_type.
* Don't forget to change this when changing the types!
"Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */
"Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */
"Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */
+ "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */
"Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */
"Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */
"Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */
"Adaptec PCMCIA SCSI controller", /* card bus stuff */
+ "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */
+ "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */
};
/*
SCB_DEVICE_RESET = 0x0020,
SCB_RESET = 0x0040,
SCB_RECOVERY_SCB = 0x0080,
- SCB_WAS_BUSY = 0x0100,
+ SCB_MSGOUT_PPR = 0x0100,
SCB_MSGOUT_SENT = 0x0200,
SCB_MSGOUT_SDTR = 0x0400,
SCB_MSGOUT_WDTR = 0x0800,
- SCB_MSGOUT_BITS = SCB_MSGOUT_SENT |
+ SCB_MSGOUT_BITS = SCB_MSGOUT_PPR |
+ SCB_MSGOUT_SENT |
SCB_MSGOUT_SDTR |
SCB_MSGOUT_WDTR,
SCB_QUEUED_ABORT = 0x1000,
- SCB_QUEUED_FOR_DONE = 0x2000
+ SCB_QUEUED_FOR_DONE = 0x2000,
+ SCB_WAS_BUSY = 0x4000
} scb_flag_type;
typedef enum {
AHC_AIC7890 = 0x0006,
AHC_AIC7895 = 0x0007,
AHC_AIC7896 = 0x0008,
+ AHC_AIC7892 = 0x0009,
+ AHC_AIC7899 = 0x000a,
AHC_VL = 0x0100,
AHC_EISA = 0x0200,
AHC_PCI = 0x0400,
AHC_QUEUE_REGS = 0x0040,
AHC_SG_PRELOAD = 0x0080,
AHC_SPIOCAP = 0x0100,
+ AHC_ULTRA3 = 0x0200,
AHC_AIC7770_FE = AHC_FENONE,
AHC_AIC7850_FE = AHC_SPIOCAP,
AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP,
AHC_QUEUE_REGS|AHC_SG_PRELOAD,
AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
AHC_AIC7896_FE = AHC_AIC7890_FE,
+ AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3,
+ AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3,
} ahc_feature;
struct aic7xxx_scb {
unsigned char goal_period;
unsigned char cur_offset;
unsigned char goal_offset;
+ unsigned char cur_options;
+ unsigned char goal_options;
unsigned char user_width;
unsigned char user_period;
unsigned char user_offset;
+ unsigned char user_options;
} transinfo_type;
/*
unsigned long isr_count; /* Interrupt count */
unsigned long spurious_int;
scb_data_type *scb_data;
+ volatile unsigned short needdv;
+ volatile unsigned short needppr;
volatile unsigned short needsdtr;
- volatile unsigned short sdtr_pending;
volatile unsigned short needwdtr;
- volatile unsigned short wdtr_pending;
+ volatile unsigned short dtr_pending;
struct aic7xxx_cmd_queue {
Scsi_Cmnd *head;
Scsi_Cmnd *tail;
#define DEVICE_PRESENT 0x01
#define BUS_DEVICE_RESET_PENDING 0x02
#define DEVICE_RESET_DELAY 0x04
-#define DEVICE_PRINT_SDTR 0x08
-#define DEVICE_PRINT_WDTR 0x10
+#define DEVICE_PRINT_DTR 0x08
+#define DEVICE_PARITY_ERROR 0x10
#define DEVICE_WAS_BUSY 0x20
+#define DEVICE_SCSI_3 0x40
#define DEVICE_SCANNED 0x80
volatile unsigned char dev_flags[MAX_TARGETS];
volatile unsigned char dev_active_cmds[MAX_TARGETS];
#endif
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
- Scsi_Cmnd *dev_wdtr_cmnd[MAX_TARGETS];
- Scsi_Cmnd *dev_sdtr_cmnd[MAX_TARGETS];
-#endif
+ Scsi_Cmnd *dev_dtr_cmnd[MAX_TARGETS];
+ unsigned int dev_checksum[MAX_TARGETS];
+
unsigned char dev_last_queue_full[MAX_TARGETS];
unsigned char dev_last_queue_full_count[MAX_TARGETS];
unsigned char dev_max_queue_depth[MAX_TARGETS];
volatile scb_queue_type delayed_scbs[MAX_TARGETS];
- unsigned char msg_buf[9]; /* The message for the target */
+ unsigned char msg_buf[13]; /* The message for the target */
unsigned char msg_type;
#define MSG_TYPE_NONE 0x00
#define MSG_TYPE_INITIATOR_MSGOUT 0x01
int scsi_id_b; /* channel B for twin adapters */
unsigned int bios_address;
int board_name_index;
+ unsigned short needppr_copy; /* default config */
unsigned short needsdtr_copy; /* default config */
unsigned short needwdtr_copy; /* default config */
unsigned short ultraenb; /* Ultra mode target list */
* Provides a mapping of transfer periods in ns/4 to the proper value to
* stick in the SCSIRATE reg to use that transfer rate.
*/
-#define AHC_SYNCRATE_ULTRA2 0
-#define AHC_SYNCRATE_ULTRA 2
-#define AHC_SYNCRATE_FAST 5
+#define AHC_SYNCRATE_ULTRA3 0
+#define AHC_SYNCRATE_ULTRA2 1
+#define AHC_SYNCRATE_ULTRA 3
+#define AHC_SYNCRATE_FAST 6
+#define AHC_SYNCRATE_CRC 0x40
+#define AHC_SYNCRATE_SE 0x10
static struct aic7xxx_syncrate {
/* Rates in Ultra mode have bit 8 of sxfr set */
#define ULTRA_SXFR 0x100
unsigned char period;
const char *rate[2];
} aic7xxx_syncrates[] = {
+ { 0x42, 0x000, 9, {"80.0", "160.0"} },
{ 0x13, 0x000, 10, {"40.0", "80.0"} },
{ 0x14, 0x000, 11, {"33.0", "66.6"} },
{ 0x15, 0x100, 12, {"20.0", "40.0"} },
#endif
-/*
- * See the comments earlier in the file for what this item is all about
- * If you have more than 4 controllers, you will need to increase the
- * the number of items in the array below. Additionally, if you don't
- * want to have lilo pass a humongous config line to the aic7xxx driver,
- * then you can get in and manually adjust these instead of leaving them
- * at the default. Pay attention to the comments earlier in this file
- * concerning this array if you are going to hand modify these values.
- */
-static adapter_tag_info_t aic7xxx_tag_info[] =
-{
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS},
- {DEFAULT_TAG_COMMANDS}
-};
-
#define VERBOSE_NORMAL 0x0000
#define VERBOSE_NEGOTIATION 0x0001
#define VERBOSE_SEQINT 0x0002
aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+ udelay(15);
break;
default:
*-F*************************************************************************/
static struct aic7xxx_syncrate *
aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
- unsigned int maxsync)
+ unsigned int maxsync, unsigned char *options)
{
struct aic7xxx_syncrate *syncrate;
+ int done = FALSE;
+ switch(*options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_CRC:
+ case MSG_EXT_PPR_OPTION_DT_UNITS:
+ if(!(p->features & AHC_ULTRA3))
+ {
+ *options = 0;
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ }
+ break;
+ case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+ case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+ if(!(p->features & AHC_ULTRA3))
+ {
+ *options = 0;
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ }
+ else
+ {
+ /*
+ * we don't support the Quick Arbitration variants of dual edge
+ * clocking. As it turns out, we want to send back the
+ * same basic option, but without the QA attribute.
+ * We know that we are responding because we would never set
+ * these options ourself, we would only respond to them.
+ */
+ switch(*options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+ *options = MSG_EXT_PPR_OPTION_DT_CRC;
+ break;
+ case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+ *options = MSG_EXT_PPR_OPTION_DT_UNITS;
+ break;
+ }
+ }
+ break;
+ default:
+ *options = 0;
+ maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+ break;
+ }
syncrate = &aic7xxx_syncrates[maxsync];
while ( (syncrate->rate[0] != NULL) &&
(!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
{
- if ( *period <= syncrate->period )
+ if (*period <= syncrate->period)
{
- /*
- * When responding to a target that requests sync, the requested rate
- * may fall between two rates that we can output, but still be a rate
- * that we can receive. Because of this, we want to respond with the
- * same rate that it sent to us even if the persiod we use to send
- * data to it is lower. Only lower the response period if we must.
- */
- if(syncrate == &aic7xxx_syncrates[maxsync])
+ switch(*options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_CRC:
+ case MSG_EXT_PPR_OPTION_DT_UNITS:
+ if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+ {
+ done = TRUE;
+ /*
+ * oops, we went too low for the CRC/DualEdge signalling, so
+ * clear the options byte
+ */
+ *options = 0;
+ /*
+ * We'll be sending a reply to this packet to set the options
+ * properly, so unilaterally set the period as well.
+ */
+ *period = syncrate->period;
+ }
+ else
+ {
+ done = TRUE;
+ if(syncrate == &aic7xxx_syncrates[maxsync])
+ {
+ *period = syncrate->period;
+ }
+ }
+ break;
+ default:
+ if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+ {
+ done = TRUE;
+ if(syncrate == &aic7xxx_syncrates[maxsync])
+ {
+ *period = syncrate->period;
+ }
+ }
+ break;
+ }
+ if(done)
{
- *period = syncrate->period;
+ break;
}
- break;
}
syncrate++;
}
/*
* Use async transfers for this target
*/
+ *options = 0;
*period = 0;
syncrate = NULL;
}
{
struct aic7xxx_syncrate *syncrate;
- if ((p->features & AHC_ULTRA2) != 0)
+ if (p->features & AHC_ULTRA2)
{
scsirate &= SXFR_ULTRA2;
}
syncrate = &aic7xxx_syncrates[maxsync];
while (syncrate->rate[0] != NULL)
{
- if ((p->features & AHC_ULTRA2) != 0)
+ if (p->features & AHC_ULTRA2)
{
if (syncrate->sxfr_ultra2 == 0)
break;
else if (scsirate == syncrate->sxfr_ultra2)
return (syncrate->period);
+ else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC))
+ return (syncrate->period);
}
else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
{
static void
aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
int target, int channel, unsigned int period, unsigned int offset,
- unsigned int type)
+ unsigned char options, unsigned int type)
{
unsigned char tindex;
unsigned short target_mask;
- unsigned char lun;
+ unsigned char lun, old_options;
unsigned int old_period, old_offset;
tindex = target | (channel << 3);
old_period = p->transinfo[tindex].cur_period;
old_offset = p->transinfo[tindex].cur_offset;
+ old_options = p->transinfo[tindex].cur_options;
if (type & AHC_TRANS_CUR)
scsirate &= ~SXFR_ULTRA2;
if (syncrate != NULL)
{
- scsirate |= syncrate->sxfr_ultra2;
+ switch(options)
+ {
+ case MSG_EXT_PPR_OPTION_DT_UNITS:
+ /*
+ * mask off the CRC bit in the xfer settings
+ */
+ scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC);
+ break;
+ default:
+ scsirate |= syncrate->sxfr_ultra2;
+ break;
+ }
}
if (type & AHC_TRANS_ACTIVE)
{
aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
p->transinfo[tindex].cur_period = period;
p->transinfo[tindex].cur_offset = offset;
+ p->transinfo[tindex].cur_options = options;
if ( !(type & AHC_TRANS_QUITE) &&
(aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
if (offset)
{
printk(INFO_LEAD "Using asynchronous transfers.\n",
p->host_no, channel, target, lun);
}
- p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
}
}
{
p->transinfo[tindex].goal_period = period;
p->transinfo[tindex].goal_offset = offset;
+ p->transinfo[tindex].goal_options = options;
}
if (type & AHC_TRANS_USER)
{
p->transinfo[tindex].user_period = period;
p->transinfo[tindex].user_offset = offset;
+ p->transinfo[tindex].user_options = options;
}
}
{
unsigned char tindex;
unsigned short target_mask;
- unsigned int old_width, new_offset;
+ unsigned int old_width;
tindex = target | (channel << 3);
target_mask = 1 << tindex;
old_width = p->transinfo[tindex].cur_width;
- if (p->features & AHC_ULTRA2)
- new_offset = MAX_OFFSET_ULTRA2;
- else if (width == MSG_EXT_WDTR_BUS_16_BIT)
- new_offset = MAX_OFFSET_16BIT;
- else
- new_offset = MAX_OFFSET_8BIT;
-
if (type & AHC_TRANS_CUR)
{
unsigned char scsirate;
p->transinfo[tindex].cur_width = width;
- if ((aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_WDTR))
+ if ( !(type & AHC_TRANS_QUITE) &&
+ (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
- p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
}
}
if (type & AHC_TRANS_USER)
p->transinfo[tindex].user_width = width;
- /*
- * Having just set the width, the SDTR should come next, and we need a valid
- * offset for the SDTR. So, we make sure we put a valid one in here now as
- * the goal_offset.
- */
if (p->transinfo[tindex].goal_offset)
- p->transinfo[tindex].goal_offset = new_offset;
-
+ {
+ if (p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else if (width == MSG_EXT_WDTR_BUS_16_BIT)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
+ }
}
/*+F*************************************************************************
if (match != 0)
match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
- if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
- {
- printk(KERN_INFO "(scsi%d:%d:%d:%d:tag%d) %s search criteria"
- " (scsi%d:%d:%d:%d:tag%d)\n", p->host_no, CTL_OF_SCB(scb),
- scb->hscb->tag, (match) ? "matches" : "doesn't match",
- p->host_no, channel, target, lun, tag);
- }
-
return (match);
}
* to the free list.
*-F*************************************************************************/
static unsigned char
-aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr,
+ unsigned char prev)
{
unsigned char next;
- unsigned char prev;
aic_outb(p, scbptr, SCBPTR);
next = aic_inb(p, SCB_NEXT);
- prev = aic_inb(p, SCB_PREV);
aic7xxx_add_curscb_to_free_list(p);
if (prev != SCB_LIST_NULL)
aic_outb(p, next, DISCONNECTED_SCBH);
}
- if (next != SCB_LIST_NULL)
- {
- aic_outb(p, next, SCBPTR);
- aic_outb(p, prev, SCB_PREV);
- }
return next;
}
* Place in the scb array; never is removed
*/
p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
- scbq_insert_head(&p->scb_data->free_scbs, scbp);
+ scbq_insert_tail(&p->scb_data->free_scbs, scbp);
}
scbp->kmalloc_ptr = scb_ap;
}
Scsi_Cmnd *cmd;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
unsigned int cpu_flags = 0;
+#endif
DRIVER_LOCK
while (p->completeq.head != NULL)
cmd = p->completeq.head;
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
cmd->host_scribble = NULL;
- sti();
cmd->scsi_done(cmd);
- cli();
}
DRIVER_UNLOCK
-#else
- while (p->completeq.head != NULL)
- {
- cmd = p->completeq.head;
- p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
- cmd->host_scribble = NULL;
- cmd->scsi_done(cmd);
- }
-#endif
}
/*+F*************************************************************************
}
#define WIDE_INQUIRY_BITS 0x60
#define SYNC_INQUIRY_BITS 0x10
+#define SCSI_VERSION_BITS 0x07
if ( (buffer[7] & WIDE_INQUIRY_BITS) &&
(p->features & AHC_WIDE) )
{
p->needwdtr |= (1<<tindex);
p->needwdtr_copy |= (1<<tindex);
- if ( (p->flags & AHC_SEEPROM_FOUND) &&
- (p->transinfo[tindex].user_width != MSG_EXT_WDTR_BUS_16_BIT) )
- p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
- else
- p->transinfo[tindex].goal_width = MSG_EXT_WDTR_BUS_16_BIT;
+ p->transinfo[tindex].goal_width = p->transinfo[tindex].user_width;
}
else
{
p->needsdtr |= (1<<tindex);
p->needsdtr_copy |= (1<<tindex);
- if (p->flags & AHC_SEEPROM_FOUND)
+ p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
+ p->transinfo[tindex].goal_options = p->transinfo[tindex].user_options;
+ if (p->transinfo[tindex].user_offset)
{
- p->transinfo[tindex].goal_period = p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_offset = p->transinfo[tindex].user_offset;
- }
- else
- {
- if (p->features & AHC_ULTRA2)
- {
- p->transinfo[tindex].goal_period =
- aic7xxx_syncrates[AHC_SYNCRATE_ULTRA2].period;
- }
- else if (p->features & AHC_ULTRA)
- {
- p->transinfo[tindex].goal_period =
- aic7xxx_syncrates[AHC_SYNCRATE_ULTRA].period;
- }
- else
- {
- p->transinfo[tindex].goal_period =
- aic7xxx_syncrates[AHC_SYNCRATE_FAST].period;
- }
if (p->features & AHC_ULTRA2)
p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
else if (p->transinfo[tindex].goal_width == MSG_EXT_WDTR_BUS_16_BIT)
p->needsdtr_copy &= ~(1<<tindex);
p->transinfo[tindex].goal_period = 0;
p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ if ( (buffer[2] & SCSI_VERSION_BITS) == 3 )
+ {
+ p->dev_flags[tindex] |= DEVICE_SCSI_3;
+ /*
+ * OK, we are a SCSI 3 device and we are in need of negotiation.
+ * Use PPR messages instead of WDTR and SDTR messages.
+ */
+ if ( (p->needsdtr & (1<<tindex)) ||
+ (p->needwdtr & (1<<tindex)) )
+ {
+ p->needppr |= (1<<tindex);
+ p->needppr_copy |= (1<<tindex);
+ }
+ p->needwdtr &= ~(1<<tindex);
+ p->needwdtr_copy &= ~(1<<tindex);
+ p->needsdtr &= ~(1<<tindex);
+ p->needsdtr_copy &= ~(1<<tindex);
+ }
+ /*
+ * Get the INQUIRY checksum. We use this on Ultra 160/m
+ * and older devices both. It allows us to drop speed on any bus type
+ * while at the same time giving us the needed domain validation for
+ * Ultra 160/m
+ *
+ * Note: We only get the checksum and set the SCANNED bit if this is
+ * one of our dtr commands. If we don't do this, then we end up
+ * getting bad checksum results on the mid-level SCSI code's INQUIRY
+ * commands.
+ */
+ if(p->dev_dtr_cmnd[tindex] == cmd) {
+ unsigned int checksum = 0;
+ int *ibuffer;
+ int i=0;
+
+ ibuffer = (int *)buffer;
+ for( i = 0; i < (cmd->request_bufflen >> 2); i++)
+ {
+ checksum += ibuffer[i];
+ }
+ p->dev_checksum[tindex] = checksum;
+ p->dev_flags[tindex] |= DEVICE_SCANNED;
+ p->dev_flags[tindex] |= DEVICE_PRINT_DTR;
}
- p->dev_flags[tindex] |= DEVICE_SCANNED;
- p->dev_flags[tindex] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR;
#undef WIDE_INQUIRY_BITS
#undef SYNC_INQUIRY_BITS
+#undef SCSI_VERSION_BITS
}
}
- else if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+ else if ((scb->flags & SCB_MSGOUT_BITS) != 0)
{
unsigned short mask;
int message_error = FALSE;
if (scb->flags & SCB_MSGOUT_WDTR)
{
- p->wdtr_pending &= ~mask;
+ p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_WDTR) )
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
printk(INFO_LEAD "Device failed to complete Wide Negotiation "
"processing and\n", p->host_no, CTL_OF_SCB(scb));
"disabling future\n", p->host_no, CTL_OF_SCB(scb));
printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
CTL_OF_SCB(scb));
- p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
}
p->needwdtr &= ~mask;
p->needwdtr_copy &= ~mask;
}
if (scb->flags & SCB_MSGOUT_SDTR)
{
- p->sdtr_pending &= ~mask;
+ p->dtr_pending &= ~mask;
if (message_error)
{
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- (p->dev_flags[tindex] & DEVICE_PRINT_SDTR) )
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
{
printk(INFO_LEAD "Device failed to complete Sync Negotiation "
"processing and\n", p->host_no, CTL_OF_SCB(scb));
"disabling future\n", p->host_no, CTL_OF_SCB(scb));
printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
CTL_OF_SCB(scb));
- p->dev_flags[tindex] &= ~DEVICE_PRINT_SDTR;
+ p->dev_flags[tindex] &= ~DEVICE_PRINT_DTR;
}
p->needsdtr &= ~mask;
p->needsdtr_copy &= ~mask;
}
}
+ if (scb->flags & SCB_MSGOUT_PPR)
+ {
+ p->dtr_pending &= ~mask;
+ if(message_error)
+ {
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ (p->dev_flags[tindex] & DEVICE_PRINT_DTR) )
+ {
+ printk(INFO_LEAD "Device failed to complete Parallel Protocol "
+ "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "returned a sense error code for invalid message, "
+ "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
+ "device.\n", p->host_no, CTL_OF_SCB(scb));
+ }
+ /*
+ * Disable PPR negotiation and revert back to WDTR and SDTR setup
+ */
+ p->needppr &= ~mask;
+ p->needppr_copy &= ~mask;
+ p->needsdtr |= mask;
+ p->needsdtr_copy |= mask;
+ p->needwdtr |= mask;
+ p->needwdtr_copy |= mask;
+ }
+ }
}
queue_depth = p->dev_temp_queue_depth[tindex];
if (queue_depth >= p->dev_active_cmds[tindex])
p->dev_active_cmds[tindex]--;
p->activescbs--;
- /*
- * If this was an untagged I/O, unbusy the target so the sequencer won't
- * mistake things later
- */
- if (aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, FALSE) ==
- scb->hscb->tag)
- {
- aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, TRUE);
- }
-
{
int actual;
#endif /* AIC7XXX_PROC_STATS */
}
#ifdef AIC7XXX_PROC_STATS
- x = -10;
+ x = -11;
while(actual)
{
actual >>= 1;
if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
printk(INFO_LEAD "Cleaning up status information "
"and delayed_scbs.\n", p->host_no, channel, i, lun);
- p->dev_flags[i] &= ~BUS_DEVICE_RESET_PENDING;
+ p->dev_flags[i] &= ~(BUS_DEVICE_RESET_PENDING | DEVICE_PARITY_ERROR);
if ( tag == SCB_LIST_NULL )
{
- p->dev_flags[i] |= DEVICE_PRINT_WDTR | DEVICE_PRINT_SDTR |
- DEVICE_RESET_DELAY;
+ p->dev_flags[i] |= DEVICE_PRINT_DTR | DEVICE_RESET_DELAY;
p->dev_expires[i] = jiffies + (4 * HZ);
p->dev_timer_active |= (0x01 << i);
p->dev_last_queue_full_count[i] = 0;
if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
printk(INFO_LEAD "Cleaning disconnected scbs "
"list.\n", p->host_no, channel, target, lun);
- if (p->features & AHC_PAGESCBS)
+ if (p->flags & AHC_PAGESCBS)
{
unsigned char next, prev, scb_index;
printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
"numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
p->scb_data->numscbs);
- next = aic7xxx_rem_scb_from_disc_list(p, next);
+ next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
}
else
{
scbp = p->scb_data->scb_array[scb_index];
if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
{
- next = aic7xxx_rem_scb_from_disc_list(p, next);
+ next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
if (scbp->flags & SCB_WAITINGQ)
{
p->dev_active_cmds[TARGET_INDEX(scbp->cmd)]++;
* Walk the free list making sure no entries on the free list have
* a valid SCB_TAG value or SCB_CONTROL byte.
*/
- if (p->features & AHC_PAGESCBS)
+ if (p->flags & AHC_PAGESCBS)
{
unsigned char next;
{
aic_outb(p, SCB_LIST_NULL, SCB_TAG);
aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
- aic_outb(p, SCB_LIST_NULL, SCB_PREV);
aic_outb(p, 0, SCB_CONTROL);
aic7xxx_add_curscb_to_free_list(p);
}
if (channel == 1)
{
p->needsdtr |= (p->needsdtr_copy & 0xFF00);
- p->sdtr_pending &= 0x00FF;
+ p->dtr_pending &= 0x00FF;
offset_min = 8;
offset_max = 16;
}
else
{
- if (p->features & AHC_WIDE)
+ if (p->features & AHC_TWIN)
{
- p->needsdtr = p->needsdtr_copy;
- p->needwdtr = p->needwdtr_copy;
- p->sdtr_pending = 0x0;
- p->wdtr_pending = 0x0;
+ /* Channel A */
+ p->needsdtr |= (p->needsdtr_copy & 0x00FF);
+ p->dtr_pending &= 0xFF00;
offset_min = 0;
- offset_max = 16;
+ offset_max = 8;
}
else
{
- /* Channel A */
- p->needsdtr |= (p->needsdtr_copy & 0x00FF);
- p->sdtr_pending &= 0xFF00;
+ p->needppr = p->needppr_copy;
+ p->needsdtr = p->needsdtr_copy;
+ p->needwdtr = p->needwdtr_copy;
+ p->dtr_pending = 0x0;
offset_min = 0;
- offset_max = 8;
+ if (p->features & AHC_WIDE)
+ {
+ offset_max = 16;
+ }
+ else
+ {
+ offset_max = 8;
+ }
}
}
#endif
}
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_construct_ppr
+ *
+ * Description:
+ * Build up a Parallel Protocol Request message for use with SCSI-3
+ * devices.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+ int tindex = TARGET_INDEX(scb->cmd);
+
+ p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+ p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
+ p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_period;
+ p->msg_buf[p->msg_index++] = 0;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_offset;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_width;
+ p->msg_buf[p->msg_index++] = p->transinfo[tindex].goal_options;
+ p->msg_len += 8;
+}
+
/*+F*************************************************************************
* Function:
* aic7xxx_construct_sdtr
/*
* Go back to async/narrow transfers and renegotiate.
*/
+ p->needppr |= (p->needppr_copy & targ_mask);
p->needsdtr |= (p->needsdtr_copy & targ_mask);
p->needwdtr |= (p->needwdtr_copy & targ_mask);
- p->sdtr_pending &= ~targ_mask;
- p->wdtr_pending &= ~targ_mask;
+ p->dtr_pending &= ~targ_mask;
aic_outb(p, 0, TARG_SCSIRATE + tindex);
if (p->features & AHC_ULTRA2)
aic_outb(p, 0, TARG_OFFSET + tindex);
if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
target, -1);
- aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
}
/*+F*************************************************************************
p->host_no, channel, target, lun,
aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
(aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+ if (aic7xxx_panic_on_abort)
+ aic7xxx_panic_abort(p, NULL);
}
break;
lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
}
break;
aic7xxx_reset_device(p, target, channel, lun, i);
reset++;
}
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
}
}
aic7xxx_verbose = old_verbose;
aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
}
}
+ else if (scb->flags & SCB_MSGOUT_PPR)
+ {
+ /*
+ * As per the draft specs, any device capable of supporting any of
+ * the option values other than 0 are not allowed to reject the
+ * PPR message. Instead, they must negotiate out what they do
+ * support instead of rejecting our offering.
+ */
+ p->needppr &= ~target_mask;
+ p->needppr_copy &= ~target_mask;
+ aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+ (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE));
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
+ p->transinfo[tindex].goal_options = 0;
+ p->dtr_pending &= ~target_mask;
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Device is rejecting PPR messages, falling "
+ "back.\n", p->host_no, channel, target, lun);
+ }
+ if ( p->transinfo[tindex].goal_width )
+ {
+ p->needwdtr |= target_mask;
+ p->needwdtr_copy |= target_mask;
+ p->dtr_pending |= target_mask;
+ scb->flags |= SCB_MSGOUT_WDTR;
+ }
+ if ( p->transinfo[tindex].goal_offset )
+ {
+ p->needsdtr |= target_mask;
+ p->needsdtr_copy |= target_mask;
+ if( !(p->dtr_pending & target_mask) )
+ {
+ p->dtr_pending |= target_mask;
+ scb->flags |= SCB_MSGOUT_SDTR;
+ }
+ }
+ if ( p->dtr_pending & target_mask )
+ {
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+ }
+ }
else if (scb->flags & SCB_MSGOUT_WDTR)
{
/*
*/
p->needwdtr &= ~target_mask;
p->needwdtr_copy &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
+ p->dtr_pending &= ~target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
(AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR));
- aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
- if ( (p->needsdtr_copy & target_mask) &&
- !(p->sdtr_pending & target_mask) )
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
- p->sdtr_pending |= target_mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- aic_outb(p, HOST_MSG, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ printk(INFO_LEAD "Device is rejecting WDTR messages, using "
+ "narrow transfers.\n", p->host_no, channel, target, lun);
}
+ p->needsdtr |= (p->needsdtr_copy & target_mask);
}
else if (scb->flags & SCB_MSGOUT_SDTR)
{
*/
p->needsdtr &= ~target_mask;
p->needsdtr_copy &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
+ p->dtr_pending &= ~target_mask;
scb->flags &= ~SCB_MSGOUT_SDTR;
- aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
(AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL));
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Device is rejecting SDTR messages, using "
+ "async transfers.\n", p->host_no, channel, target, lun);
+ }
}
else if (aic7xxx_verbose & VERBOSE_SEQINT)
{
* However, if this SCB already was attempting to negotiate,
* then we assume this isn't the problem and skip this part.
*/
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
(p->dev_flags[tindex] & DEVICE_SCANNED) &&
- !(p->wdtr_pending & target_mask) &&
- !(p->sdtr_pending & target_mask) )
+ !(p->dtr_pending & target_mask) )
{
+ p->needppr |= (p->needppr_copy & target_mask);
p->needwdtr |= (p->needwdtr_copy & target_mask);
p->needsdtr |= (p->needsdtr_copy & target_mask);
}
- else if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) ||
- (scb->cmd == p->dev_sdtr_cmnd[tindex]) )
+ else if ( scb->cmd == p->dev_dtr_cmnd[tindex] )
{
/*
* This is already a negotiation command, so we must have
- * already done either WDTR or SDTR (or maybe both). So
- * we simply check sdtr_pending and needsdtr to see if we
- * should throw out SDTR on this command.
- *
- * Note: Don't check the needsdtr_copy here, instead just
- * check to see if WDTR wiped out our SDTR and set needsdtr.
- * Even if WDTR did wipe out SDTR and set needsdtr, if
- * parse_msg() then turned around and started our SDTR
- * in back to back fasion, then conclusion of that should
- * have negated any needsdtr setting. That's why we only
- * check needsdtr and sdtr_pending.
+ * already done PPR, WDTR or SDTR. Since our negotiation
+ * could have gotten rejected, we don't really know the
+ * full state of things. Don't do anything here, and allow
+ * the negotiation_complete() handler to do the right
+ * thing.
*/
- scb->flags &= ~SCB_MSGOUT_BITS;
- if ( (scb->cmd == p->dev_wdtr_cmnd[tindex]) &&
- !(p->sdtr_pending & target_mask) &&
- (p->needsdtr & target_mask) )
- {
- p->sdtr_pending |= target_mask;
- hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_SDTR;
- }
/*
* This is the important part though. We are getting sense
hscb->data_pointer = scb->sg_list[0].address;
}
}
-#else
- if ( (scb->cmd->cmnd[0] != TEST_UNIT_READY) &&
- !(scb->flags & SCB_MSGOUT_BITS) &&
- (scb->cmd->lun == 0) &&
- (p->dev_flags[TARGET_INDEX(scb->cmd)] & DEVICE_SCANNED) )
- {
- if ( (p->needwdtr_copy & target_mask) &&
- !(p->wdtr_pending & target_mask) &&
- !(p->sdtr_pending & target_mask) )
- {
- p->needwdtr |= target_mask;
- p->wdtr_pending |= target_mask;
- hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_WDTR;
- }
- if ( p->needsdtr_copy & target_mask )
- {
- p->needsdtr |= target_mask;
- if ( !(p->wdtr_pending & target_mask) &&
- !(p->sdtr_pending & target_mask) )
- {
- p->sdtr_pending |= target_mask;
- hscb->control |= MK_MESSAGE;
- scb->flags |= SCB_MSGOUT_SDTR;
- }
- }
- }
- else
- scb->flags &= ~SCB_MSGOUT_BITS;
-#endif /* AIC7XXX_FAKE_NEGOTIATION_CMDS */
scb->flags |= SCB_SENSE;
/*
* Ensure the target is busy since this will be an
* an untagged request.
*/
#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
{
if (scb->flags & SCB_MSGOUT_BITS)
printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
}
}
#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+ if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
+ (aic7xxx_verbose > 0xffff) )
{
if (queue_flag)
printk(INFO_LEAD "Queue full received; queue depth %d, "
#endif
if (queue_flag)
{
- p->dev_temp_queue_depth[tindex] =
- p->dev_active_cmds[tindex];
if ( p->dev_last_queue_full[tindex] !=
p->dev_active_cmds[tindex] )
{
p->dev_active_cmds[tindex];
p->dev_last_queue_full[tindex] = 0;
p->dev_last_queue_full_count[tindex] = 0;
+ p->dev_temp_queue_depth[tindex] =
+ p->dev_active_cmds[tindex];
}
- else
+ else if (p->dev_active_cmds[tindex] == 0)
{
- p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
- }
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ {
+ printk(INFO_LEAD "QUEUE_FULL status received with 0 "
+ "commands active.\n", p->host_no, CTL_OF_SCB(scb));
+ printk(INFO_LEAD "Tagged Command Queueing disabled\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ p->dev_max_queue_depth[tindex] = 1;
+ p->dev_temp_queue_depth[tindex] = 1;
+ scb->tag_action = 0;
+ scb->hscb->control &= ~(MSG_ORDERED_Q_TAG|MSG_SIMPLE_Q_TAG);
+ }
+ else
+ {
+ p->dev_flags[tindex] |= DEVICE_WAS_BUSY;
+ p->dev_temp_queue_depth[tindex] =
+ p->dev_active_cmds[tindex];
+ }
}
break;
}
*/
if ( !(scb->flags & SCB_DEVICE_RESET) &&
- (aic_inb(p, MSG_OUT) == MSG_IDENTIFYFLAG) &&
+ (msg_out == MSG_IDENTIFYFLAG) &&
(scb->hscb->control & TAG_ENB) )
{
p->msg_buf[p->msg_index++] = scb->tag_action;
printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
CTL_OF_SCB(scb));
}
+ else if (scb->flags & SCB_MSGOUT_PPR)
+ {
+ unsigned int max_sync, period;
+ unsigned char options = p->transinfo[tindex].goal_options;
+
+ if (p->features & AHC_ULTRA2)
+ {
+ if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+ !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+ {
+ if( (p->features & AHC_ULTRA3) &&
+ (p->dev_flags[tindex] & DEVICE_SCSI_3) &&
+ (p->transinfo[tindex].goal_width ==
+ MSG_EXT_WDTR_BUS_16_BIT) &&
+ (options != 0) )
+ {
+ max_sync = AHC_SYNCRATE_ULTRA3;
+ }
+ else
+ {
+ max_sync = AHC_SYNCRATE_ULTRA2;
+ }
+ }
+ else
+ {
+ max_sync = AHC_SYNCRATE_ULTRA;
+ }
+ }
+ else if (p->features & AHC_ULTRA)
+ {
+ max_sync = AHC_SYNCRATE_ULTRA;
+ }
+ else
+ {
+ max_sync = AHC_SYNCRATE_FAST;
+ }
+ period = p->transinfo[tindex].goal_period;
+ aic7xxx_find_syncrate(p, &period, max_sync, &options);
+ p->transinfo[tindex].goal_period = period;
+ p->transinfo[tindex].goal_options = options;
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
+ p->host_no, CTL_OF_SCB(scb), period,
+ p->transinfo[tindex].goal_offset,
+ p->transinfo[tindex].goal_width, options);
+ }
+ aic7xxx_construct_ppr(p, scb);
+ }
else if (scb->flags & SCB_MSGOUT_WDTR)
{
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
CTL_OF_SCB(scb));
-#endif
- aic7xxx_construct_wdtr(p,
- p->transinfo[TARGET_INDEX(scb->cmd)].goal_width);
+ }
+ aic7xxx_construct_wdtr(p, p->transinfo[tindex].goal_width);
}
else if (scb->flags & SCB_MSGOUT_SDTR)
{
unsigned int max_sync, period;
- /*
- * We need to set an accurate goal_offset instead of
- * the ridiculously high one we default to. We should
- * now know if we are wide. Plus, the WDTR code will
- * set our goal_offset for us as well.
- */
- if (p->transinfo[tindex].goal_offset)
- {
- if (p->features & AHC_ULTRA2)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
- else if (p->transinfo[tindex].cur_width == MSG_EXT_WDTR_BUS_16_BIT)
- p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
- else
- p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
- }
+ unsigned char options = 0;
/*
* Now that the device is selected, use the bits in SBLKCTL and
* SSTAT2 to determine the max sync rate for this device.
max_sync = AHC_SYNCRATE_FAST;
}
period = p->transinfo[tindex].goal_period;
- aic7xxx_find_syncrate(p, &period, max_sync);
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
+ aic7xxx_find_syncrate(p, &period, max_sync, &options);
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
CTL_OF_SCB(scb),
p->transinfo[tindex].goal_period,
p->transinfo[tindex].goal_offset);
-#endif
+ }
aic7xxx_construct_sdtr(p, period,
p->transinfo[tindex].goal_offset);
}
#if AIC7XXX_NOT_YET
case TRACEPOINT:
{
- printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no, channel,
- target, lun);
+ printk(INFO_LEAD "Tracepoint #1 reached.\n", p->host_no,
+ channel, target, lun);
}
break;
case TRACEPOINT2:
{
- printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, channel,
- target, lun);
+ printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+ channel, target, lun);
}
break;
case MSG_EXT_SDTR:
{
unsigned int period, offset;
- unsigned char maxsync, saved_offset;
+ unsigned char maxsync, saved_offset, options;
struct aic7xxx_syncrate *syncrate;
if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
period = p->msg_buf[3];
saved_offset = offset = p->msg_buf[4];
+ options = 0;
+ /*
+ * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+ * using the SDTR messages. We need the PPR messages to enable the
+ * higher speeds that include things like Dual Edge clocking.
+ */
if (p->features & AHC_ULTRA2)
{
if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
{
- if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
+ if (!(p->dev_flags[tindex] & DEVICE_SCANNED) &&
+ !(p->needsdtr_copy & target_mask) &&
+ (p->transinfo[tindex].user_offset) )
{
/*
* Not only is the device starting this up, but it also hasn't
*/
p->transinfo[tindex].goal_period =
p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
+ if(p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else if (p->transinfo[tindex].cur_width)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
p->needsdtr_copy |= target_mask;
}
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Received pre-emptive SDTR message from "
+ "target.\n", p->host_no, CTL_OF_SCB(scb));
+ }
if ( !p->transinfo[tindex].goal_offset )
period = 255;
if ( p->transinfo[tindex].goal_period > period )
period = p->transinfo[tindex].goal_period;
}
- syncrate = aic7xxx_find_syncrate(p, &period, maxsync);
+ syncrate = aic7xxx_find_syncrate(p, &period, maxsync, &options);
aic7xxx_validate_offset(p, syncrate, &offset,
target_scsirate & WIDEXFER);
aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ offset, options, AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
/*
- * Did we drop to async? If so, are we sending a reply? If we are,
+ * Did we drop to async? Or are we sending a reply? If we are,
* then we have to make sure that the reply value reflects the proper
* settings so we need to set the goal values according to what
* we need to send.
*/
- if ( (offset == 0) || (offset != saved_offset) ||
+ if ( (offset != saved_offset) ||
((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
(SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) )
{
- aic7xxx_set_syncrate(p, syncrate, target, channel, period,
- offset, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
- if ( offset == 0 )
- {
- p->needsdtr_copy &= ~target_mask;
- }
+ aic7xxx_set_syncrate(p, syncrate, target, channel, period, offset,
+ options, AHC_TRANS_GOAL|AHC_TRANS_QUITE);
}
/*
* go async, then send an SDTR back to the target
*/
p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ==
- (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) &&
- (offset == saved_offset) )
- {
- scb->flags &= ~SCB_MSGOUT_BITS;
- }
- else
+ p->dtr_pending &= ~target_mask;
+ if ( ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+ (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) ||
+ (offset != saved_offset) )
{
+ reply = TRUE;
+ p->dtr_pending |= target_mask;
scb->flags &= ~SCB_MSGOUT_BITS;
scb->flags |= SCB_MSGOUT_SDTR;
aic_outb(p, HOST_MSG, MSG_OUT);
{
reject = TRUE;
if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
- ((p->dev_flags[tindex] & DEVICE_PRINT_WDTR) ||
+ ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
(aic7xxx_verbose > 0xffff)) )
{
printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
- p->dev_flags[tindex] &= ~DEVICE_PRINT_WDTR;
}
} /* We fall through on purpose */
case MSG_EXT_WDTR_BUS_8_BIT:
break;
}
}
- scb->flags &= ~SCB_MSGOUT_BITS;
- p->wdtr_pending &= ~target_mask;
+ p->dtr_pending &= ~target_mask;
p->needwdtr &= ~target_mask;
}
else
{
- scb->flags &= ~SCB_MSGOUT_BITS;
- scb->flags |= SCB_MSGOUT_WDTR;
- reply = TRUE;
if ( !(p->dev_flags[tindex] & DEVICE_SCANNED) )
{
/*
*/
p->transinfo[tindex].goal_period =
p->transinfo[tindex].user_period;
- p->transinfo[tindex].goal_offset =
- p->transinfo[tindex].user_offset;
+ if(p->transinfo[tindex].user_offset)
+ {
+ if(p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else if( p->transinfo[tindex].user_width &&
+ (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+ p->features & AHC_WIDE )
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
+ }
p->transinfo[tindex].goal_width =
p->transinfo[tindex].user_width;
p->needwdtr_copy |= target_mask;
p->needsdtr_copy |= target_mask;
}
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Received pre-emptive WDTR message from "
+ "target.\n", p->host_no, CTL_OF_SCB(scb));
+ }
switch(bus_width)
{
default:
break;
}
}
+ reply = TRUE;
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ scb->flags |= SCB_MSGOUT_WDTR;
p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
+ p->dtr_pending |= target_mask;
aic_outb(p, HOST_MSG, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
}
* supports SDTR at all. Therefore, we check needsdtr_copy instead
* of needstr.
*/
- aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0,
+ aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE);
- if ( (p->needsdtr_copy & target_mask) &&
- !(p->sdtr_pending & target_mask))
+ p->needsdtr |= (p->needsdtr_copy & target_mask);
+ done = TRUE;
+ break;
+ }
+ case MSG_EXT_PPR:
+ {
+ unsigned char bus_width, trans_options, new_trans_options;
+ unsigned int period, offset;
+ unsigned char maxsync, saved_offset;
+ struct aic7xxx_syncrate *syncrate;
+
+ if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
+ {
+ reject = TRUE;
+ break;
+ }
+
+ /*
+ * If we aren't on one of the new Ultra3 cards, then reject any PPR
+ * message since we can't support any option field other than 0
+ */
+ if( !(p->features & AHC_ULTRA3) )
+ {
+ reject = TRUE;
+ break;
+ }
+
+ if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
+ {
+ break;
+ }
+
+ period = p->msg_buf[3];
+ offset = saved_offset = p->msg_buf[5];
+ bus_width = p->msg_buf[6];
+ trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
+ p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
+ trans_options);
+ }
+
+ if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+ !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+ {
+ if(p->features & AHC_ULTRA3)
+ {
+ maxsync = AHC_SYNCRATE_ULTRA3;
+ }
+ else
+ {
+ maxsync = AHC_SYNCRATE_ULTRA2;
+ }
+ }
+ else
{
- p->needsdtr |= target_mask;
- if ( !reject && !reply )
+ maxsync = AHC_SYNCRATE_ULTRA;
+ }
+ /*
+ * We might have a device that is starting negotiation with us
+ * before we can start up negotiation with it....be prepared to
+ * have a device ask for a higher speed then we want to give it
+ * in that case
+ */
+ if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+ (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
+ {
+ reply = TRUE;
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ scb->flags |= SCB_MSGOUT_PPR;
+ if (!(p->dev_flags[tindex] & DEVICE_SCANNED))
{
- scb->flags &= ~SCB_MSGOUT_WDTR;
- if (p->transinfo[tindex].goal_period)
+ /*
+ * Not only is the device starting this up, but it also hasn't
+ * been scanned yet, so this would likely be our TUR or our
+ * INQUIRY command at scan time, so we need to use the
+ * settings from the SEEPROM if they existed. Of course, even
+ * if we didn't find a SEEPROM, we stuffed default values into
+ * the user settings anyway, so use those in all cases.
+ */
+ p->transinfo[tindex].goal_period =
+ p->transinfo[tindex].user_period;
+ if(p->transinfo[tindex].user_offset)
{
- p->sdtr_pending |= target_mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- aic_outb(p, HOST_MSG, MSG_OUT);
- aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ if(p->features & AHC_ULTRA2)
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_ULTRA2;
+ }
+ else if( p->transinfo[tindex].user_width &&
+ (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+ p->features & AHC_WIDE )
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_16BIT;
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = MAX_OFFSET_8BIT;
+ }
+ }
+ p->transinfo[tindex].goal_width =
+ p->transinfo[tindex].user_width;
+ p->transinfo[tindex].goal_options =
+ p->transinfo[tindex].user_options;
+ p->needppr_copy |= target_mask;
+ }
+ if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+ {
+ printk(INFO_LEAD "Received pre-emptive PPR message from "
+ "target.\n", p->host_no, CTL_OF_SCB(scb));
+ }
+ if ( !p->transinfo[tindex].goal_offset )
+ period = 255;
+ if ( p->transinfo[tindex].goal_period > period )
+ period = p->transinfo[tindex].goal_period;
+ if ( p->transinfo[tindex].goal_options == 0 )
+ new_trans_options = 0;
+ switch(bus_width)
+ {
+ default:
+ {
+ if ( (p->features & AHC_WIDE) &&
+ (p->transinfo[tindex].goal_width ==
+ MSG_EXT_WDTR_BUS_16_BIT) )
+ {
+ bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+ break;
+ }
+ } /* Fall through if we aren't a wide card */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ {
+ p->needwdtr_copy &= ~target_mask;
+ bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ aic7xxx_set_width(p, target, channel, lun, bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ break;
}
}
}
+ else
+ {
+ switch(bus_width)
+ {
+ default:
+ {
+ reply = TRUE;
+ if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+ ((p->dev_flags[tindex] & DEVICE_PRINT_DTR) ||
+ (aic7xxx_verbose > 0xffff)) )
+ {
+ printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+ p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+ }
+ } /* We fall through on purpose */
+ case MSG_EXT_WDTR_BUS_8_BIT:
+ {
+ /*
+ * According to the spec, if we aren't wide, we also can't be
+ * Dual Edge so clear the options byte
+ */
+ new_trans_options = 0;
+ bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+ break;
+ }
+ case MSG_EXT_WDTR_BUS_16_BIT:
+ {
+ break;
+ }
+ }
+ }
+
+ aic7xxx_set_width(p, target, channel, lun, bus_width,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+ syncrate = aic7xxx_find_syncrate(p, &period, maxsync,
+ &new_trans_options);
+ aic7xxx_validate_offset(p, syncrate, &offset, bus_width);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+ offset, new_trans_options,
+ AHC_TRANS_ACTIVE|AHC_TRANS_CUR);
+
+ if( (offset != saved_offset) ||
+ (trans_options != new_trans_options) ||
+ ((scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+ (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) )
+ {
+ aic7xxx_set_width(p, target, channel, lun, bus_width,
+ AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ aic7xxx_set_syncrate(p, syncrate, target, channel, period,
+ offset, new_trans_options,
+ AHC_TRANS_GOAL|AHC_TRANS_QUITE);
+ reply = TRUE;
+ }
+ p->dtr_pending &= ~target_mask;
+ p->needppr &= ~target_mask;
+ if(reply)
+ {
+ p->dtr_pending |= target_mask;
+ scb->flags &= ~SCB_MSGOUT_BITS;
+ scb->flags |= SCB_MSGOUT_PPR;
+ aic_outb(p, HOST_MSG, MSG_OUT);
+ aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+ }
done = TRUE;
break;
}
} /* end of switch(p->msg_type) */
} /* end of if (!reject && (p->msg_len > 2)) */
- if (reject)
+ if (!reply && reject)
{
aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
if (aic7xxx_verbose & VERBOSE_RESET)
printk(WARN_LEAD "Someone else reset the channel!!\n",
p->host_no, channel, -1, -1);
+ if (aic7xxx_panic_on_abort)
+ aic7xxx_panic_abort(p, NULL);
/*
* Go through and abort all commands for the channel, but do not
* reset the channel again.
*/
aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
scb = NULL;
}
else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
CTL_OF_SCB(scb), scb->hscb->tag);
aic7xxx_reset_device(p, target, channel, ALL_LUNS,
(message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
scb = NULL;
printerror = 0;
}
printerror = 0;
}
}
+ if ( (scb != NULL) &&
+ (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)]) )
+ {
+ /*
+ * This might be a SCSI-3 device that is dropping the bus due to
+ * errors and signalling that we should reduce the transfer speed.
+ * All we have to do is complete this command (since it's a negotiation
+ * command already) and the checksum routine should flag an error and
+ * reduce the speed setting and renegotiate. We call the reset routing
+ * just to clean out the hardware from this scb.
+ */
+ printerror = 0;
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+ aic7xxx_run_done_queue(p, TRUE);
+ scb = NULL;
+ }
if (printerror != 0)
{
if (scb != NULL)
tag = SCB_LIST_NULL;
}
aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
- aic7xxx_run_done_queue(p, FALSE);
+ aic7xxx_run_done_queue(p, TRUE);
+ }
+ else
+ {
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, TRUE);
}
printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
"SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
cmd->result = 0;
scb = NULL;
}
+ if (scb->cmd == p->dev_dtr_cmnd[TARGET_INDEX(scb->cmd)])
+ {
+ /*
+ * Turn off the needsdtr, needwdtr, and needppr bits since this device
+ * doesn't seem to exist.
+ */
+ p->needppr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+ p->needppr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+ p->needsdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+ p->needsdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+ p->needwdtr &= ~(0x01 << TARGET_INDEX(scb->cmd));
+ p->needwdtr_copy &= ~(0x01 << TARGET_INDEX(scb->cmd));
+ }
}
/*
* Restarting the sequencer will stop the selection and make sure devices
* are allowed to reselect in.
*/
aic_outb(p, 0, SCSISEQ);
+ aic_outb(p, CLRSELINGO, CLRSINT0);
aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
p->flags &= ~AHC_HANDLING_REQINITS;
aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
Scsi_Cmnd *cmd;
unsigned char mesg_out = MSG_NOOP;
unsigned char lastphase = aic_inb(p, LASTPHASE);
+ unsigned char sstat2 = aic_inb(p, SSTAT2);
+ unsigned char tindex = TARGET_INDEX(scb->cmd);
cmd = scb->cmd;
switch (lastphase)
break;
}
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- printk(WARN_LEAD "Parity error during %s phase.\n",
- p->host_no, CTL_OF_SCB(scb), phase);
+ /*
+ * A parity error has occurred during a data
+ * transfer phase. Flag it and continue.
+ */
+ if( (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && (lastphase == P_DATAIN) )
+ {
+ printk(WARN_LEAD "CRC error during %s phase.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
+ if(sstat2 & CRCVALERR)
+ {
+ printk(WARN_LEAD " CRC error in intermediate CRC packet.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ if(sstat2 & CRCENDERR)
+ {
+ printk(WARN_LEAD " CRC error in ending CRC packet.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ if(sstat2 & CRCREQERR)
+ {
+ printk(WARN_LEAD " Target incorrectly requested a CRC packet.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ if(sstat2 & DUAL_EDGE_ERROR)
+ {
+ printk(WARN_LEAD " Dual Edge transmission error.\n",
+ p->host_no, CTL_OF_SCB(scb));
+ }
+ }
+ else
+ {
+ printk(WARN_LEAD "Parity error during %s phase.\n",
+ p->host_no, CTL_OF_SCB(scb), phase);
+ }
+
+ if(p->dev_flags[tindex] & DEVICE_PARITY_ERROR)
+ {
+ struct aic7xxx_syncrate *syncrate;
+ unsigned int period = p->transinfo[tindex].cur_period;
+ unsigned char options = p->transinfo[tindex].cur_options;
+ /*
+ * oops, we had a failure, lower the transfer rate and try again. It's
+ * worth noting here that it might be wise to also check for typical
+ * wide setting on narrow cable type problems and try disabling wide
+ * instead of slowing down if those exist. That's hard to do with simple
+ * checksums though.
+ */
+ if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+ {
+ syncrate++;
+ if( (syncrate->rate[0] != NULL) &&
+ (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+ {
+ p->transinfo[tindex].goal_period = syncrate->period;
+ if( !(syncrate->sxfr_ultra2 & 0x40) )
+ {
+ p->transinfo[tindex].goal_options = 0;
+ }
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+ }
+ p->dev_flags[tindex] &= ~DEVICE_PARITY_ERROR;
+ }
+ else
+ {
+ p->dev_flags[tindex] |= DEVICE_PARITY_ERROR;
+ }
/*
* We've set the hardware to assert ATN if we get a parity
printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
bogus = TRUE;
}
- temp = aic_inb(p, SCB_PREV);
- if ((temp != SCB_LIST_NULL) &&
- (temp >= p->scb_data->maxhscbs))
- {
- printk("HSCB %d bad, SCB_PREV invalid(%d).\n", i, temp);
- bogus = TRUE;
- }
if (scb_status[i] == 0)
lost++;
if (lost > 1)
unsigned char scb_index;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if(aic7xxx_verbose > 0xffff)
+ if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
#endif
* Determines the queue depth for a given device. There are two ways
* a queue depth can be obtained for a tagged queueing device. One
* way is the default queue depth which is determined by whether
- * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used
+ * AIC7XXX_CMDS_PER_DEVICE is defined. If it is defined, then it is used
* as the default queue depth. Otherwise, we use either 4 or 8 as the
* default queue depth (dependent on the number of hardware SCBs).
* The other way we determine queue depth is through the use of the
{
int tag_enabled = TRUE;
- default_depth = AIC7XXX_CMDS_PER_LUN;
+ default_depth = AIC7XXX_CMDS_PER_DEVICE;
if (!(p->discenable & target_mask))
{
}
printk("\n");
#endif
- if (checksum != scarray[len - 1])
+ if ( (checksum != scarray[len - 1]) || (checksum == 0) )
{
return (0);
}
aic_outb(p, i, SCBPTR);
aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */
aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */
- aic_outb(p, i - 1, SCB_PREV); /* Set the prev pointer. */
aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */
aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */
aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
*/
aic7xxx_loadseq(p);
+ /*
+ * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+ */
+ aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
{
aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */
{
p->transinfo[i].goal_period = 0;
p->transinfo[i].goal_offset = 0;
+ p->transinfo[i].goal_options = 0;
p->transinfo[i].goal_width = MSG_EXT_WDTR_BUS_8_BIT;
}
DRIVER_LOCK_INIT
*/
for (i = 0; i < MAX_TARGETS; i++)
{
- if(p->dev_wdtr_cmnd[i])
- kfree(p->dev_wdtr_cmnd[i]);
- if(p->dev_sdtr_cmnd[i])
- kfree(p->dev_sdtr_cmnd[i]);
+ if(p->dev_dtr_cmnd[i])
+ {
+ if(p->dev_dtr_cmnd[i]->request_buffer)
+ {
+ kfree(p->dev_dtr_cmnd[i]->request_buffer);
+ }
+ kfree(p->dev_dtr_cmnd[i]);
+ }
}
}
{
printk("aic7xxx: Using leftover BIOS values.\n");
}
- if ( *sxfrctl1 & STPWEN )
+ if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
{
p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
sc->adapter_control &= ~CFAUTOTERM;
sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
}
if (aic7xxx_extended)
- p->flags |= AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B;
+ p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+ else
+ p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
}
else
{
* Limit to 16 targets just in case. The 2842 for one is known to
* blow the max_targets setting, future cards might also.
*/
- max_targets = MIN(sc->max_targets & CFMAXTARG,
- ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8));
+ max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
if (have_seeprom)
{
mask = (0x01 << i);
if (!have_seeprom)
{
- if(aic_inb(p, SCSISEQ) != 0)
+ if (aic_inb(p, SCSISEQ) != 0)
{
/*
* OK...the BIOS set things up and left behind the settings we need.
sc->device_flags[i] = CFDISC;
if (p->features & AHC_WIDE)
sc->device_flags[i] |= CFWIDEB;
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_ULTRA3)
+ sc->device_flags[i] |= 2;
+ else if (p->features & AHC_ULTRA2)
sc->device_flags[i] |= 3;
else if (p->features & AHC_ULTRA)
sc->device_flags[i] |= CFSYNCHISULTRA;
}
if (p->flags & AHC_NEWEEPROM_FMT)
{
- if (sc->device_flags[i] & CFSYNCHISULTRA)
- {
- p->ultraenb |= mask;
- }
- else if (sc->device_flags[i] & CFNEWULTRAFORMAT)
+ if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+ !(p->features & AHC_ULTRA2) )
{
- if ( ((sc->device_flags[i] & (CFSYNCHISULTRA | CFXFER)) == 0x03) &&
- !(p->features & AHC_ULTRA2) )
+ /*
+ * I know of two different Ultra BIOSes that do this differently.
+ * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+ * be == to 0x03 and SYNCISULTRA to be true to mean 40MByte/s
+ * while on the IBM Netfinity 5000 they want the same thing
+ * to be something else, while flags[i] & CFXFER == 0x03 and
+ * SYNCISULTRA false should be 40MByte/s. So, we set both to
+ * 40MByte/s and the lower speeds be damned. People will have
+ * to select around the conversely mapped lower speeds in order
+ * to select lower speeds on these boards.
+ */
+ if ((sc->device_flags[i] & (CFXFER)) == 0x03)
{
sc->device_flags[i] &= ~CFXFER;
sc->device_flags[i] |= CFSYNCHISULTRA;
- p->ultraenb |= mask;
}
}
+ if (sc->device_flags[i] & CFSYNCHISULTRA)
+ {
+ p->ultraenb |= mask;
+ }
}
else if (sc->adapter_control & CFULTRAEN)
{
p->ultraenb &= ~mask;
p->transinfo[i].user_offset = 0;
p->transinfo[i].user_period = 0;
+ p->transinfo[i].user_options = 0;
p->transinfo[i].cur_offset = 0;
p->transinfo[i].cur_period = 0;
+ p->transinfo[i].cur_options = 0;
p->needsdtr_copy &= ~mask;
}
else
{
- if (p->features & AHC_ULTRA2)
+ if (p->features & AHC_ULTRA3)
+ {
+ p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
+ p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
+ if( (sc->device_flags[i] & CFXFER) < 0x03 )
+ {
+ scsirate = (sc->device_flags[i] & CFXFER);
+ p->transinfo[i].user_options = MSG_EXT_PPR_OPTION_DT_CRC;
+ if( (aic_inb(p, TARG_SCSIRATE + i) & CFXFER) < 0x03 )
+ {
+ p->transinfo[i].cur_options =
+ ((aic_inb(p, TARG_SCSIRATE + i) & 0x40) ?
+ MSG_EXT_PPR_OPTION_DT_CRC : MSG_EXT_PPR_OPTION_DT_UNITS);
+ }
+ else
+ {
+ p->transinfo[i].cur_options = 0;
+ }
+ }
+ else
+ {
+ scsirate = (sc->device_flags[i] & CFXFER) |
+ ((p->ultraenb & mask) ? 0x18 : 0x10);
+ p->transinfo[i].user_options = 0;
+ p->transinfo[i].cur_options = 0;
+ }
+ p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
+ AHC_SYNCRATE_ULTRA3);
+ p->transinfo[i].cur_period = aic7xxx_find_period(p,
+ aic_inb(p, TARG_SCSIRATE + i),
+ AHC_SYNCRATE_ULTRA3);
+ }
+ else if (p->features & AHC_ULTRA2)
{
p->transinfo[i].user_offset = MAX_OFFSET_ULTRA2;
p->transinfo[i].cur_offset = aic_inb(p, TARG_OFFSET + i);
scsirate = (sc->device_flags[i] & CFXFER) |
((p->ultraenb & mask) ? 0x18 : 0x10);
+ p->transinfo[i].user_options = 0;
+ p->transinfo[i].cur_options = 0;
p->transinfo[i].user_period = aic7xxx_find_period(p, scsirate,
AHC_SYNCRATE_ULTRA2);
p->transinfo[i].cur_period = aic7xxx_find_period(p,
else
{
scsirate = (sc->device_flags[i] & CFXFER) << 4;
- if (sc->device_flags[i] & CFWIDEB)
- p->transinfo[i].user_offset = MAX_OFFSET_16BIT;
- else
- p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
+ p->transinfo[i].user_options = 0;
+ p->transinfo[i].cur_options = 0;
+ p->transinfo[i].user_offset = MAX_OFFSET_8BIT;
if (p->features & AHC_ULTRA)
{
short ultraenb;
}
aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+ p->needppr = p->needppr_copy = p->needdv = 0;
p->needwdtr = p->needwdtr_copy;
p->needsdtr = p->needsdtr_copy;
- p->wdtr_pending = p->sdtr_pending = 0;
+ p->dtr_pending = 0;
/*
* We set the p->ultraenb from the SEEPROM to begin with, but now we make
{
case AHC_AIC7895:
case AHC_AIC7896:
+ case AHC_AIC7899:
if (p->adapter_control & CFBPRIMARY)
p->flags |= AHC_CHANNEL_B_PRIMARY;
default:
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
AHC_PAGESCBS, AHC_AIC7850_FE, 6,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7860_FE, 7,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7860_FE, 7,
+ 32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7860_FE, 7,
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+ AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18,
+ 32, C46 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
AHC_AIC7895_FE, 19,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7890_FE, 20,
32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_78902, AHC_AIC7890,
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7890_FE, 20,
32, C46 },
- {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
AHC_AIC7890_FE, 21,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7890_FE, 22,
+ 32, C46 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 22,
+ AHC_AIC7896_FE, 23,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 23,
+ AHC_AIC7896_FE, 24,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
- AHC_AIC7896_FE, 24,
+ AHC_AIC7896_FE, 25,
32, C56_66 },
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
- AHC_AIC7860_FE, 25,
+ AHC_AIC7860_FE, 26,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+ AHC_AIC7892_FE, 27,
+ 32, C46 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
+ {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+ AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+ AHC_AIC7899_FE, 28,
+ 32, C56_66 },
};
unsigned short command;
}
#ifdef AIC7XXX_STRICT_PCI_SETUP
command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
- PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#else
command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#endif
+ command &= ~PCI_COMMAND_INVALIDATE;
if (aic7xxx_pci_parity == 0)
command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
pci_write_config_word(pdev, PCI_COMMAND, command);
{
printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
}
- devconfig |= 0x80000000;
- if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
- {
- devconfig &= ~(0x00000008);
- }
- else
- {
- devconfig |= 0x00000008;
- }
+ devconfig |= 0x80000040;
pci_write_config_dword(pdev, DEVCONFIG, devconfig);
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#else /* LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
}
#ifdef AIC7XXX_STRICT_PCI_SETUP
command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
- PCI_COMMAND_INVALIDATE | PCI_COMMAND_MASTER |
- PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#else
command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
#endif
+ command &= ~PCI_COMMAND_INVALIDATE;
if (aic7xxx_pci_parity == 0)
command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
pcibios_write_config_word(pci_bus, pci_devfn, PCI_COMMAND, command);
{
printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
}
- devconfig |= 0x80000000;
- if ((aic7xxx_pci_parity == 0) || (aic7xxx_pci_parity == -1))
- {
- devconfig &= ~(0x00000008);
- }
- else
- {
- devconfig |= 0x00000008;
- }
+ devconfig |= 0x80000040;
pcibios_write_config_dword(pci_bus, pci_devfn, DEVCONFIG, devconfig);
#endif /* AIC7XXX_STRICT_PCI_SETUP */
#endif /* LINUIX_VERSION_CODE > KERNEL_VERSION(2,1,92) */
case AHC_AIC7895: /* 7895 */
case AHC_AIC7896: /* 7896/7 */
+ case AHC_AIC7899: /* 7899 */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
if (PCI_FUNC(temp_p->pdev->devfn) != 0)
{
*/
switch (temp_p->chip & AHC_CHIPID_MASK)
{
- case AHC_AIC7890:
- case AHC_AIC7896:
+ case AHC_AIC7892:
+ case AHC_AIC7899:
aic_outb(temp_p, 0, SCAMCTL);
/*
- * We used to set DPARCKEN in this register, but after talking
- * to a tech from Adaptec, I found out they don't use that
- * particular bit in their own register settings, and when you
- * combine that with the fact that I determined that we were
- * seeing Data-Path Parity Errors on things we shouldn't see
- * them on, I think there is a bug in the silicon and the way
- * to work around it is to disable this particular check. Also
- * This bug only showed up on certain commands, so it seems to
- * be pattern related or some such. The commands we would
- * typically send as a linux TEST_UNIT_READY or INQUIRY command
- * could cause it to be triggered, while regular commands that
- * actually made reasonable use of the SG array capabilities
- * seemed not to cause the problem.
+ * Switch to the alt mode of the chip...
*/
+ aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
/*
- aic_outb(temp_p, aic_inb(temp_p, DSCOMMAND0) |
- CACHETHEN | DPARCKEN | MPARCKEN |
- USCBSIZE32 | CIOPARCKEN,
- DSCOMMAND0);
+ * Set our options...the last two items set our CRC after x byte
+ * count in target mode...
*/
+ aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
+ aic_outb(temp_p, 0x00, 0x0b);
+ aic_outb(temp_p, 0x10, 0x0a);
+ /*
+ * switch back to normal mode...
+ */
+ aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
+ aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
+ TARGCRCENDEN | TARGCRCCNTEN,
+ CRCCONTROL1);
+ aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
+ MPARCKEN | CIOPARCKEN | CACHETHEN) &
+ ~DPARCKEN), DSCOMMAND0);
+ aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+ break;
+ case AHC_AIC7890:
+ case AHC_AIC7896:
+ aic_outb(temp_p, 0, SCAMCTL);
aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
CACHETHEN | MPARCKEN | USCBSIZE32 |
CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
- /* FALLTHROUGH */
- default:
- /*
- * We attempt to read a SEEPROM on *everything*. If we fail,
- * then we fail, but this covers things like 2910c cards that
- * now have SEEPROMs with their 7856 chipset that we would
- * otherwise ignore. They still don't have a BIOS, but they
- * have a SEEPROM that the SCSISelect utility on the Adaptec
- * diskettes can configure.
- */
aic7xxx_load_seeprom(temp_p, &sxfrctl1);
break;
case AHC_AIC7850:
aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
CACHETHEN | MPARCKEN) & ~DPARCKEN,
DSCOMMAND0);
+ /* FALLTHROUGH */
+ default:
aic7xxx_load_seeprom(temp_p, &sxfrctl1);
break;
case AHC_AIC7880:
/*
- * Only set the DSCOMMAND0 register if this is a Rev B.
- * chipset. For those, we also enable Ultra mode by
- * force due to brain-damage on the part of some BIOSes
- * We overload the devconfig variable here since we can.
+ * Check the rev of the chipset before we change DSCOMMAND0
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
{
case AHC_AIC7895:
case AHC_AIC7896:
+ case AHC_AIC7899:
current_p = list_p;
while(current_p != NULL)
{
break;
case AHC_AIC7895:
case AHC_AIC7896:
+ case AHC_AIC7899:
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
#else
*/
if (temp_p->features & AHC_ULTRA2)
{
- aic_outb(temp_p, RD_DFTHRSH_75 | WR_DFTHRSH_75, DFF_THRSH);
+ aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
}
else
{
}
}
/*
- * Are we dealing with a 7985 where we need to sort the
+ * Are we dealing with a 7895/6/7/9 where we need to sort the
* channels as well, if so, the bios_address values should
* be the same
*/
return (found);
}
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
+static void aic7xxx_build_negotiation_cmnd(struct aic7xxx_host *p,
+ Scsi_Cmnd *old_cmd, int tindex);
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_allocate_negotiation_command
+ *
+ * Description:
+ * allocate the actual command struct and fill in the gaps...
+ *-F*************************************************************************/
+static Scsi_Cmnd *
+aic7xxx_allocate_negotiation_command(struct aic7xxx_host *p,
+ Scsi_Cmnd *old_cmd, int tindex)
+{
+ Scsi_Cmnd *cmd;
+ char *buffer;
+
+ if (!(p->dev_dtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+ {
+ return(NULL);
+ }
+ if (!(buffer = kmalloc(256, GFP_ATOMIC)))
+ {
+ kfree(p->dev_dtr_cmnd[tindex]);
+ p->dev_dtr_cmnd[tindex] = NULL;
+ return(NULL);
+ }
+ cmd = p->dev_dtr_cmnd[tindex];
+ memset(cmd, 0, sizeof(Scsi_Cmnd));
+ memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
+ memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
+ memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
+ cmd->lun = 0;
+ cmd->request_bufflen = 255;
+ cmd->request_buffer = buffer;
+ cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
+ cmd->bufflen = 0;
+ cmd->buffer = NULL;
+ cmd->underflow = 0;
+ cmd->cmd_len = 6;
+ cmd->cmnd[0] = cmd->data_cmnd[0] = INQUIRY;
+ cmd->cmnd[1] = cmd->data_cmnd[1] = 0;
+ cmd->cmnd[2] = cmd->data_cmnd[2] = 0;
+ cmd->cmnd[3] = cmd->data_cmnd[3] = 0;
+ cmd->cmnd[4] = cmd->data_cmnd[4] = 255; /* match what scsi.c does here */
+ cmd->cmnd[5] = cmd->data_cmnd[5] = 0;
+ return(cmd);
+}
/*+F*************************************************************************
* Function:
static void
aic7xxx_negotiation_complete(Scsi_Cmnd *cmd)
{
+ unsigned int checksum;
+ int i;
+ int *ibuffer;
+ struct aic7xxx_host *p = (struct aic7xxx_host *)cmd->host->hostdata;
+ int tindex = TARGET_INDEX(cmd);
+ struct aic7xxx_syncrate *syncrate;
+
+ /*
+ * perform our minimalistic domain validation
+ */
+ if(p->dev_flags[tindex] & DEVICE_SCANNED)
+ {
+ ibuffer = (int *)cmd->request_buffer;
+ checksum = 0;
+ for(i = 0; i < (cmd->request_bufflen >> 2); i++)
+ {
+ checksum += ibuffer[i];
+ }
+ if( (checksum != p->dev_checksum[tindex]) &&
+ (p->transinfo[tindex].cur_offset != 0) )
+ {
+ unsigned int period = p->transinfo[tindex].cur_period;
+ unsigned char options = p->transinfo[tindex].cur_options;
+
+ if (p->needdv & (1<<tindex))
+ {
+ /*
+ * oops, we had a failure, lower the transfer rate and try again. It's
+ * worth noting here that it might be wise to also check for typical
+ * wide setting on narrow cable type problems and try disabling wide
+ * instead of slowing down if those exist. That's hard to do with simple
+ * checksums though.
+ */
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ {
+ printk(INFO_LEAD "reducing SCSI transfer speed due to Domain "
+ "validation failure.\n", p->host_no, CTL_OF_CMD(cmd));
+ }
+ if((syncrate = aic7xxx_find_syncrate(p, &period, 0, &options)) != NULL)
+ {
+ syncrate++;
+ if( (syncrate->rate[0] != NULL) &&
+ (!(p->features & AHC_ULTRA2) || (syncrate->sxfr_ultra2 == 0)) )
+ {
+ p->transinfo[tindex].goal_period = syncrate->period;
+ if( !(syncrate->sxfr_ultra2 & 0x40) )
+ {
+ p->transinfo[tindex].goal_options = 0;
+ }
+ }
+ else
+ {
+ p->transinfo[tindex].goal_offset = 0;
+ p->transinfo[tindex].goal_period = 0;
+ p->transinfo[tindex].goal_options = 0;
+ }
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+ }
+ p->needdv &= ~(1<<tindex);
+ }
+ else
+ {
+ if(aic7xxx_verbose & VERBOSE_NEGOTIATION)
+ {
+ printk(INFO_LEAD "Performing Domain validation.\n",
+ p->host_no, CTL_OF_CMD(cmd));
+ }
+ /*
+ * Update the checksum in case the INQUIRY data has changed, maybe
+ * in relation to a change in the mode pages, or whatever.
+ */
+ p->dev_checksum[tindex] = checksum;
+ /*
+ * Signal that we are trying out the domain validation
+ */
+ p->needdv |= (1<<tindex);
+ /*
+ * Signal that we need to re-negotiate things, this also gets us our
+ * INQUIRY command to re-checksum off of.
+ */
+ p->needppr |= (p->needppr_copy & (1<<tindex));
+ p->needsdtr |= (p->needsdtr_copy & (1<<tindex));
+ p->needwdtr |= (p->needwdtr_copy & (1<<tindex));
+ }
+ }
+ else
+ {
+ if( (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+ (p->needdv & (1<<tindex)) )
+ {
+ printk(INFO_LEAD "Successfully completed Domain validation.\n",
+ p->host_no, CTL_OF_CMD(cmd));
+ }
+ /*
+ * We successfully did our checksum, so don't leave the needdv flag set
+ * in case we might have set it last time through.
+ */
+ p->needdv &= ~(1<<tindex);
+ }
+ }
+
+ p->dtr_pending &= ~(0x01 << tindex);
+ /*
+ * This looks recursive in the extreme, but if this was a WDTR negotiation
+ * and we didn't follow up with SDTR yet, then this will get it started.
+ * For all other cases, this should work out to be a no-op, unless we are
+ * doing domain validation and happen to need a new negotiation command.
+ */
+ aic7xxx_build_negotiation_cmnd(p, cmd->next, tindex);
return;
}
int tindex)
{
- if ( (p->needwdtr & (1<<tindex)) && !(p->wdtr_pending & (1<<tindex)) )
+ if ( !(p->dtr_pending & (1<<tindex)) &&
+ ( (p->needppr & (1<<tindex)) ||
+ (p->needwdtr & (1<<tindex)) ||
+ (p->needsdtr & (1<<tindex)) ) )
{
- if(p->dev_wdtr_cmnd[tindex] == NULL)
+ if ( (p->dev_dtr_cmnd[tindex] == NULL) &&
+ (aic7xxx_allocate_negotiation_command(p, old_cmd, tindex) == NULL) )
{
- Scsi_Cmnd *cmd;
-
- if (!(p->dev_wdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
- {
- return;
- }
- cmd = p->dev_wdtr_cmnd[tindex];
- memset(cmd, 0, sizeof(Scsi_Cmnd));
- memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
- memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
- memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
- cmd->lun = 0;
- cmd->request_bufflen = 0;
- cmd->request_buffer = NULL;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
+ return;
}
/*
- * Before sending this thing out, we also amke the cmd->next pointer
+ * Before sending this thing out, we also make the cmd->next pointer
* point to the real command so we can stuff any possible SENSE data
- * intp the real command instead of this fake command. This has to be
+ * into the real command instead of this fake command. This has to be
* done each time the command is built, not just the first time, hence
* it's outside of the above if()...
*/
- p->dev_wdtr_cmnd[tindex]->next = old_cmd;
- aic7xxx_queue(p->dev_wdtr_cmnd[tindex],
- aic7xxx_negotiation_complete);
- }
- else if ( (p->needsdtr & (1<<tindex)) && !(p->sdtr_pending & (1<<tindex)) &&
- !(p->wdtr_pending & (1<<tindex)) )
- {
- if(p->dev_sdtr_cmnd[tindex] == NULL)
+ p->dev_dtr_cmnd[tindex]->next = old_cmd;
+ /*
+ * Clear the buffer so checksums come out right....
+ */
+ memset(p->dev_dtr_cmnd[tindex]->request_buffer, 0,
+ p->dev_dtr_cmnd[tindex]->request_bufflen);
+ /*
+ * Remove any commands for this particular device that might be on the
+ * waiting_scbs queue or qinfifo so that this command goes out first.
+ * This is vital for our implementation of domain validation.
+ */
+ pause_sequencer(p);
+ aic7xxx_search_qinfifo(p, old_cmd->target, old_cmd->channel, ALL_LUNS,
+ SCB_LIST_NULL, 0, TRUE, &p->delayed_scbs[tindex]);
+ unpause_sequencer(p, FALSE);
{
- Scsi_Cmnd *cmd;
+ struct aic7xxx_scb *scb, *next;
- if (!(p->dev_sdtr_cmnd[tindex] = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC)) )
+ scb = p->waiting_scbs.head;
+ while(scb != NULL)
{
- return;
+ if( aic7xxx_match_scb(p, scb, old_cmd->target, old_cmd->channel,
+ ALL_LUNS, SCB_LIST_NULL) )
+ {
+ next = scb->q_next;
+ scbq_remove(&p->waiting_scbs, scb);
+ scbq_insert_tail(&p->delayed_scbs[tindex], scb);
+ scb = next;
+ }
+ else
+ {
+ scb = scb->q_next;
+ }
}
- cmd = p->dev_sdtr_cmnd[tindex];
- memset(cmd, 0, sizeof(Scsi_Cmnd));
- memcpy(cmd, old_cmd, sizeof(Scsi_Cmnd));
- memset(&cmd->cmnd[0], 0, sizeof(cmd->cmnd));
- memset(&cmd->data_cmnd[0], 0, sizeof(cmd->data_cmnd));
- cmd->lun = 0;
- cmd->request_bufflen = 0;
- cmd->request_buffer = NULL;
- cmd->use_sg = cmd->old_use_sg = cmd->sglist_len = 0;
- cmd->bufflen = 0;
- cmd->buffer = NULL;
- cmd->underflow = 0;
- cmd->cmd_len = 6;
}
- /*
- * Before sending this thing out, we also amke the cmd->next pointer
- * point to the real command so we can stuff any possible SENSE data
- * intp the real command instead of this fake command. This has to be
- * done each time the command is built, not just the first time, hence
- * it's outside of the above if()...
- */
- p->dev_sdtr_cmnd[tindex]->next = old_cmd;
- aic7xxx_queue(p->dev_sdtr_cmnd[tindex],
+ aic7xxx_queue(p->dev_dtr_cmnd[tindex],
aic7xxx_negotiation_complete);
}
}
-#endif
-
#ifdef AIC7XXX_VERBOSE_DEBUGGING
/*+F*************************************************************************
* Function:
{
unsigned short mask;
struct aic7xxx_hwscb *hscb;
+ unsigned char tindex = TARGET_INDEX(cmd);
- mask = (0x01 << TARGET_INDEX(cmd));
+ mask = (0x01 << tindex);
hscb = scb->hscb;
/*
if (p->discenable & mask)
{
hscb->control |= DISCENB;
- if (p->tagenable & mask)
+ if ( (p->tagenable & mask) &&
+ (cmd->cmnd[0] != TEST_UNIT_READY) )
{
cmd->tag = hscb->tag;
- p->dev_commands_sent[TARGET_INDEX(cmd)]++;
- if (p->dev_commands_sent[TARGET_INDEX(cmd)] < 200)
+ p->dev_commands_sent[tindex]++;
+ if (p->dev_commands_sent[tindex] < 200)
{
hscb->control |= MSG_SIMPLE_Q_TAG;
scb->tag_action = MSG_SIMPLE_Q_TAG;
hscb->control |= MSG_SIMPLE_Q_TAG;
scb->tag_action = MSG_SIMPLE_Q_TAG;
}
- p->dev_commands_sent[TARGET_INDEX(cmd)] = 0;
+ p->dev_commands_sent[tindex] = 0;
}
}
}
- if (p->dev_flags[TARGET_INDEX(cmd)] & DEVICE_SCANNED)
+ if ( cmd == p->dev_dtr_cmnd[tindex] )
{
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
- if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) )
+ p->dtr_pending |= mask;
+ scb->tag_action = 0;
+ if (p->dev_flags[tindex] & DEVICE_SCANNED)
{
- if (cmd == p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
+ hscb->control &= DISCENB;
+ hscb->control |= MK_MESSAGE;
+ if(p->needppr & mask)
{
- p->wdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_WDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
+ scb->flags |= SCB_MSGOUT_PPR;
}
- else
+ else if(p->needwdtr & mask)
{
- aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
+ scb->flags |= SCB_MSGOUT_WDTR;
}
- }
- else if ( (p->needsdtr & mask) && !(p->sdtr_pending & mask) &&
- !(p->wdtr_pending & mask) )
- {
- if (cmd == p->dev_sdtr_cmnd[TARGET_INDEX(cmd)])
+ else if(p->needsdtr & mask)
{
- p->sdtr_pending |= mask;
scb->flags |= SCB_MSGOUT_SDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
}
- else if (cmd != p->dev_wdtr_cmnd[TARGET_INDEX(cmd)])
- {
- aic7xxx_build_negotiation_cmnd(p, cmd, TARGET_INDEX(cmd));
- }
- }
-#else
- if ( (p->needwdtr & mask) && !(p->wdtr_pending & mask) &&
- !(p->sdtr_pending & mask) && (cmd->lun == 0) )
- {
- p->wdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_WDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Building WDTR command.\n", p->host_no,
- CTL_OF_CMD(cmd));
-#endif
- }
- else if ( (p->needsdtr & mask) && !(p->wdtr_pending & mask) &&
- !(p->sdtr_pending & mask) && (cmd->lun == 0) )
- {
- p->sdtr_pending |= mask;
- scb->flags |= SCB_MSGOUT_SDTR;
- hscb->control &= DISCENB;
- hscb->control |= MK_MESSAGE;
- scb->tag_action = 0;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if (aic7xxx_verbose > 0xffff)
- printk(INFO_LEAD "Building SDTR command.\n", p->host_no,
- CTL_OF_CMD(cmd));
-#endif
}
-#endif
+ }
+ if ( !(p->dtr_pending & mask) &&
+ ( (p->needppr & mask) ||
+ (p->needwdtr & mask) ||
+ (p->needsdtr & mask) ) )
+ {
+ aic7xxx_build_negotiation_cmnd(p, cmd, tindex);
}
hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
scb->sg_count = cmd->use_sg;
hscb->SG_segment_count = cmd->use_sg;
hscb->SG_list_pointer = cpu_to_le32(VIRT_TO_BUS(&scb->sg_list[1]));
-
}
else
{
hscb->data_pointer = 0;
}
}
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
- if((cmd->cmnd[0] == TEST_UNIT_READY) && (aic7xxx_verbose & VERBOSE_PROBE2))
- {
- aic7xxx_print_scb(p, scb);
- }
-#endif
}
/*+F*************************************************************************
if(p->dev_flags[i] & DEVICE_PRESENT)
{
mask = (0x01 << i);
- printk(INFO_LEAD "dev_flags=0x%x, WDTR:%c/%c/%c, SDTR:%c/%c/%c,"
- " q_depth=%d:%d\n",
+ printk(INFO_LEAD "dev_flags=0x%x, Pending:%c, PPR:%c/%c, WDTR:%c/%c, "
+ "SDTR:%c/%c, q_depth=%d:%d\n",
p->host_no, 0, i, 0, p->dev_flags[i],
- (p->wdtr_pending & mask) ? 'Y' : 'N',
+ (p->dtr_pending & mask) ? 'Y' : 'N',
+ (p->needppr & mask) ? 'Y' : 'N',
+ (p->needppr_copy & mask) ? 'Y' : 'N',
(p->needwdtr & mask) ? 'Y' : 'N',
(p->needwdtr_copy & mask) ? 'Y' : 'N',
- (p->sdtr_pending & mask) ? 'Y' : 'N',
(p->needsdtr & mask) ? 'Y' : 'N',
(p->needsdtr_copy & mask) ? 'Y' : 'N',
p->dev_active_cmds[i],
* We haven't found the offending SCB yet, and it should be around
* somewhere, so go look for it in the cards SCBs.
*/
- printk("SCBPTR CONTROL TAG PREV NEXT\n");
+ printk("SCBPTR CONTROL TAG NEXT\n");
for(i=0; i<p->scb_data->maxhscbs; i++)
{
aic_outb(p, i, SCBPTR);
- printk(" %3d %02x %02x %02x %02x\n", i,
+ printk(" %3d %02x %02x %02x\n", i,
aic_inb(p, SCB_CONTROL), aic_inb(p, SCB_TAG),
- aic_inb(p, SCB_PREV), aic_inb(p, SCB_NEXT));
+ aic_inb(p, SCB_NEXT));
}
}
if ((found == 0) && (scb->flags & SCB_WAITINGQ))
{
int tindex = TARGET_INDEX(cmd);
-#ifdef AIC7XXX_FAKE_NEGOTIATION_CMDS
unsigned short mask;
mask = (1 << tindex);
- if (p->wdtr_pending & mask)
- {
- if (p->dev_wdtr_cmnd[tindex]->next != cmd)
- found = 1;
- else
- found = 0;
- }
- else if (p->sdtr_pending & mask)
+ if (p->dtr_pending & mask)
{
- if (p->dev_sdtr_cmnd[tindex]->next != cmd)
+ if (p->dev_dtr_cmnd[tindex]->next != cmd)
found = 1;
else
found = 0;
DRIVER_UNLOCK
return(SCSI_ABORT_PENDING);
}
-#endif
if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
printk(INFO_LEAD "SCB found on waiting list and "
"aborted.\n", p->host_no, CTL_OF_SCB(scb));
if(aic7xxx_verbose & VERBOSE_RESET_RETURN)
printk(INFO_LEAD "SCB on qoutfifo, returning.\n", p->host_no,
CTL_OF_SCB(scb));
+ aic7xxx_run_done_queue(p, TRUE);
+ aic7xxx_run_waiting_queues(p);
unpause_sequencer(p, FALSE);
DRIVER_UNLOCK
return(SCSI_RESET_NOT_RUNNING);
int
aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[])
{
- int heads, sectors, cylinders;
+ int heads, sectors, cylinders, ret;
struct aic7xxx_host *p;
+ struct buffer_head *bh;
p = (struct aic7xxx_host *) disk->device->host->hostdata;
+ bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, 1024);
- /*
- * XXX - if I could portably find the card's configuration
- * information, then this could be autodetected instead
- * of left to a boot-time switch.
- */
+ if ( bh )
+ {
+ ret = scsi_partsize(bh, disk->capacity, &geom[2], &geom[0], &geom[1]);
+ brelse(bh);
+ if ( ret != -1 )
+ return(ret);
+ }
+
heads = 64;
sectors = 32;
cylinders = disk->capacity / (heads * sectors);
0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
0xfe, 0xff} },
+ {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
+ 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+ 0xe0, 0xf1, 0xf4, 0xfc} },
+ {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
+ 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+ 0xe0, 0xf1, 0xf4, 0xfc} },
};
#ifdef CONFIG_PCI
static struct register_ranges cards_ns[] = {
{ 5, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3} },
{ 6, {0x04, 0x08, 0x0c, 0x0e, 0x10, 0x17, 0x30, 0x34, 0x3c, 0x47,
0xdc, 0xe3} },
+ { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+ 0xff, 0xff} },
+ { 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
+ 0xff, 0xff} },
{ 6, {0x04, 0x08, 0x0c, 0x1b, 0x30, 0x34, 0x3c, 0x43, 0xdc, 0xe3,
0xff, 0xff} }
};
access_mode RW
}
+/*
+ * Option Mode Register (Alternate Mode) (p. 5-198)
+ * This register is used to set certain options on Ultra3 based chips.
+ * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set)
+ */
+register OPTIONMODE {
+ address 0x008
+ access_mode RW
+ bit AUTORATEEN 0x80
+ bit AUTOACKEN 0x40
+ bit ATNMGMNTEN 0x20
+ bit BUSFREEREV 0x10
+ bit EXPPHASEDIS 0x08
+ bit SCSIDATL_IMGEN 0x04
+ bit AUTO_MSGOUT_DE 0x02
+ bit DIS_MSGIN_DUALEDGE 0x01
+}
+
+
/*
* Clear SCSI Interrupt 0 (p. 3-20)
* Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
address 0x00d
access_mode RO
bit OVERRUN 0x80
+ bit SHVALID 0x40
+ bit WIDE_RES 0x20
bit EXP_ACTIVE 0x10 /* SCSI Expander Active */
+ bit CRCVALERR 0x08 /* CRC Value Error */
+ bit CRCENDERR 0x04 /* CRC End Error */
+ bit CRCREQERR 0x02 /* CRC REQ Error */
+ bit DUAL_EDGE_ERROR 0x01 /* Invalid pins for Dual Edge phase */
mask SFCNT 0x1f
}
bit SQPARERR 0x08
bit ILLOPCODE 0x04
bit ILLSADDR 0x02
+ bit DSCTMOUT 0x02 /* Ultra3 only */
bit ILLHADDR 0x01
}
access_mode RO
}
+/*
+ * SCSIDATL IMAGE Register (p. 5-104)
+ * Write to this register also go to SCSIDATL but this register will preserve
+ * the data for later reading as long as the SCSIDATL_IMGEN bit in the
+ * OPTIONMODE register is set.
+ */
+register SCSIDATL_IMG {
+ address 0x09c
+ access_mode RW
+}
+
/*
* Queue Out FIFO (p. 3-61)
* Queue of SCBs that have completed and await the host
access_mode WO
}
+/*
+ * CRC Control 1 Register (p. 5-105)
+ * Control bits for the Ultra 160/m CRC facilities
+ */
+register CRCCONTROL1 {
+ address 0x09d
+ access_mode RW
+ bit CRCONSEEN 0x80 /* CRC ON Single Edge ENable */
+ bit CRCVALCHKEN 0x40 /* CRC Value Check Enable */
+ bit CRCENDCHKEN 0x20 /* CRC End Check Enable */
+ bit CRCREQCHKEN 0x10
+ bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */
+ bit TARGCRCCNTEN 0x40 /* Enable CRC transfer when target */
+}
+
/*
* Queue Out Count (p. 3-61)
* Number of queued SCBs in the Out FIFO
access_mode RO
}
+/*
+ * SCSI Phase Register (p. 5-106)
+ * Current bus phase
+ */
+register SCSIPHASE {
+ address 0x09e
+ access_mode RO
+ bit SP_STATUS 0x20
+ bit SP_COMMAND 0x10
+ bit SP_MSG_IN 0x08
+ bit SP_MSG_OUT 0x04
+ bit SP_DATA_IN 0x02
+ bit SP_DATA_OUT 0x01
+}
+
/*
* Special Function
*/
register SFUNCT {
address 0x09f
access_mode RW
+ bit ALT_MODE 0x80
}
/*
address 0x0F4
}
+register HESCB_QOFF {
+ address 0x0F5
+}
+
register SNSCB_QOFF {
address 0x0F6
}
+register SESCB_QOFF {
+ address 0x0F7
+}
+
register SDSCB_QOFF {
address 0x0F8
}
register QOFF_CTLSTA {
address 0x0FA
+ bit ESTABLISH_SCB_AVAIL 0x80
bit SCB_AVAIL 0x40
bit SNSCB_ROLLOVER 0x20
bit SDSCB_ROLLOVER 0x10
+ bit SESCB_ROLLOVER 0x08
mask SCB_QSIZE 0x07
mask SCB_QSIZE_256 0x06
}
/*
* Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
*
- * Copyright (c) 1994-1998 Justin Gibbs.
+ * Copyright (c) 1994-1999 Justin Gibbs.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
reset:
clr SCSISIGO; /* De-assert BSY */
+ and SXFRCTL1, ~BITBUCKET;
/* Always allow reselection */
if ((p->flags & AHC_TARGETMODE) != 0) {
mvi SCSISEQ, ENSELI|ENRSELI|ENAUTOATNP;
}
call clear_target_state;
- and SXFRCTL0, ~SPIOEN;
poll_for_work:
+ and SXFRCTL0, ~SPIOEN;
if ((p->features & AHC_QUEUE_REGS) == 0) {
mov A, QINPOS;
}
mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
mov RETURN_2 call dma_scb;
+/*
+ * Preset the residual fields in case we never go through a data phase.
+ * This isn't done by the host so we can avoid a DMA to clear these
+ * fields for the normal case of I/O that completes without underrun
+ * or overrun conditions.
+ */
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_RESID_DCNT, SCB_DATACNT, 3;
+ } else {
+ mov SCB_RESID_DCNT[0],SCB_DATACNT[0];
+ mov SCB_RESID_DCNT[1],SCB_DATACNT[1];
+ mov SCB_RESID_DCNT[2],SCB_DATACNT[2];
+ }
+ mov SCB_RESID_SGCNT, SCB_SGCOUNT;
+
start_scb:
/*
* Place us on the waiting list in case our selection
* set in SXFRCTL0.
*/
initialize_channel:
- or A, CLRSTCNT|CLRCHN, SINDEX;
- or SXFRCTL0, A;
+ or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
if ((p->features & AHC_ULTRA) != 0) {
ultra:
mvi SINDEX, ULTRA_ENB+1;
mvi INTSTAT, BAD_PHASE;
clear_target_state:
- clr DFCNTRL; /*
- * We assume that the kernel driver
- * may reset us at any time, even
- * in the middle of a DMA, so clear
- * DFCNTRL too.
- */
- clr SCSIRATE; /*
- * We don't know the target we will
- * connect to, so default to narrow
- * transfers to avoid parity problems.
- */
- and SXFRCTL0, ~(FAST20);
+ /*
+ * We assume that the kernel driver may reset us
+ * at any time, even in the middle of a DMA, so
+ * clear DFCNTRL too.
+ */
+ clr DFCNTRL;
+
+ /*
+ * We don't know the target we will connect to,
+ * so default to narrow transfers to avoid
+ * parity problems.
+ */
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov SCSIRATE, ALLZEROS, 2;
+ } else {
+ clr SCSIRATE;
+ and SXFRCTL0, ~(FAST20);
+ }
mvi LASTPHASE, P_BUSFREE;
/* clear target specific flags */
- and SEQ_FLAGS, (WIDE_BUS|TWIN_BUS) ret;
+ clr SEQ_FLAGS ret;
/*
* If we re-enter the data phase after going through another phase, the
* STCNT may have been cleared, so restore it from the residual field.
*/
data_phase_reinit:
- mvi DINDEX, STCNT;
- mvi SCB_RESID_DCNT call bcopy_3;
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HCNT, SCB_RESID_DCNT, 3;
+ }
+ bmov STCNT, SCB_RESID_DCNT, 3;
+ } else {
+ mvi DINDEX, STCNT;
+ mvi SCB_RESID_DCNT call bcopy_3;
+ }
jmp data_phase_loop;
p_data:
*/
if ((p->features & AHC_CMD_CHAN) != 0) {
bmov HADDR, SCB_DATAPTR, 7;
+ bmov STCNT, HCNT, 3;
+ bmov SG_COUNT, SCB_SGCOUNT, 5;
} else {
mvi DINDEX, HADDR;
mvi SCB_DATAPTR call bcopy_7;
- }
-
- if ((p->features & AHC_ULTRA2) == 0) {
call set_stcnt_from_hcnt;
+ mvi DINDEX, SG_COUNT;
+ mvi SCB_SGCOUNT call bcopy_5;
}
- mov SG_COUNT,SCB_SGCOUNT;
-
- mvi DINDEX, SG_NEXT;
- mvi SCB_SGPTR call bcopy_4;
-
data_phase_loop:
/* Guard against overruns */
test SG_COUNT, 0xff jnz data_phase_inbounds;
*/
or SXFRCTL1,BITBUCKET;
and DMAPARAMS, ~(HDMAEN|SDMAEN);
- if ((p->features & AHC_ULTRA2) != 0) {
- bmov HCNT, ALLONES, 3;
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ if ((p->features & AHC_ULTRA2) != 0) {
+ bmov HCNT, ALLONES, 3;
+ }
+ bmov STCNT, ALLONES, 3;
} else {
mvi STCNT[0], 0xFF;
mvi STCNT[1], 0xFF;
}
data_phase_inbounds:
/* If we are the last SG block, tell the hardware. */
+if ((p->features & AHC_ULTRA2) == 0) {
cmp SG_COUNT,0x01 jne data_phase_wideodd;
- if ((p->features & AHC_ULTRA2) != 0) {
- or SG_CACHEPTR, LAST_SEG;
- } else {
- and DMAPARAMS, ~WIDEODD;
- }
+ and DMAPARAMS, ~WIDEODD;
+}
data_phase_wideodd:
if ((p->features & AHC_ULTRA2) != 0) {
mov SINDEX, ALLONES;
mov DFCNTRL, DMAPARAMS;
- test SSTAT0, SDONE jnz .;/* Wait for preload to complete */
+ test SSTAT0, SDONE jnz .;
data_phase_dma_loop:
- test SSTAT0, SDONE jnz data_phase_dma_done;
+ test SSTAT0, SDONE jnz data_phase_dma_done;
test SSTAT1,PHASEMIS jz data_phase_dma_loop; /* ie. underrun */
data_phase_dma_phasemis:
test SSTAT0,SDONE jnz . + 2;
- mov SINDEX,ALLZEROS; /* Remeber the phasemiss */
+ clr SINDEX; /* Remember the phasemiss */
} else {
mov DMAPARAMS call dma;
}
mvi CCSGCTL, CCSGRESET;
prefetched_segs_avail:
bmov HADDR, CCSGRAM, 8;
+ if ((p->features & AHC_ULTRA2) == 0) {
+ bmov STCNT, HCNT, 3;
+ }
} else {
mvi DINDEX, HADDR;
mvi SG_NEXT call bcopy_4;
* };
*/
mvi HADDR call dfdat_in_7;
- }
-
- if ((p->features & AHC_ULTRA2) == 0) {
- /* Load STCNT as well. It is a mirror of HCNT */
call set_stcnt_from_hcnt;
}
add SG_NEXT[0],SG_SIZEOF;
adc SG_NEXT[1],A;
+ test SSTAT1, REQINIT jz .;
test SSTAT1,PHASEMIS jz data_phase_loop;
- /* Ensure the last seg is visable at the shaddow layer */
+
if ((p->features & AHC_ULTRA2) != 0) {
- or DFCNTRL, PRELOADEN;
+ mov DFCNTRL, DMAPARAMS;
+ test SSTAT0, SDONE jnz .;
}
data_phase_finish:
- if ((p->features & AHC_ULTRA2) != 0) {
- call ultra2_dmafinish;
- }
/*
* After a DMA finishes, save the SG and STCNT residuals back into the SCB
* We use STCNT instead of HCNT, since it's a reflection of how many bytes
* were transferred on the SCSI (as opposed to the host) bus.
*/
- mov SCB_RESID_DCNT[0],STCNT[0];
- mov SCB_RESID_DCNT[1],STCNT[1];
- mov SCB_RESID_DCNT[2],STCNT[2];
- mov SCB_RESID_SGCNT, SG_COUNT;
-
if ((p->features & AHC_ULTRA2) != 0) {
- or SXFRCTL0, CLRSTCNT|CLRCHN;
+ call ultra2_dmafinish;
+ }
+ if ((p->features & AHC_ULTRA2) == 0) {
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_RESID_DCNT, STCNT, 3;
+ mov SCB_RESID_SGCNT, SG_COUNT;
+ } else {
+ mov SCB_RESID_DCNT[0],STCNT[0];
+ mov SCB_RESID_DCNT[1],STCNT[1];
+ mov SCB_RESID_DCNT[2],STCNT[2];
+ mov SCB_RESID_SGCNT, SG_COUNT;
+ }
}
jmp ITloop;
data_phase_overrun:
if ((p->features & AHC_ULTRA2) != 0) {
call ultra2_dmafinish;
- or SXFRCTL0, CLRSTCNT|CLRCHN;
}
/*
* Turn off BITBUCKET mode and notify the host
ultra2_dmahalt:
and DFCNTRL, ~(SCSIEN|HDMAEN);
test DFCNTRL, HDMAEN jnz .;
+ bmov SCB_RESID_DCNT, STCNT, 3;
+ mov SCB_RESID_SGCNT, SG_COUNT;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
ret;
}
/*
* Load HADDR and HCNT.
*/
- if ((p->features & AHC_ULTRA2) != 0) {
- or SG_CACHEPTR, LAST_SEG;
- }
-
if ((p->features & AHC_CMD_CHAN) != 0) {
bmov HADDR, SCB_CMDPTR, 5;
bmov HCNT[1], ALLZEROS, 2;
+ if ((p->features & AHC_ULTRA2) == 0) {
+ bmov STCNT, HCNT, 3;
+ }
} else {
mvi DINDEX, HADDR;
mvi SCB_CMDPTR call bcopy_5;
clr HCNT[1];
clr HCNT[2];
+ call set_stcnt_from_hcnt;
}
if ((p->features & AHC_ULTRA2) == 0) {
- call set_stcnt_from_hcnt;
mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
} else {
- mvi (PRELOADEN|SCSIEN|HDMAEN|DIRECTION) call dma;
+ mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+ test SSTAT0, SDONE jnz .;
+p_command_dma_loop:
+ test SSTAT0, DMADONE jnz p_command_ultra2_dma_done;
+ test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */
+p_command_ultra2_dma_done:
+ and DFCNTRL, ~(SCSIEN|HDMAEN);
+ test DFCNTRL, HDMAEN jnz .;
+ or SXFRCTL0, CLRSTCNT|CLRCHN;
}
jmp ITloop;
* in case the target decides to put us in this phase for some strange
* reason.
*/
+p_mesgout_retry:
+ or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
p_mesgout:
mov SINDEX, MSG_OUT;
cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
* that the target is requesting that the last message(s) be resent.
*/
call phase_lock;
- cmp LASTPHASE, P_MESGOUT jne p_mesgout_done;
- or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
- jmp p_mesgout;
+ cmp LASTPHASE, P_MESGOUT je p_mesgout_retry;
p_mesgout_done:
mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */
*/
mesgin_sdptrs:
test SEQ_FLAGS, DPHASE jz mesgin_done;
- mov SCB_SGCOUNT,SG_COUNT;
-
- /* The SCB SGPTR becomes the next one we'll download */
- mvi DINDEX, SCB_SGPTR;
- mvi SG_NEXT call bcopy_4;
-
- /* The SCB DATAPTR0 becomes the current SHADDR */
- mvi DINDEX, SCB_DATAPTR;
- mvi SHADDR call bcopy_4;
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer.
- */
- mvi SCB_RESID_DCNT call bcopy_3;
-
+ /*
+ * The SCB SGPTR becomes the next one we'll download,
+ * and the SCB DATAPTR becomes the current SHADDR.
+ * Use the residual number since STCNT is corrupted by
+ * any message transfer.
+ */
+ if ((p->features & AHC_CMD_CHAN) != 0) {
+ bmov SCB_SGCOUNT, SG_COUNT, 5;
+ bmov SCB_DATAPTR, SHADDR, 4;
+ bmov SCB_DATACNT, SCB_RESID_DCNT, 3;
+ } else {
+ mvi DINDEX, SCB_SGCOUNT;
+ mvi SG_COUNT call bcopy_5;
+ mvi DINDEX, SCB_DATAPTR;
+ mvi SHADDR call bcopy_4;
+ mvi SCB_RESID_DCNT call bcopy_3;
+ }
jmp mesgin_done;
/*
}
or SAVED_TCL,A; /* SAVED_TCL should be complete now */
+ mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */
call get_untagged_SCBID;
cmp ARG_1, SCB_LIST_NULL je snoop_tag;
if ((p->flags & AHC_PAGESCBS) != 0) {
get_tag:
mvi ARG_1 call inb_next; /* tag value */
- if ((p->flags & AHC_PAGESCBS) == 0) {
-index_by_tag:
- mov SCBPTR,ARG_1;
- test SCB_CONTROL,TAG_ENB jz not_found;
- mov SCBPTR call rem_scb_from_disc_list;
- } else {
- /*
- * Ensure that the SCB the tag points to is for
- * an SCB transaction to the reconnecting target.
- */
use_retrieveSCB:
- call retrieveSCB;
- }
+ call retrieveSCB;
setup_SCB:
mov A, SAVED_TCL;
cmp SCB_TCL, A jne not_found_cleanup_scb;
* host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared
* during initialization.
*/
+if ((p->features & AHC_ULTRA2) == 0) {
dma:
mov DFCNTRL,SINDEX;
dma_loop:
* to drain the data fifo until there is space for the input
* latch to drain and HDMAEN de-asserts.
*/
- if ((p->features & AHC_ULTRA2) == 0) {
- mov NONE, DFDAT;
- }
- test DFCNTRL, HDMAEN jnz dma_halt;
+ mov NONE, DFDAT;
+ test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+}
return:
ret;
mov A, ARG_1; /* Tag passed in ARG_1 */
mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */
findSCB_next:
+ mov ARG_2, SCBPTR;
cmp SCB_NEXT, SCB_LIST_NULL je notFound;
mov SCBPTR,SCB_NEXT;
dec SINDEX; /* Last comparison moved us too far */
/*
* This routine expects SINDEX to contain the index of the SCB to be
- * removed and SCBPTR to be pointing to that SCB.
+ * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
+ * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
+ * if it is at the head.
*/
rem_scb_from_disc_list:
/* Remove this SCB from the disconnection list */
- cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev;
- mov DINDEX, SCB_PREV;
- mov SCBPTR, SCB_NEXT;
- mov SCB_PREV, DINDEX;
- mov SCBPTR, SINDEX;
-unlink_prev:
- cmp SCB_PREV,SCB_LIST_NULL je rHead;/* At the head of the list */
+ cmp ARG_2, SCB_LIST_NULL je rHead;
mov DINDEX, SCB_NEXT;
- mov SCBPTR, SCB_PREV;
+ mov SCBPTR, ARG_2;
mov SCB_NEXT, DINDEX;
mov SCBPTR, SINDEX ret;
rHead:
phase_lock:
test SSTAT1, REQINIT jz phase_lock;
test SSTAT1, SCSIPERR jnz phase_lock;
- and LASTPHASE, PHASE_MASK, SCSISIGI;
- mov SCSISIGO, LASTPHASE ret;
+ and SCSISIGO, PHASE_MASK, SCSISIGI;
+ and LASTPHASE, PHASE_MASK, SCSISIGI ret;
+if ((p->features & AHC_CMD_CHAN) == 0) {
set_stcnt_from_hcnt:
mov STCNT[0], HCNT[0];
mov STCNT[1], HCNT[1];
mov DINDIR, SINDIR;
mov DINDIR, SINDIR;
mov DINDIR, SINDIR ret;
+}
/*
* Setup addr assuming that A is an index into
* Wait for DMA from host memory to data FIFO to complete, then disable
* DMA and wait for it to acknowledge that it's off.
*/
+if ((p->features & AHC_CMD_CHAN) == 0) {
dma_finish:
test DFSTATUS,HDONE jz dma_finish;
/* Turn off DMA */
and DFCNTRL, ~HDMAEN;
test DFCNTRL, HDMAEN jnz .;
ret;
+}
add_scb_to_free_list:
if ((p->flags & AHC_PAGESCBS) != 0) {
mvi DMAPARAMS, FIFORESET;
mov SCB_TAG call dma_scb;
unlink_disc_scb:
- /* jmp instead of call since we want to return anyway */
- mov SCBPTR jmp rem_scb_from_disc_list;
+ mov DISCONNECTED_SCBH, SCB_NEXT ret;
dequeue_free_scb:
mov SCBPTR, FREE_SCBH;
mov FREE_SCBH, SCB_NEXT ret;
* candidates for paging out an SCB if one is needed for a new command.
* Modifying the disconnected list is a critical(pause dissabled) section.
*/
- mvi SCB_PREV, SCB_LIST_NULL;
mov SCB_NEXT, DISCONNECTED_SCBH;
- mov DISCONNECTED_SCBH, SCBPTR;
- cmp SCB_NEXT,SCB_LIST_NULL je return;
- mov SCBPTR,SCB_NEXT;
- mov SCB_PREV,DISCONNECTED_SCBH;
- mov SCBPTR,DISCONNECTED_SCBH ret;
+ mov DISCONNECTED_SCBH, SCBPTR ret;
#define MSG_EXT_WDTR_LEN 0x02
#define MSG_EXT_WDTR_BUS_8_BIT 0x00
#define MSG_EXT_WDTR_BUS_16_BIT 0x01
-#define MSG_EXT_WDTR_BUS_32_BIT 0x02
+#define MSG_EXT_WDTR_BUS_32_BIT 0x02
+
+#define MSG_EXT_PPR 0x04
+#define MSG_EXT_PPR_LEN 0x06
+#define MSG_EXT_PPR_OPTION_ST 0x00
+#define MSG_EXT_PPR_OPTION_DT_CRC 0x02
+#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03
+#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04
+#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05
size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Compile Options:\n");
-#ifdef AIC7XXX_RESET_DELAY
- size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
+#ifdef CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT
+ size += sprintf(BLS, " TCQ Enabled By Default : Enabled\n");
+#else
+ size += sprintf(BLS, " TCQ Enabled By Default : Disabled\n");
#endif
- size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Adapter Support Enabled\n");
- size += sprintf(BLS, " Check below to see "
- "which\n"
- " devices use tagged "
- "queueing\n");
- size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled (This is no longer "
- "an option)\n");
#ifdef AIC7XXX_PROC_STATS
size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n");
#else
size += sprintf(BLS, " AIC7XXX_PROC_STATS : Disabled\n");
#endif
+ size += sprintf(BLS, " AIC7XXX_RESET_DELAY : %d\n", AIC7XXX_RESET_DELAY);
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
size += sprintf(BLS, " SCSI Adapter: %s\n",
}
if (p->features & AHC_WIDE)
wide = "Wide ";
- if (p->features & AHC_ULTRA2)
- ultra = "Ultra2-LVD/SE ";
+ if (p->features & AHC_ULTRA3)
+ {
+ switch(p->chip & AHC_CHIPID_MASK)
+ {
+ case AHC_AIC7892:
+ case AHC_AIC7899:
+ ultra = "Ultra-160/m LVD/SE ";
+ break;
+ default:
+ ultra = "Ultra-3 LVD/SE ";
+ break;
+ }
+ }
+ else if (p->features & AHC_ULTRA2)
+ ultra = "Ultra-2 LVD/SE ";
else if (p->features & AHC_ULTRA)
ultra = "Ultra ";
size += sprintf(BLS, " %s%sController%s\n",
}
size += sprintf(BLS, " Tag Queue Enable Flags: 0x%04x\n", p->tagenable);
size += sprintf(BLS, "Ordered Queue Tag Flags: 0x%04x\n", p->orderedtag);
-#ifdef AIC7XXX_CMDS_PER_LUN
- size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_LUN);
-#else
- size += sprintf(BLS, "Default Tag Queue Depth: %d\n", 8);
-#endif
+ size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host "
"instance %d:\n", p->instance);
size += sprintf(BLS, " {");
if (p->transinfo[target].cur_offset != 0)
{
struct aic7xxx_syncrate *sync_rate;
+ unsigned char options = p->transinfo[target].cur_options;
int period = p->transinfo[target].cur_period;
int rate = (p->transinfo[target].cur_width ==
MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
- sync_rate = aic7xxx_find_syncrate(p, &period, AHC_SYNCRATE_ULTRA2);
+ sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
if (sync_rate != NULL)
{
size += sprintf(BLS, "%s MByte/sec, offset %d\n",
}
}
size += sprintf(BLS, " Transinfo settings: ");
- size += sprintf(BLS, "current(%d/%d/%d), ",
+ size += sprintf(BLS, "current(%d/%d/%d/%d), ",
p->transinfo[target].cur_period,
p->transinfo[target].cur_offset,
- p->transinfo[target].cur_width);
- size += sprintf(BLS, "goal(%d/%d/%d), ",
+ p->transinfo[target].cur_width,
+ p->transinfo[target].cur_options);
+ size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
p->transinfo[target].goal_period,
p->transinfo[target].goal_offset,
- p->transinfo[target].goal_width);
- size += sprintf(BLS, "user(%d/%d/%d)\n",
+ p->transinfo[target].goal_width,
+ p->transinfo[target].goal_options);
+ size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
p->transinfo[target].user_period,
p->transinfo[target].user_offset,
- p->transinfo[target].user_width);
+ p->transinfo[target].user_width,
+ p->transinfo[target].user_options);
#ifdef AIC7XXX_PROC_STATS
size += sprintf(BLS, " Total transfers %ld (%ld reads and %ld writes)\n",
sp->r_total + sp->w_total, sp->r_total, sp->w_total);
#define STCNT 0x08
+#define OPTIONMODE 0x08
+#define AUTORATEEN 0x80
+#define AUTOACKEN 0x40
+#define ATNMGMNTEN 0x20
+#define BUSFREEREV 0x10
+#define EXPPHASEDIS 0x08
+#define SCSIDATL_IMGEN 0x04
+#define AUTO_MSGOUT_DE 0x02
+#define DIS_MSGIN_DUALEDGE 0x01
+
#define CLRSINT0 0x0b
#define CLRSELDO 0x40
#define CLRSELDI 0x20
#define SSTAT2 0x0d
#define OVERRUN 0x80
+#define SHVALID 0x40
+#define WIDE_RES 0x20
#define SFCNT 0x1f
#define EXP_ACTIVE 0x10
+#define CRCVALERR 0x08
+#define CRCENDERR 0x04
+#define CRCREQERR 0x02
+#define DUAL_EDGE_ERROR 0x01
#define SSTAT3 0x0e
#define SCSICNT 0xf0
#define DPARERR 0x10
#define SQPARERR 0x08
#define ILLOPCODE 0x04
+#define DSCTMOUT 0x02
#define ILLSADDR 0x02
#define ILLHADDR 0x01
#define QINCNT 0x9c
+#define SCSIDATL_IMG 0x9c
+
#define QOUTFIFO 0x9d
+#define CRCCONTROL1 0x9d
+#define CRCONSEEN 0x80
+#define TARGCRCCNTEN 0x40
+#define CRCVALCHKEN 0x40
+#define CRCENDCHKEN 0x20
+#define CRCREQCHKEN 0x10
+#define TARGCRCENDEN 0x08
+
+#define SCSIPHASE 0x9e
+#define SP_STATUS 0x20
+#define SP_COMMAND 0x10
+#define SP_MSG_IN 0x08
+#define SP_MSG_OUT 0x04
+#define SP_DATA_IN 0x02
+#define SP_DATA_OUT 0x01
+
#define QOUTCNT 0x9e
#define SFUNCT 0x9f
+#define ALT_MODE 0x80
#define SCB_CONTROL 0xa0
#define MK_MESSAGE 0x80
#define HNSCB_QOFF 0xf4
+#define HESCB_QOFF 0xf5
+
#define SNSCB_QOFF 0xf6
+#define SESCB_QOFF 0xf7
+
#define SDSCB_QOFF 0xf8
#define QOFF_CTLSTA 0xfa
+#define ESTABLISH_SCB_AVAIL 0x80
#define SCB_AVAIL 0x40
#define SNSCB_ROLLOVER 0x20
#define SDSCB_ROLLOVER 0x10
+#define SESCB_ROLLOVER 0x08
#define SCB_QSIZE 0x07
#define SCB_QSIZE_256 0x06
*/
static unsigned char seqprog[] = {
0xff, 0x6a, 0x06, 0x08,
+ 0x7f, 0x02, 0x04, 0x08,
0x32, 0x6a, 0x00, 0x00,
0x12, 0x6a, 0x00, 0x00,
0xff, 0x6a, 0xd6, 0x09,
0xff, 0x6a, 0xdc, 0x09,
- 0x00, 0x65, 0x38, 0x59,
+ 0x00, 0x65, 0x42, 0x59,
0xf7, 0x01, 0x02, 0x08,
0xff, 0x4e, 0xc8, 0x08,
0xbf, 0x60, 0xc0, 0x08,
- 0x60, 0x0b, 0x7c, 0x68,
+ 0x60, 0x0b, 0x86, 0x68,
0x40, 0x00, 0x0e, 0x68,
0x08, 0x1f, 0x3e, 0x10,
- 0x60, 0x0b, 0x7c, 0x68,
+ 0x60, 0x0b, 0x86, 0x68,
0x40, 0x00, 0x0e, 0x68,
0x08, 0x1f, 0x3e, 0x10,
- 0xff, 0x3e, 0x3e, 0x60,
- 0x40, 0xfa, 0x10, 0x78,
+ 0xff, 0x3e, 0x4a, 0x60,
+ 0x40, 0xfa, 0x12, 0x78,
0xff, 0xf6, 0xd4, 0x08,
0x01, 0x4e, 0x9c, 0x18,
0x40, 0x60, 0xc0, 0x00,
- 0x00, 0x4d, 0x10, 0x70,
+ 0x00, 0x4d, 0x12, 0x70,
0x01, 0x4e, 0x9c, 0x18,
0xbf, 0x60, 0xc0, 0x08,
- 0x00, 0x6a, 0x72, 0x5c,
+ 0x00, 0x6a, 0x92, 0x5c,
0xff, 0x4e, 0xc8, 0x18,
- 0x02, 0x6a, 0x88, 0x5b,
+ 0x02, 0x6a, 0xa8, 0x5b,
0xff, 0x52, 0x20, 0x09,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x52, 0xfe, 0x5b,
+ 0x00, 0x52, 0x1e, 0x5c,
+ 0x03, 0xb0, 0x52, 0x31,
+ 0xff, 0xb0, 0x52, 0x09,
+ 0xff, 0xb1, 0x54, 0x09,
+ 0xff, 0xb2, 0x56, 0x09,
+ 0xff, 0xa3, 0x50, 0x09,
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
0xff, 0x3e, 0x20, 0x09,
- 0x00, 0x65, 0x44, 0x58,
+ 0x00, 0x65, 0x50, 0x58,
0x00, 0x65, 0x0e, 0x40,
0xf7, 0x1f, 0xca, 0x08,
0x08, 0xa1, 0xc8, 0x08,
0x0f, 0x05, 0x0a, 0x08,
0x00, 0x05, 0x0a, 0x00,
0x5a, 0x6a, 0x00, 0x04,
- 0x12, 0x65, 0xc8, 0x00,
- 0x00, 0x01, 0x02, 0x00,
+ 0x12, 0x65, 0x02, 0x00,
0x31, 0x6a, 0xca, 0x00,
- 0x80, 0x37, 0x64, 0x68,
+ 0x80, 0x37, 0x6e, 0x68,
0xff, 0x65, 0xca, 0x18,
0xff, 0x37, 0xdc, 0x08,
0xff, 0x6e, 0xc8, 0x08,
- 0x00, 0x6c, 0x6c, 0x78,
+ 0x00, 0x6c, 0x76, 0x78,
0x20, 0x01, 0x02, 0x00,
0x4c, 0x37, 0xc8, 0x28,
- 0x08, 0x1f, 0x74, 0x78,
+ 0x08, 0x1f, 0x7e, 0x78,
0x08, 0x37, 0x6e, 0x00,
0x08, 0x64, 0xc8, 0x00,
0x70, 0x64, 0xca, 0x18,
0xff, 0x6c, 0x0a, 0x08,
0x20, 0x64, 0xca, 0x18,
0xff, 0x6c, 0x08, 0x0c,
- 0x40, 0x0b, 0x04, 0x69,
- 0x80, 0x0b, 0xf6, 0x78,
+ 0x40, 0x0b, 0x0e, 0x69,
+ 0x80, 0x0b, 0x00, 0x79,
0xa4, 0x6a, 0x06, 0x00,
0x40, 0x6a, 0x16, 0x00,
- 0x10, 0x03, 0xf2, 0x78,
+ 0x10, 0x03, 0xfc, 0x78,
0xff, 0x50, 0xc8, 0x08,
0x88, 0x6a, 0xcc, 0x00,
- 0x49, 0x6a, 0xee, 0x5b,
+ 0x49, 0x6a, 0x0e, 0x5c,
0x01, 0x6a, 0x26, 0x01,
0xff, 0x6a, 0xca, 0x08,
0x08, 0x01, 0x02, 0x00,
- 0x02, 0x0b, 0x92, 0x78,
+ 0x02, 0x0b, 0x9c, 0x78,
0xf7, 0x01, 0x02, 0x08,
0xff, 0x06, 0xcc, 0x08,
0xff, 0x66, 0x32, 0x09,
0x01, 0x65, 0xca, 0x18,
- 0x80, 0x66, 0xa0, 0x78,
+ 0x80, 0x66, 0xaa, 0x78,
0xff, 0x66, 0xa2, 0x08,
- 0x10, 0x03, 0x90, 0x68,
+ 0x10, 0x03, 0x9a, 0x68,
0xfc, 0x65, 0xc8, 0x18,
- 0x00, 0x65, 0xa8, 0x48,
+ 0x00, 0x65, 0xb2, 0x48,
0xff, 0x6a, 0x32, 0x01,
0x01, 0x64, 0x18, 0x19,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x84, 0x6a, 0x06, 0x00,
0x08, 0x01, 0x02, 0x00,
- 0x02, 0x0b, 0xb2, 0x78,
+ 0x02, 0x0b, 0xbc, 0x78,
0xff, 0x06, 0xc8, 0x08,
0xff, 0x64, 0x32, 0x09,
0xff, 0x6a, 0xca, 0x08,
0x0b, 0x65, 0xca, 0x18,
0xff, 0x65, 0xc8, 0x08,
0x00, 0x8c, 0x18, 0x19,
- 0x02, 0x0b, 0xce, 0x78,
- 0x01, 0x65, 0xd4, 0x60,
+ 0x02, 0x0b, 0xd8, 0x78,
+ 0x01, 0x65, 0xde, 0x60,
0xf7, 0x01, 0x02, 0x08,
0xff, 0x06, 0x32, 0x09,
0xff, 0x65, 0xca, 0x18,
- 0xff, 0x65, 0xce, 0x68,
+ 0xff, 0x65, 0xd8, 0x68,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x64, 0x5c,
- 0x40, 0x51, 0xe6, 0x78,
+ 0x00, 0x65, 0x84, 0x5c,
+ 0x40, 0x51, 0xf0, 0x78,
0xe4, 0x6a, 0x06, 0x00,
0x08, 0x01, 0x02, 0x00,
- 0x04, 0x6a, 0x18, 0x5b,
+ 0x04, 0x6a, 0x40, 0x5b,
0x01, 0x50, 0xa0, 0x18,
- 0x00, 0x50, 0xec, 0xe0,
+ 0x00, 0x50, 0xf6, 0xe0,
0xff, 0x6a, 0xa0, 0x08,
0xff, 0x6a, 0x3a, 0x01,
0x02, 0x6a, 0x22, 0x01,
- 0x40, 0x51, 0xf2, 0x68,
+ 0x40, 0x51, 0xfc, 0x68,
0xff, 0x6a, 0x06, 0x08,
0x00, 0x65, 0x0e, 0x40,
0x20, 0x6a, 0x16, 0x00,
0xf0, 0x19, 0x6e, 0x08,
0x08, 0x6a, 0x18, 0x00,
0x08, 0x11, 0x22, 0x00,
- 0x08, 0x6a, 0x5a, 0x58,
+ 0x08, 0x6a, 0x66, 0x58,
0x08, 0x6a, 0x68, 0x00,
- 0x00, 0x65, 0x18, 0x41,
+ 0x00, 0x65, 0x22, 0x41,
0x12, 0x6a, 0x00, 0x00,
0x40, 0x6a, 0x16, 0x00,
0xff, 0x3e, 0x20, 0x09,
0xff, 0xa1, 0x6e, 0x08,
0x08, 0x6a, 0x18, 0x00,
0x08, 0x11, 0x22, 0x00,
- 0x08, 0x6a, 0x5a, 0x58,
+ 0x08, 0x6a, 0x66, 0x58,
0x80, 0x6a, 0x68, 0x00,
0x80, 0x36, 0x6c, 0x00,
- 0x00, 0x65, 0xd2, 0x5b,
+ 0x00, 0x65, 0xf2, 0x5b,
0xff, 0x3d, 0xc8, 0x08,
- 0xbf, 0x64, 0x48, 0x79,
- 0x80, 0x64, 0xf0, 0x71,
- 0xa0, 0x64, 0x0e, 0x72,
- 0xc0, 0x64, 0x08, 0x72,
- 0xe0, 0x64, 0x52, 0x72,
+ 0xbf, 0x64, 0x58, 0x79,
+ 0x80, 0x64, 0x0e, 0x72,
+ 0xa0, 0x64, 0x3a, 0x72,
+ 0xc0, 0x64, 0x32, 0x72,
+ 0xe0, 0x64, 0x7a, 0x72,
0x01, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x18, 0x41,
+ 0x00, 0x65, 0x22, 0x41,
0xf7, 0x11, 0x22, 0x08,
- 0x00, 0x65, 0x38, 0x59,
+ 0x00, 0x65, 0x42, 0x59,
0xff, 0x06, 0xd4, 0x08,
0xf7, 0x01, 0x02, 0x08,
- 0x09, 0x0c, 0x32, 0x79,
+ 0x09, 0x0c, 0x3c, 0x79,
0x08, 0x0c, 0x0e, 0x68,
0x01, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0x26, 0x09,
+ 0x02, 0x6a, 0x08, 0x30,
0xff, 0x6a, 0x08, 0x08,
0xdf, 0x01, 0x02, 0x08,
0x01, 0x6a, 0x7a, 0x00,
- 0x03, 0x36, 0x6c, 0x0c,
+ 0xff, 0x6a, 0x6c, 0x0c,
+ 0x03, 0xa9, 0x18, 0x31,
+ 0x03, 0xa9, 0x10, 0x30,
0x08, 0x6a, 0xcc, 0x00,
- 0xa9, 0x6a, 0xe8, 0x5b,
- 0x00, 0x65, 0x66, 0x41,
+ 0xa9, 0x6a, 0x08, 0x5c,
+ 0x00, 0x65, 0x78, 0x41,
0xa8, 0x6a, 0x6a, 0x00,
0x79, 0x6a, 0x6a, 0x00,
- 0x40, 0x3d, 0x50, 0x69,
+ 0x40, 0x3d, 0x60, 0x69,
0x04, 0x35, 0x6a, 0x00,
- 0x00, 0x65, 0x3a, 0x5b,
+ 0x00, 0x65, 0x62, 0x5b,
0x80, 0x6a, 0xd4, 0x01,
- 0x10, 0x36, 0x42, 0x69,
+ 0x10, 0x36, 0x4e, 0x69,
0x10, 0x36, 0x6c, 0x00,
0x07, 0xac, 0x10, 0x31,
+ 0x03, 0x8c, 0x10, 0x30,
+ 0x05, 0xa3, 0x70, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xac, 0x6a, 0xe0, 0x5b,
- 0x00, 0x65, 0xda, 0x5b,
- 0xff, 0xa3, 0x70, 0x08,
- 0x39, 0x6a, 0xcc, 0x00,
- 0xa4, 0x6a, 0xe6, 0x5b,
- 0xff, 0x38, 0x74, 0x69,
+ 0xac, 0x6a, 0x00, 0x5c,
+ 0x00, 0x65, 0xfa, 0x5b,
+ 0x38, 0x6a, 0xcc, 0x00,
+ 0xa3, 0x6a, 0x04, 0x5c,
+ 0xff, 0x38, 0x88, 0x69,
0x80, 0x02, 0x04, 0x00,
0xe7, 0x35, 0x6a, 0x08,
0x03, 0x69, 0x18, 0x31,
+ 0x03, 0x69, 0x10, 0x30,
0xff, 0x6a, 0x10, 0x00,
0xff, 0x6a, 0x12, 0x00,
0xff, 0x6a, 0x14, 0x00,
- 0x01, 0x38, 0x7a, 0x61,
- 0x02, 0xfc, 0xf8, 0x01,
+ 0x01, 0x38, 0x8c, 0x61,
0xbf, 0x35, 0x6a, 0x08,
0xff, 0x69, 0xca, 0x08,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x0b, 0x7e, 0x69,
- 0x04, 0x0b, 0x8a, 0x69,
- 0x10, 0x0c, 0x80, 0x79,
- 0x04, 0x0b, 0x88, 0x69,
+ 0x04, 0x0b, 0x90, 0x69,
+ 0x04, 0x0b, 0x9c, 0x69,
+ 0x10, 0x0c, 0x92, 0x79,
+ 0x04, 0x0b, 0x9a, 0x69,
0xff, 0x6a, 0xca, 0x08,
- 0x00, 0x35, 0x22, 0x5b,
- 0x80, 0x02, 0xd6, 0x69,
- 0xff, 0x65, 0xc8, 0x79,
+ 0x00, 0x35, 0x4a, 0x5b,
+ 0x80, 0x02, 0xf0, 0x69,
+ 0xff, 0x65, 0xe0, 0x79,
0xff, 0x38, 0x70, 0x18,
- 0xff, 0x38, 0xc8, 0x79,
- 0x80, 0xea, 0xaa, 0x61,
+ 0xff, 0x38, 0xe0, 0x79,
+ 0x80, 0xea, 0xbc, 0x61,
0xef, 0x38, 0xc8, 0x18,
0x80, 0x6a, 0xc8, 0x00,
- 0x00, 0x65, 0x9c, 0x49,
+ 0x00, 0x65, 0xae, 0x49,
0x33, 0x38, 0xc8, 0x28,
0xff, 0x64, 0xd0, 0x09,
0x04, 0x39, 0xc0, 0x31,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0xa2, 0x79,
+ 0x80, 0xeb, 0xb4, 0x79,
0xf7, 0xeb, 0xd6, 0x09,
- 0x08, 0xeb, 0xa6, 0x69,
+ 0x08, 0xeb, 0xb8, 0x69,
0x01, 0x6a, 0xd6, 0x01,
0x08, 0xe9, 0x10, 0x31,
+ 0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0x39, 0x6a, 0xe6, 0x5b,
+ 0x39, 0x6a, 0x06, 0x5c,
0x08, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x64, 0x5c,
- 0x88, 0x6a, 0x54, 0x5c,
- 0x00, 0x65, 0xda, 0x5b,
+ 0x00, 0x65, 0x84, 0x5c,
+ 0x88, 0x6a, 0x74, 0x5c,
+ 0x00, 0x65, 0xfa, 0x5b,
0xff, 0x6a, 0xc8, 0x08,
0x08, 0x39, 0x72, 0x18,
0x00, 0x3a, 0x74, 0x20,
- 0x10, 0x0c, 0x66, 0x79,
- 0x80, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0xe0, 0x59,
+ 0x01, 0x0c, 0xd8, 0x79,
+ 0x10, 0x0c, 0x78, 0x79,
+ 0xff, 0x35, 0x26, 0x09,
+ 0x04, 0x0b, 0xde, 0x69,
+ 0x00, 0x65, 0xf8, 0x59,
+ 0x03, 0x08, 0x52, 0x31,
+ 0xff, 0x38, 0x50, 0x09,
0xff, 0x08, 0x52, 0x09,
0xff, 0x09, 0x54, 0x09,
0xff, 0x0a, 0x56, 0x09,
0xff, 0x38, 0x50, 0x09,
- 0x12, 0x01, 0x02, 0x00,
- 0x00, 0x65, 0x18, 0x41,
- 0x00, 0x65, 0xe0, 0x59,
- 0x12, 0x01, 0x02, 0x00,
+ 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0xf8, 0x59,
0x7f, 0x02, 0x04, 0x08,
0xe1, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x18, 0x41,
- 0x04, 0x93, 0xea, 0x69,
+ 0x00, 0x65, 0x22, 0x41,
+ 0x04, 0x93, 0x02, 0x6a,
0xdf, 0x93, 0x26, 0x09,
- 0x20, 0x93, 0xe4, 0x69,
+ 0x20, 0x93, 0xfc, 0x69,
0x02, 0x93, 0x26, 0x01,
- 0x01, 0x94, 0xe6, 0x79,
+ 0x01, 0x94, 0xfe, 0x79,
0xd7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0xec, 0x69,
+ 0x08, 0x93, 0x04, 0x6a,
+ 0x03, 0x08, 0x52, 0x31,
+ 0xff, 0x38, 0x50, 0x09,
+ 0x12, 0x01, 0x02, 0x00,
0xff, 0x6a, 0xd4, 0x0c,
- 0x00, 0x65, 0x3a, 0x5b,
- 0x02, 0xfc, 0xf8, 0x01,
+ 0x00, 0x65, 0x62, 0x5b,
0x05, 0xb4, 0x10, 0x31,
0x02, 0x6a, 0x1a, 0x31,
+ 0x03, 0x8c, 0x10, 0x30,
0x88, 0x6a, 0xcc, 0x00,
- 0xb4, 0x6a, 0xe4, 0x5b,
+ 0xb4, 0x6a, 0x04, 0x5c,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
- 0x00, 0x65, 0xda, 0x5b,
- 0x3d, 0x6a, 0x22, 0x5b,
- 0xac, 0x6a, 0x22, 0x5b,
- 0x00, 0x65, 0x18, 0x41,
- 0x00, 0x65, 0x3a, 0x5b,
+ 0x00, 0x65, 0xfa, 0x5b,
+ 0x3d, 0x6a, 0x4a, 0x5b,
+ 0xac, 0x6a, 0x26, 0x01,
+ 0x04, 0x0b, 0x24, 0x6a,
+ 0x01, 0x0b, 0x2a, 0x6a,
+ 0x10, 0x0c, 0x26, 0x7a,
+ 0xd7, 0x93, 0x26, 0x09,
+ 0x08, 0x93, 0x2c, 0x6a,
+ 0x12, 0x01, 0x02, 0x00,
+ 0x00, 0x65, 0x22, 0x41,
+ 0x00, 0x65, 0x62, 0x5b,
0xff, 0x06, 0x44, 0x09,
- 0x00, 0x65, 0x18, 0x41,
+ 0x00, 0x65, 0x22, 0x41,
+ 0x10, 0x3d, 0x06, 0x00,
0xff, 0x34, 0xca, 0x08,
- 0x80, 0x65, 0x32, 0x62,
+ 0x80, 0x65, 0x5e, 0x62,
0x0f, 0xa1, 0xca, 0x08,
0x07, 0xa1, 0xca, 0x08,
0x40, 0xa0, 0xc8, 0x08,
0x00, 0x65, 0xca, 0x00,
0x80, 0x65, 0xca, 0x00,
- 0x80, 0xa0, 0x22, 0x7a,
+ 0x80, 0xa0, 0x4e, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0x34, 0x42,
- 0x20, 0xa0, 0x3a, 0x7a,
+ 0x00, 0x65, 0x60, 0x42,
+ 0x20, 0xa0, 0x66, 0x7a,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0xd2, 0x5b,
- 0xa0, 0x3d, 0x46, 0x62,
+ 0x00, 0x65, 0xf2, 0x5b,
+ 0xa0, 0x3d, 0x6e, 0x62,
0x23, 0xa0, 0x0c, 0x08,
- 0x00, 0x65, 0xd2, 0x5b,
- 0xa0, 0x3d, 0x46, 0x62,
- 0x00, 0xb9, 0x3a, 0x42,
- 0xff, 0x65, 0x3a, 0x62,
+ 0x00, 0x65, 0xf2, 0x5b,
+ 0xa0, 0x3d, 0x6e, 0x62,
+ 0x00, 0xb9, 0x66, 0x42,
+ 0xff, 0x65, 0x66, 0x62,
0xa1, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x10, 0x51, 0x46, 0x72,
+ 0x10, 0x51, 0x6e, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x65, 0x0c, 0x08,
- 0x00, 0x65, 0xd2, 0x5b,
- 0xa0, 0x3d, 0x46, 0x62,
- 0x10, 0x3d, 0x06, 0x00,
- 0x00, 0x65, 0x0e, 0x42,
+ 0x00, 0x65, 0xf2, 0x5b,
+ 0xa0, 0x3d, 0x38, 0x72,
0x40, 0x6a, 0x18, 0x00,
0xff, 0x34, 0xa6, 0x08,
- 0x80, 0x34, 0x4e, 0x62,
+ 0x80, 0x34, 0x76, 0x62,
0x7f, 0xa0, 0x40, 0x09,
0x08, 0x6a, 0x68, 0x00,
- 0x00, 0x65, 0x18, 0x41,
- 0x64, 0x6a, 0x12, 0x5b,
- 0x80, 0x64, 0xbe, 0x6a,
- 0x04, 0x64, 0xa4, 0x72,
- 0x02, 0x64, 0xaa, 0x72,
- 0x00, 0x6a, 0x6c, 0x72,
- 0x03, 0x64, 0xba, 0x72,
- 0x01, 0x64, 0xa0, 0x72,
- 0x07, 0x64, 0x00, 0x73,
- 0x08, 0x64, 0x68, 0x72,
+ 0x00, 0x65, 0x22, 0x41,
+ 0x64, 0x6a, 0x3a, 0x5b,
+ 0x80, 0x64, 0xea, 0x6a,
+ 0x04, 0x64, 0xcc, 0x72,
+ 0x02, 0x64, 0xd2, 0x72,
+ 0x00, 0x6a, 0x94, 0x72,
+ 0x03, 0x64, 0xe6, 0x72,
+ 0x01, 0x64, 0xc8, 0x72,
+ 0x07, 0x64, 0x28, 0x73,
+ 0x08, 0x64, 0x90, 0x72,
0x11, 0x6a, 0x22, 0x01,
- 0x07, 0x6a, 0x04, 0x5b,
+ 0x07, 0x6a, 0x2c, 0x5b,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0x18, 0x41,
- 0xff, 0xa8, 0x70, 0x6a,
- 0xff, 0xa2, 0x88, 0x7a,
+ 0x00, 0x65, 0x22, 0x41,
+ 0xff, 0xa8, 0x98, 0x6a,
+ 0xff, 0xa2, 0xb0, 0x7a,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0xfe, 0x5b,
- 0xff, 0xa2, 0x88, 0x7a,
+ 0x00, 0xb9, 0x1e, 0x5c,
+ 0xff, 0xa2, 0xb0, 0x7a,
0x71, 0x6a, 0x22, 0x01,
0xff, 0x6a, 0xd4, 0x08,
- 0x40, 0x51, 0x88, 0x62,
+ 0x40, 0x51, 0xb0, 0x62,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0xfe, 0x5b,
+ 0x00, 0xb9, 0x1e, 0x5c,
0xff, 0x3e, 0x74, 0x09,
0xff, 0x90, 0x7c, 0x08,
- 0x00, 0x65, 0x44, 0x58,
- 0x00, 0x65, 0x2a, 0x41,
- 0x20, 0xa0, 0x90, 0x6a,
+ 0x00, 0x65, 0x50, 0x58,
+ 0x00, 0x65, 0x34, 0x41,
+ 0x20, 0xa0, 0xb8, 0x6a,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0xa8, 0x5b,
- 0xff, 0x6a, 0xbe, 0x5b,
+ 0x00, 0x6a, 0xc8, 0x5b,
+ 0xff, 0x6a, 0xde, 0x5b,
0xff, 0xf8, 0xc8, 0x08,
0xff, 0x4f, 0xc8, 0x08,
- 0x01, 0x6a, 0xa8, 0x5b,
- 0x00, 0xb9, 0xbe, 0x5b,
+ 0x01, 0x6a, 0xc8, 0x5b,
+ 0x00, 0xb9, 0xde, 0x5b,
0x01, 0x4f, 0x9e, 0x18,
0x02, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x6c, 0x5c,
- 0x00, 0x65, 0x2a, 0x41,
+ 0x00, 0x65, 0x8c, 0x5c,
+ 0x00, 0x65, 0x34, 0x41,
0x41, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x18, 0x41,
+ 0x00, 0x65, 0x22, 0x41,
0x04, 0xa0, 0x40, 0x01,
- 0x00, 0x65, 0x84, 0x5c,
- 0x00, 0x65, 0x2a, 0x41,
- 0x10, 0x36, 0x68, 0x7a,
- 0xff, 0x38, 0x46, 0x09,
- 0xa4, 0x6a, 0xcc, 0x00,
- 0x39, 0x6a, 0xe6, 0x5b,
+ 0x00, 0x65, 0xa4, 0x5c,
+ 0x00, 0x65, 0x34, 0x41,
+ 0x10, 0x36, 0x90, 0x7a,
+ 0x05, 0x38, 0x46, 0x31,
+ 0x04, 0x14, 0x58, 0x31,
+ 0x03, 0xa9, 0x60, 0x31,
+ 0xa3, 0x6a, 0xcc, 0x00,
+ 0x38, 0x6a, 0x04, 0x5c,
0xac, 0x6a, 0xcc, 0x00,
- 0x14, 0x6a, 0xe6, 0x5b,
- 0xa9, 0x6a, 0xe8, 0x5b,
- 0x00, 0x65, 0x68, 0x42,
+ 0x14, 0x6a, 0x06, 0x5c,
+ 0xa9, 0x6a, 0x08, 0x5c,
+ 0x00, 0x65, 0x90, 0x42,
0xef, 0x36, 0x6c, 0x08,
- 0x00, 0x65, 0x68, 0x42,
+ 0x00, 0x65, 0x90, 0x42,
0x0f, 0x64, 0xc8, 0x08,
0x07, 0x64, 0xc8, 0x08,
0x00, 0x37, 0x6e, 0x00,
- 0x00, 0x65, 0x78, 0x5b,
- 0xff, 0x51, 0xce, 0x72,
- 0x20, 0x36, 0xde, 0x7a,
- 0x00, 0x90, 0x5c, 0x5b,
- 0x00, 0x65, 0xe0, 0x42,
+ 0xff, 0x6a, 0xa4, 0x00,
+ 0x00, 0x65, 0x98, 0x5b,
+ 0xff, 0x51, 0xfc, 0x72,
+ 0x20, 0x36, 0x06, 0x7b,
+ 0x00, 0x90, 0x86, 0x5b,
+ 0x00, 0x65, 0x08, 0x43,
0xff, 0x06, 0xd4, 0x08,
- 0x00, 0x65, 0xd2, 0x5b,
- 0xe0, 0x3d, 0xfa, 0x62,
- 0x20, 0x12, 0xfa, 0x62,
- 0x51, 0x6a, 0x08, 0x5b,
- 0xff, 0x51, 0x20, 0x09,
- 0x20, 0xa0, 0xfa, 0x7a,
- 0x00, 0x90, 0x5c, 0x5b,
- 0x00, 0x65, 0x56, 0x5b,
+ 0x00, 0x65, 0xf2, 0x5b,
+ 0xe0, 0x3d, 0x22, 0x63,
+ 0x20, 0x12, 0x22, 0x63,
+ 0x51, 0x6a, 0x30, 0x5b,
+ 0x00, 0x65, 0x80, 0x5b,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0xa1, 0xf2, 0x62,
- 0x04, 0xa0, 0xf2, 0x7a,
+ 0x00, 0xa1, 0x1a, 0x63,
+ 0x04, 0xa0, 0x1a, 0x7b,
0xfb, 0xa0, 0x40, 0x09,
0x80, 0x36, 0x6c, 0x00,
- 0x80, 0xa0, 0x68, 0x7a,
+ 0x80, 0xa0, 0x90, 0x7a,
0x7f, 0xa0, 0x40, 0x09,
- 0xff, 0x6a, 0x04, 0x5b,
- 0x00, 0x65, 0x68, 0x42,
- 0x04, 0xa0, 0xf8, 0x7a,
- 0x00, 0x65, 0x84, 0x5c,
- 0x00, 0x65, 0xfa, 0x42,
- 0x00, 0x65, 0x6c, 0x5c,
+ 0xff, 0x6a, 0x2c, 0x5b,
+ 0x00, 0x65, 0x90, 0x42,
+ 0x04, 0xa0, 0x20, 0x7b,
+ 0x00, 0x65, 0xa4, 0x5c,
+ 0x00, 0x65, 0x22, 0x43,
+ 0x00, 0x65, 0x8c, 0x5c,
0x31, 0x6a, 0x22, 0x01,
- 0x0c, 0x6a, 0x04, 0x5b,
- 0x00, 0x65, 0x68, 0x42,
+ 0x0c, 0x6a, 0x2c, 0x5b,
+ 0x00, 0x65, 0x90, 0x42,
0x61, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x68, 0x42,
+ 0x00, 0x65, 0x90, 0x42,
0x10, 0x3d, 0x06, 0x00,
0xff, 0x65, 0x68, 0x0c,
0xff, 0x06, 0xd4, 0x08,
- 0x01, 0x0c, 0x0a, 0x7b,
- 0x04, 0x0c, 0x0a, 0x6b,
+ 0x01, 0x0c, 0x32, 0x7b,
+ 0x04, 0x0c, 0x32, 0x6b,
0xe0, 0x03, 0x7a, 0x08,
- 0xe0, 0x3d, 0x1e, 0x63,
+ 0xe0, 0x3d, 0x46, 0x63,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x12, 0xda, 0x0c,
0xff, 0x06, 0xd4, 0x0c,
0xff, 0x65, 0x0c, 0x08,
- 0x02, 0x0b, 0x1a, 0x7b,
+ 0x02, 0x0b, 0x42, 0x7b,
0xff, 0x6a, 0xd4, 0x0c,
0xd1, 0x6a, 0x22, 0x01,
- 0x00, 0x65, 0x18, 0x41,
+ 0x00, 0x65, 0x22, 0x41,
0xff, 0x65, 0x26, 0x09,
- 0x01, 0x0b, 0x32, 0x6b,
- 0x10, 0x0c, 0x24, 0x7b,
- 0x04, 0x0b, 0x2c, 0x6b,
+ 0x01, 0x0b, 0x5a, 0x6b,
+ 0x10, 0x0c, 0x4c, 0x7b,
+ 0x04, 0x0b, 0x54, 0x6b,
0xff, 0x6a, 0xca, 0x08,
- 0x04, 0x93, 0x30, 0x6b,
- 0x01, 0x94, 0x2e, 0x7b,
- 0x10, 0x94, 0x30, 0x6b,
+ 0x04, 0x93, 0x58, 0x6b,
+ 0x01, 0x94, 0x56, 0x7b,
+ 0x10, 0x94, 0x58, 0x6b,
0xc7, 0x93, 0x26, 0x09,
0xff, 0x99, 0xd4, 0x08,
- 0x08, 0x93, 0x34, 0x6b,
+ 0x38, 0x93, 0x5c, 0x6b,
0xff, 0x6a, 0xd4, 0x0c,
- 0x80, 0x36, 0x38, 0x6b,
+ 0x80, 0x36, 0x60, 0x6b,
0x21, 0x6a, 0x22, 0x05,
0xff, 0x65, 0x20, 0x09,
- 0xff, 0x51, 0x46, 0x63,
+ 0xff, 0x51, 0x6e, 0x63,
0xff, 0x37, 0xc8, 0x08,
- 0xa1, 0x6a, 0x50, 0x43,
+ 0xa1, 0x6a, 0x7a, 0x43,
0xff, 0x51, 0xc8, 0x08,
- 0xb9, 0x6a, 0x50, 0x43,
- 0xff, 0xba, 0x54, 0x73,
+ 0xb9, 0x6a, 0x7a, 0x43,
+ 0xff, 0x90, 0xa4, 0x08,
+ 0xff, 0xba, 0x7e, 0x73,
0xff, 0xba, 0x20, 0x09,
0xff, 0x65, 0xca, 0x18,
- 0x00, 0x6c, 0x4a, 0x63,
+ 0x00, 0x6c, 0x72, 0x63,
0xff, 0x90, 0xca, 0x0c,
0xff, 0x6a, 0xca, 0x04,
- 0x20, 0x36, 0x72, 0x7b,
- 0x00, 0x90, 0x3e, 0x5b,
- 0xff, 0x65, 0x72, 0x73,
- 0xff, 0xba, 0x66, 0x73,
- 0xff, 0xbb, 0xcc, 0x08,
- 0xff, 0xba, 0x20, 0x09,
- 0xff, 0x66, 0x76, 0x09,
- 0xff, 0x65, 0x20, 0x09,
- 0xff, 0xbb, 0x70, 0x73,
+ 0x20, 0x36, 0x92, 0x7b,
+ 0x00, 0x90, 0x66, 0x5b,
+ 0xff, 0x65, 0x92, 0x73,
+ 0xff, 0x52, 0x90, 0x73,
0xff, 0xba, 0xcc, 0x08,
- 0xff, 0xbb, 0x20, 0x09,
+ 0xff, 0x52, 0x20, 0x09,
0xff, 0x66, 0x74, 0x09,
0xff, 0x65, 0x20, 0x0d,
0xff, 0xba, 0x7e, 0x0c,
- 0x00, 0x6a, 0x72, 0x5c,
+ 0x00, 0x6a, 0x92, 0x5c,
0x0d, 0x6a, 0x6a, 0x00,
- 0x00, 0x51, 0xfe, 0x43,
- 0xff, 0x3f, 0xcc, 0x73,
+ 0x00, 0x51, 0x1e, 0x44,
+ 0xff, 0x3f, 0xec, 0x73,
0xff, 0x6a, 0xa2, 0x00,
- 0x00, 0x3f, 0x3e, 0x5b,
- 0xff, 0x65, 0xcc, 0x73,
+ 0x00, 0x3f, 0x66, 0x5b,
+ 0xff, 0x65, 0xec, 0x73,
0x20, 0x36, 0x6c, 0x00,
- 0x20, 0xa0, 0x86, 0x6b,
+ 0x20, 0xa0, 0xa6, 0x6b,
0xff, 0xb9, 0xa2, 0x0c,
0xff, 0x6a, 0xa2, 0x04,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xf2, 0x5b,
+ 0x45, 0x6a, 0x12, 0x5c,
0x01, 0x6a, 0xd0, 0x01,
0x09, 0x6a, 0xd6, 0x01,
- 0x80, 0xeb, 0x92, 0x7b,
+ 0x80, 0xeb, 0xb2, 0x7b,
0x01, 0x6a, 0xd6, 0x01,
0x01, 0xe9, 0xa4, 0x34,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xf2, 0x5b,
+ 0x45, 0x6a, 0x12, 0x5c,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x0d, 0x6a, 0x26, 0x01,
- 0x00, 0x65, 0x64, 0x5c,
+ 0x00, 0x65, 0x84, 0x5c,
0xff, 0x99, 0xa4, 0x0c,
0xff, 0x65, 0xa4, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xf2, 0x5b,
+ 0x45, 0x6a, 0x12, 0x5c,
0x01, 0x6a, 0xd0, 0x01,
0x01, 0x6a, 0xdc, 0x05,
0x88, 0x6a, 0xcc, 0x00,
- 0x45, 0x6a, 0xf2, 0x5b,
+ 0x45, 0x6a, 0x12, 0x5c,
0x01, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0x01, 0x6a, 0x26, 0x05,
0x01, 0x65, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0xc2, 0x7b,
+ 0x80, 0xee, 0xe2, 0x7b,
0xff, 0x6a, 0xdc, 0x0d,
0xff, 0x65, 0x32, 0x09,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x64, 0x44,
+ 0x00, 0x65, 0x84, 0x44,
0xff, 0x37, 0xc8, 0x08,
- 0x00, 0x6a, 0x88, 0x5b,
+ 0x00, 0x6a, 0xa8, 0x5b,
0xff, 0x52, 0xa2, 0x0c,
- 0x01, 0x0c, 0xd2, 0x7b,
- 0x04, 0x0c, 0xd2, 0x6b,
- 0xe0, 0x03, 0x7a, 0x08,
- 0xff, 0x3d, 0x06, 0x0c,
+ 0x01, 0x0c, 0xf2, 0x7b,
+ 0x04, 0x0c, 0xf2, 0x6b,
+ 0xe0, 0x03, 0x06, 0x08,
+ 0xe0, 0x03, 0x7a, 0x0c,
0xff, 0x8c, 0x10, 0x08,
0xff, 0x8d, 0x12, 0x08,
0xff, 0x8e, 0x14, 0x0c,
0x00, 0x6c, 0xda, 0x24,
0xff, 0x65, 0xc8, 0x08,
0xe0, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0xee, 0x5b,
+ 0x41, 0x6a, 0x0e, 0x5c,
0xff, 0x90, 0xe2, 0x09,
0x20, 0x6a, 0xd0, 0x01,
- 0x04, 0x35, 0x10, 0x7c,
+ 0x04, 0x35, 0x30, 0x7c,
0x1d, 0x6a, 0xdc, 0x01,
- 0xdc, 0xee, 0x0c, 0x64,
- 0x00, 0x65, 0x1c, 0x44,
+ 0xdc, 0xee, 0x2c, 0x64,
+ 0x00, 0x65, 0x3c, 0x44,
0x01, 0x6a, 0xdc, 0x01,
0x20, 0xa0, 0xd8, 0x31,
0x09, 0xee, 0xdc, 0x01,
- 0x80, 0xee, 0x16, 0x7c,
+ 0x80, 0xee, 0x36, 0x7c,
0x19, 0x6a, 0xdc, 0x01,
- 0xd8, 0xee, 0x1a, 0x64,
+ 0xd8, 0xee, 0x3a, 0x64,
0xff, 0x6a, 0xdc, 0x09,
- 0x18, 0xee, 0x1e, 0x6c,
+ 0x18, 0xee, 0x3e, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0x88, 0x6a, 0xcc, 0x00,
- 0x41, 0x6a, 0xee, 0x5b,
+ 0x41, 0x6a, 0x0e, 0x5c,
0x20, 0x6a, 0x18, 0x01,
0xff, 0x6a, 0x1a, 0x09,
0xff, 0x6a, 0x1c, 0x09,
0xff, 0x35, 0x26, 0x09,
- 0x04, 0x35, 0x48, 0x6c,
+ 0x04, 0x35, 0x68, 0x6c,
0xa0, 0x6a, 0xca, 0x00,
0x20, 0x65, 0xc8, 0x18,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
0xff, 0x6c, 0x32, 0x09,
- 0x00, 0x65, 0x34, 0x64,
+ 0x00, 0x65, 0x54, 0x64,
0x0a, 0x93, 0x26, 0x01,
- 0x00, 0x65, 0x64, 0x5c,
- 0x04, 0x35, 0x38, 0x7b,
- 0xa0, 0x6a, 0x54, 0x5c,
- 0x00, 0x65, 0x56, 0x5c,
- 0x00, 0x65, 0x56, 0x5c,
- 0x00, 0x65, 0x56, 0x44,
+ 0x00, 0x65, 0x84, 0x5c,
+ 0x04, 0x35, 0x60, 0x7b,
+ 0xa0, 0x6a, 0x74, 0x5c,
+ 0x00, 0x65, 0x76, 0x5c,
+ 0x00, 0x65, 0x76, 0x5c,
+ 0x00, 0x65, 0x76, 0x44,
0xff, 0x65, 0xcc, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x08,
0xff, 0x99, 0xda, 0x0c,
- 0x08, 0x94, 0x64, 0x7c,
+ 0x08, 0x94, 0x84, 0x7c,
0xf7, 0x93, 0x26, 0x09,
- 0x08, 0x93, 0x68, 0x6c,
+ 0x08, 0x93, 0x88, 0x6c,
0xff, 0x6a, 0xd4, 0x0c,
0xff, 0x40, 0x74, 0x09,
0xff, 0x90, 0x80, 0x08,
0xff, 0x6a, 0x72, 0x05,
- 0xff, 0x40, 0x80, 0x64,
- 0xff, 0x3f, 0x78, 0x64,
+ 0xff, 0x40, 0xa0, 0x64,
+ 0xff, 0x3f, 0x98, 0x64,
0xff, 0x6a, 0xca, 0x04,
0xff, 0x3f, 0x20, 0x09,
0x01, 0x6a, 0x6a, 0x00,
- 0x00, 0xb9, 0xfe, 0x5b,
- 0x00, 0x90, 0x5c, 0x43,
+ 0x00, 0xb9, 0x1e, 0x5c,
+ 0xff, 0xba, 0x7e, 0x0c,
0xff, 0x40, 0x20, 0x09,
0xff, 0xba, 0x80, 0x0c,
- 0xff, 0x6a, 0x76, 0x01,
0xff, 0x3f, 0x74, 0x09,
- 0xff, 0x90, 0x7e, 0x08,
- 0xff, 0xba, 0x38, 0x73,
- 0xff, 0xba, 0x20, 0x09,
- 0xff, 0x3f, 0x76, 0x09,
- 0xff, 0x3f, 0x20, 0x0d,
+ 0xff, 0x90, 0x7e, 0x0c,
};
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+ return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+}
+
static int aic7xxx_patch12_func(struct aic7xxx_host *p);
static int
aic7xxx_patch12_func(struct aic7xxx_host *p)
{
- return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+ return ((p->features & AHC_CMD_CHAN) == 0);
}
static int aic7xxx_patch11_func(struct aic7xxx_host *p);
skip_instr :10,
skip_patch :12;
} sequencer_patches[] = {
- { aic7xxx_patch1_func, 1, 1, 2 },
- { aic7xxx_patch0_func, 2, 1, 1 },
- { aic7xxx_patch2_func, 3, 2, 1 },
- { aic7xxx_patch3_func, 7, 1, 1 },
+ { aic7xxx_patch1_func, 2, 1, 2 },
+ { aic7xxx_patch0_func, 3, 1, 1 },
+ { aic7xxx_patch2_func, 4, 2, 1 },
{ aic7xxx_patch3_func, 8, 1, 1 },
- { aic7xxx_patch4_func, 11, 4, 1 },
- { aic7xxx_patch5_func, 16, 3, 2 },
- { aic7xxx_patch0_func, 19, 4, 1 },
- { aic7xxx_patch6_func, 23, 1, 1 },
- { aic7xxx_patch7_func, 26, 1, 1 },
- { aic7xxx_patch4_func, 34, 4, 1 },
- { aic7xxx_patch8_func, 38, 3, 2 },
- { aic7xxx_patch0_func, 41, 3, 1 },
- { aic7xxx_patch9_func, 47, 7, 1 },
- { aic7xxx_patch4_func, 55, 3, 1 },
- { aic7xxx_patch8_func, 58, 2, 1 },
- { aic7xxx_patch1_func, 63, 60, 1 },
- { aic7xxx_patch8_func, 164, 1, 2 },
- { aic7xxx_patch0_func, 165, 1, 1 },
- { aic7xxx_patch2_func, 169, 1, 1 },
- { aic7xxx_patch2_func, 172, 1, 2 },
- { aic7xxx_patch0_func, 173, 2, 1 },
- { aic7xxx_patch10_func, 175, 1, 1 },
- { aic7xxx_patch8_func, 182, 1, 2 },
- { aic7xxx_patch0_func, 183, 3, 1 },
- { aic7xxx_patch8_func, 187, 1, 2 },
- { aic7xxx_patch0_func, 188, 1, 1 },
- { aic7xxx_patch8_func, 189, 7, 2 },
- { aic7xxx_patch0_func, 196, 1, 1 },
- { aic7xxx_patch2_func, 201, 13, 2 },
- { aic7xxx_patch0_func, 214, 8, 1 },
- { aic7xxx_patch10_func, 222, 1, 1 },
- { aic7xxx_patch8_func, 227, 1, 1 },
- { aic7xxx_patch8_func, 228, 1, 1 },
- { aic7xxx_patch8_func, 233, 1, 1 },
- { aic7xxx_patch8_func, 235, 2, 1 },
- { aic7xxx_patch8_func, 240, 8, 1 },
- { aic7xxx_patch8_func, 249, 1, 1 },
- { aic7xxx_patch2_func, 250, 2, 2 },
- { aic7xxx_patch0_func, 252, 4, 1 },
- { aic7xxx_patch10_func, 256, 2, 2 },
- { aic7xxx_patch0_func, 258, 1, 1 },
- { aic7xxx_patch11_func, 265, 1, 2 },
- { aic7xxx_patch0_func, 266, 1, 1 },
- { aic7xxx_patch5_func, 328, 1, 2 },
- { aic7xxx_patch0_func, 329, 1, 1 },
- { aic7xxx_patch3_func, 332, 1, 1 },
- { aic7xxx_patch11_func, 351, 1, 2 },
- { aic7xxx_patch0_func, 352, 1, 1 },
- { aic7xxx_patch6_func, 356, 1, 1 },
- { aic7xxx_patch7_func, 364, 3, 2 },
- { aic7xxx_patch0_func, 367, 1, 1 },
- { aic7xxx_patch1_func, 396, 3, 1 },
- { aic7xxx_patch10_func, 410, 1, 1 },
- { aic7xxx_patch2_func, 453, 7, 2 },
- { aic7xxx_patch0_func, 460, 8, 1 },
- { aic7xxx_patch2_func, 469, 4, 2 },
- { aic7xxx_patch0_func, 473, 6, 1 },
- { aic7xxx_patch2_func, 479, 4, 2 },
- { aic7xxx_patch0_func, 483, 3, 1 },
- { aic7xxx_patch2_func, 512, 17, 4 },
- { aic7xxx_patch12_func, 520, 4, 2 },
- { aic7xxx_patch0_func, 524, 2, 1 },
- { aic7xxx_patch0_func, 529, 33, 1 },
- { aic7xxx_patch6_func, 566, 2, 1 },
- { aic7xxx_patch6_func, 569, 9, 1 },
+ { aic7xxx_patch3_func, 9, 1, 1 },
+ { aic7xxx_patch4_func, 12, 4, 1 },
+ { aic7xxx_patch5_func, 17, 3, 2 },
+ { aic7xxx_patch0_func, 20, 4, 1 },
+ { aic7xxx_patch6_func, 24, 1, 1 },
+ { aic7xxx_patch7_func, 27, 1, 1 },
+ { aic7xxx_patch2_func, 30, 1, 2 },
+ { aic7xxx_patch0_func, 31, 3, 1 },
+ { aic7xxx_patch4_func, 40, 4, 1 },
+ { aic7xxx_patch8_func, 44, 3, 2 },
+ { aic7xxx_patch0_func, 47, 3, 1 },
+ { aic7xxx_patch9_func, 52, 7, 1 },
+ { aic7xxx_patch4_func, 60, 3, 1 },
+ { aic7xxx_patch8_func, 63, 2, 1 },
+ { aic7xxx_patch1_func, 68, 60, 1 },
+ { aic7xxx_patch8_func, 162, 1, 2 },
+ { aic7xxx_patch0_func, 163, 2, 1 },
+ { aic7xxx_patch2_func, 167, 2, 3 },
+ { aic7xxx_patch8_func, 167, 1, 1 },
+ { aic7xxx_patch0_func, 169, 2, 1 },
+ { aic7xxx_patch8_func, 172, 1, 2 },
+ { aic7xxx_patch0_func, 173, 1, 1 },
+ { aic7xxx_patch2_func, 177, 1, 1 },
+ { aic7xxx_patch2_func, 180, 3, 2 },
+ { aic7xxx_patch0_func, 183, 5, 1 },
+ { aic7xxx_patch2_func, 191, 2, 3 },
+ { aic7xxx_patch8_func, 191, 1, 1 },
+ { aic7xxx_patch0_func, 193, 3, 1 },
+ { aic7xxx_patch10_func, 196, 2, 1 },
+ { aic7xxx_patch8_func, 198, 7, 2 },
+ { aic7xxx_patch0_func, 205, 1, 1 },
+ { aic7xxx_patch2_func, 210, 14, 3 },
+ { aic7xxx_patch10_func, 223, 1, 1 },
+ { aic7xxx_patch0_func, 224, 9, 1 },
+ { aic7xxx_patch8_func, 238, 2, 1 },
+ { aic7xxx_patch8_func, 240, 1, 1 },
+ { aic7xxx_patch10_func, 241, 6, 3 },
+ { aic7xxx_patch2_func, 241, 2, 2 },
+ { aic7xxx_patch0_func, 243, 4, 1 },
+ { aic7xxx_patch8_func, 248, 1, 1 },
+ { aic7xxx_patch8_func, 252, 11, 1 },
+ { aic7xxx_patch2_func, 264, 3, 3 },
+ { aic7xxx_patch10_func, 266, 1, 1 },
+ { aic7xxx_patch0_func, 267, 5, 1 },
+ { aic7xxx_patch10_func, 272, 1, 2 },
+ { aic7xxx_patch0_func, 273, 7, 1 },
+ { aic7xxx_patch11_func, 287, 1, 2 },
+ { aic7xxx_patch0_func, 288, 1, 1 },
+ { aic7xxx_patch5_func, 348, 1, 2 },
+ { aic7xxx_patch0_func, 349, 1, 1 },
+ { aic7xxx_patch3_func, 352, 1, 1 },
+ { aic7xxx_patch2_func, 362, 3, 2 },
+ { aic7xxx_patch0_func, 365, 5, 1 },
+ { aic7xxx_patch11_func, 373, 1, 2 },
+ { aic7xxx_patch0_func, 374, 1, 1 },
+ { aic7xxx_patch6_func, 379, 1, 1 },
+ { aic7xxx_patch1_func, 416, 3, 1 },
+ { aic7xxx_patch10_func, 421, 11, 1 },
+ { aic7xxx_patch2_func, 469, 7, 2 },
+ { aic7xxx_patch0_func, 476, 8, 1 },
+ { aic7xxx_patch2_func, 485, 4, 2 },
+ { aic7xxx_patch0_func, 489, 6, 1 },
+ { aic7xxx_patch2_func, 495, 4, 2 },
+ { aic7xxx_patch0_func, 499, 3, 1 },
+ { aic7xxx_patch12_func, 509, 10, 1 },
+ { aic7xxx_patch2_func, 528, 17, 4 },
+ { aic7xxx_patch13_func, 536, 4, 2 },
+ { aic7xxx_patch0_func, 540, 2, 1 },
+ { aic7xxx_patch0_func, 545, 33, 1 },
+ { aic7xxx_patch12_func, 578, 4, 1 },
+ { aic7xxx_patch6_func, 582, 2, 1 },
+ { aic7xxx_patch6_func, 585, 9, 1 },
};
#define SCSI_1 1
#define SCSI_1_CCS 2
#define SCSI_2 3
+#define SCSI_3 4
/*
* Every SCSI command starts with a one byte OP-code.
scd->type < MAX_SCSI_DEVICE_CODE ?
scsi_device_types[(int)scd->type] : "Unknown " );
y += sprintf(buffer + len + y, " ANSI"
- " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
+ " SCSI revision: %02x", (scd->scsi_level - 1)?scd->scsi_level - 1:1);
if (scd->scsi_level == 2)
y += sprintf(buffer + len + y, " CCS\n");
else
#include "constants.h"
#include "sd.h"
+#include <scsi/scsicam.h>
/*
* This source file contains the symbol table used by scsi loadable
* modules.
*/
-extern int scsicam_bios_param (Disk * disk,
- int dev, int *ip );
-
extern void print_command (unsigned char *command);
extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
EXPORT_SYMBOL(scsi_register);
EXPORT_SYMBOL(scsi_unregister);
EXPORT_SYMBOL(scsicam_bios_param);
+EXPORT_SYMBOL(scsi_partsize);
EXPORT_SYMBOL(scsi_allocate_device);
EXPORT_SYMBOL(scsi_do_cmd);
EXPORT_SYMBOL(scsi_command_size);
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
+#include <scsi/scsicam.h>
-static int partsize(struct buffer_head *bh, unsigned long capacity,
- unsigned int *cyls, unsigned int *hds, unsigned int *secs);
static int setsize(unsigned long capacity,unsigned int *cyls,unsigned int *hds,
unsigned int *secs);
return -1;
/* try to infer mapping from partition table */
- ret_code = partsize (bh, (unsigned long) size, (unsigned int *) ip + 2,
+ ret_code = scsi_partsize (bh, (unsigned long) size, (unsigned int *) ip + 2,
(unsigned int *) ip + 0, (unsigned int *) ip + 1);
brelse (bh);
}
/*
- * Function : static int partsize(struct buffer_head *bh, unsigned long
+ * Function : static int scsi_partsize(struct buffer_head *bh, unsigned long
* capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
*
* Purpose : to determine the BIOS mapping used to create the partition
*
*/
-static int partsize(struct buffer_head *bh, unsigned long capacity,
+int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
unsigned int *cyls, unsigned int *hds, unsigned int *secs) {
struct partition *p, *largest = NULL;
int i, largest_cyl;
static void sd_detach(Scsi_Device * SDp)
{
Scsi_Disk * dpnt;
- int i;
+ int i, j;
int max_p;
int start;
max_p = sd_gendisk.max_p;
start = i << sd_gendisk.minor_shift;
- for (i=max_p - 1; i >=0 ; i--) {
- int index = start+i;
+ for (j=max_p - 1; j >=0 ; j--) {
+ int index = start+j;
kdev_t devi = MKDEV_SD_PARTITION(index);
struct super_block *sb = get_super(devi);
sync_dev(devi);
SDp->attached--;
sd_template.dev_noticed--;
sd_template.nr_dev--;
- SD_GENDISK(start).nr_real--;
+ SD_GENDISK(i).nr_real--;
return;
}
return;
*
* Borrows code from st driver. Thanks to Alessandro Rubini's "dd" book.
*/
- static char * sg_version_str = "Version: 2.1.32 (990501)";
+ static char * sg_version_str = "Version: 2.1.34 (990603)";
+ static int sg_version_num = 20134; /* 2 digits for each component */
/*
- * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
- * - scatter list logic replaces previous large atomic SG_BIG_BUFF
- * sized allocation. See notes in <scsi/sg.h> include file.
- *
+ * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
* the kernel/module needs to be built with CONFIG_SCSI_LOGGING
* (otherwise the macros compile to empty statements), then do
* Should use hlcomplete but it is too "noisy" (sd uses it).
*
* - This driver obtains memory (heap) for the low-level driver to
- * transfer/dma to and from. It is obtained from up to 4 sources:
- * - 1 SG_SCATTER_SZ sized buffer on open() (per fd)
- * [could be less if SG_SCATTER_SZ bytes not available]
- * - obtain heap as required on write()s (get_free_pages)
+ * transfer/dma to and from. It is obtained from up to 3 sources:
+ * - obtain heap via get_free_pages()
* - obtain heap from the shared scsi dma pool
* - obtain heap from kernel directly (kmalloc) [last choice]
- * the 'alt_address' field in the scatter_list structure and the
+ * Each open() attempts to obtain a "reserve" buffer of
+ * SG_DEF_RESERVED_SIZE bytes (or 0 bytes if opened O_RDONLY). The
+ * amount actually obtained [which could be 0 bytes] can be found from
+ * the SG_GET_RESERVED_SIZE ioctl(). This reserved buffer size can
+ * be changed by calling the SG_SET_RESERVED_SIZE ioctl(). Since this
+ * is an ambit claim, it should be followed by a SG_GET_RESERVED_SIZE
+ * ioctl() to find out how much was actually obtained.
+ * A subsequent write() to this file descriptor will use the
+ * reserved buffer unless:
+ * - it is already in use (eg during command queuing)
+ * - or the write() needs a buffer size larger than the
+ * reserved size
+ * In these cases the write() will attempt to get the required memory
+ * for the duration of this request but, if memory is low, it may
+ * fail with ENOMEM.
+ *
+ * - The 'alt_address' field in the scatter_list structure and the
* related 'mem_src' indicate the source of the heap allocation.
*
*/
#include <scsi/sg.h>
-int sg_big_buff = SG_SCATTER_SZ; /* sg_big_buff is ro through sysctl */
+int sg_big_buff = SG_DEF_RESERVED_SIZE; /* sg_big_buff is ro through sysctl */
/* N.B. This global is here to keep existing software happy. It now holds
- the size of the "first buffer" of the most recent sucessful sg_open().
+ the size of the reserve buffer of the most recent sucessful sg_open().
Only available when 'sg' compiled into kernel (rather than a module).
- This should probably be deprecated (use SG_GET_RESERVED_SIZE instead). */
+ This is deprecated (use SG_GET_RESERVED_SIZE ioctl() instead). */
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
static int sg_num_page = 0;
#endif
-#define SG_HEAP_FB 0 /* heap obtained at open() (one buffer per fd) */
#define SG_HEAP_PAGE 1 /* heap from kernel via get_free_pages() */
#define SG_HEAP_KMAL 2 /* heap from kernel via kmalloc() */
#define SG_HEAP_POOL 3 /* heap from scsi dma pool (mid-level) */
{
unsigned short use_sg; /* Number of pieces of scatter-gather */
unsigned short sglist_len; /* size of malloc'd scatter-gather list */
- unsigned bufflen; /* Size of data buffer */
+ unsigned bufflen; /* Size of (aggregate) data buffer */
unsigned b_malloc_len; /* actual len malloc'ed in buffer */
- void * buffer; /* Data buffer or scatter list (12 bytes) */
+ void * buffer; /* Data buffer or scatter list,12 bytes each*/
char mem_src; /* heap whereabouts of 'buffer' */
} Sg_scatter_hold; /* 20 bytes long on i386 */
Scsi_Cmnd * my_cmdp; /* NULL -> ready to read, else id */
struct sg_request * nextrp; /* NULL -> tail request (slist) */
struct sg_fd * parentfp; /* NULL -> not in use */
- Sg_scatter_hold data; /* hold buffers, perhaps scatter list */
- struct sg_header header; /* scsi command+info <include/sg.h> */
- char fb_used; /* 1 -> using fst_buf, normally 0 (used) */
-} Sg_request; /* around 72 bytes long on i386 */
+ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
+ struct sg_header header; /* scsi command+info, see <scsi/sg.h> */
+ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
+} Sg_request; /* 72 bytes long on i386 */
typedef struct sg_fd /* holds the state of a file descriptor */
{
struct sg_device * parentdp; /* owning device */
struct wait_queue * read_wait; /* queue read until command done */
int timeout; /* defaults to SG_DEFAULT_TIMEOUT */
- char * fst_buf; /* try to grab SG_SCATTER_SZ sized buffer on open */
- int fb_size; /* actual size of allocated fst_buf */
- Sg_request * headrp; /* head of request slist, NULL->empty */
+ Sg_scatter_hold reserve; /* buffer held for this file descriptor */
+ unsigned save_scat_len; /* original length of trunc. scat. element */
+ Sg_request * headrp; /* head of request slist, NULL->empty */
struct fasync_struct * async_qp; /* used by asynchronous notification */
Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */
- char low_dma; /* as in parent but possible overridden to 1 */
+ char low_dma; /* as in parent but possibly overridden to 1 */
char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */
char closed; /* 1 -> fd closed but request(s) outstanding */
- char my_mem_src; /* heap whereabouts of this sg_fb object */
+ char my_mem_src; /* heap whereabouts of this Sg_fd object */
char cmd_q; /* 1 -> allow command queuing, 0 -> don't */
char underrun_flag; /* 1 -> flag underruns, 0 -> don't, 2 -> test */
-} Sg_fd; /* around 1192 bytes long on i386 */
+ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */
+} Sg_fd; /* 1208 bytes long on i386 */
typedef struct sg_device /* holds the state of each scsi generic device */
{
Scsi_Device * device;
- struct wait_queue * generic_wait;/* queue open if O_EXCL on prev. open */
+ struct wait_queue * o_excl_wait; /* queue open() when O_EXCL in use */
int sg_tablesize; /* adapter's max scatter-gather table size */
Sg_fd * headfp; /* first open fd belonging to this device */
kdev_t i_rdev; /* holds device major+minor number */
char exclude; /* opened for exclusive access */
char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
- unsigned char merge_fd; /* 0->sequencing per fd (def) else fd count */
-} Sg_device; /* around 24 bytes long on i386 */
+ unsigned char merge_fd; /* 0->sequencing per fd, else fd count */
+} Sg_device; /* 24 bytes long on i386 */
static int sg_fasync(int fd, struct file * filp, int mode);
static void sg_command_done(Scsi_Cmnd * SCpnt);
-static int sg_sc_build(Sg_request * srp, int max_buff_size,
- const char * inp, int num_write_xfer);
-static int sg_sc_undo_rem(Sg_request * srp, char * outp,
- int num_read_xfer);
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp,
+static int sg_start_req(Sg_request * srp, int max_buff_size,
+ const char * inp, int num_write_xfer);
+static void sg_finish_rem_req(Sg_request * srp, char * outp,
+ int num_read_xfer);
+static int sg_build_scat(Sg_scatter_hold * schp, int buff_size,
+ const Sg_fd * sfp);
+static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp,
+ int num_write_xfer);
+static void sg_remove_scat(Sg_scatter_hold * schp);
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+ int num_read_xfer);
+static void sg_build_reserve(Sg_fd * sfp, int req_size);
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
int * mem_srcp);
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src);
+static void sg_free(char * buff, int size, int mem_src);
static char * sg_low_malloc(int rqSz, int lowDma, int mem_src,
int * retSzp);
static void sg_low_free(char * buff, int size, int mem_src);
static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id);
static Sg_request * sg_add_request(Sg_fd * sfp);
static int sg_remove_request(Sg_fd * sfp, const Sg_request * srp);
-static int sg_fb_in_use(const Sg_fd * sfp);
+static int sg_res_in_use(const Sg_fd * sfp);
static void sg_clr_scpnt(Scsi_Cmnd * SCpnt);
static void sg_shorten_timeout(Scsi_Cmnd * scpnt);
static void sg_debug(const Sg_device * sdp, const Sg_fd * sfp, int part_of);
int flags = filp->f_flags;
Sg_device * sdp;
Sg_fd * sfp;
+ int res;
if ((NULL == sg_dev_arr) || (dev < 0) || (dev >= sg_template.dev_max))
return -ENXIO;
printk("sg_open: inode maj=%d, min=%d sdp maj=%d, min=%d\n",
MAJOR(inode->i_rdev), MINOR(inode->i_rdev),
MAJOR(sdp->i_rdev), MINOR(sdp->i_rdev));
+ /* If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device))
return -ENXIO;
-/* if (O_RDWR != (flags & O_ACCMODE)) */
-/* return -EACCES; May just want to get to a ioctl, so remove */
SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
- /* If we want exclusive access, then wait until the device is not
- * busy, and then set the flag to prevent anyone else from using it. */
+
if (flags & O_EXCL) {
if (O_RDONLY == (flags & O_ACCMODE))
return -EACCES; /* Can't lock it with read only access */
- while (sdp->headfp) {
- if (flags & O_NONBLOCK)
- return -EBUSY;
- interruptible_sleep_on(&sdp->generic_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
- sdp->exclude = 1;
+ if (sdp->headfp && (filp->f_flags & O_NONBLOCK))
+ return -EBUSY;
+ res = 0; /* following is a macro that beats race condition */
+ __wait_event_interruptible(sdp->o_excl_wait,
+ ((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)),
+ res);
+ if (res)
+ return res; /* -ERESTARTSYS because signal hit process */
}
- else { /* Wait until nobody has an exclusive open on this device. */
- while (sdp->exclude) {
- if (flags & O_NONBLOCK)
- return -EBUSY;
- interruptible_sleep_on(&sdp->generic_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
+ else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */
+ if (filp->f_flags & O_NONBLOCK)
+ return -EBUSY;
+ res = 0; /* following is a macro that beats race condition */
+ __wait_event_interruptible(sdp->o_excl_wait, (! sdp->exclude), res);
+ if (res)
+ return res; /* -ERESTARTSYS because signal hit process */
}
- /* OK, we should have grabbed the device. Mark the thing so
- * that other processes know that we have it, and initialize the
- * state variables to known values. */
if (! sdp->headfp) { /* no existing opens on this device */
sdp->sgdebug = 0;
sdp->sg_tablesize = sdp->device->host->sg_tablesize;
if(sg_template.module)
__MOD_DEC_USE_COUNT(sg_template.module);
sdp->exclude = 0;
- wake_up_interruptible(&sdp->generic_wait);
+ wake_up_interruptible(&sdp->o_excl_wait);
return 0;
}
-/* Read back the results of a SCSI command which was sent in a prior
- write(). */
static ssize_t sg_read(struct file * filp, char * buf,
size_t count, loff_t *ppos)
{
- int k;
+ int k, res;
Sg_device * sdp;
Sg_fd * sfp;
Sg_request * srp;
SCSI_LOG_TIMEOUT(3, printk("sg_read: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
- /* If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device))
return -ENXIO;
-
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_WRITE, buf, count)))
if (sfp->force_packid && (count >= size_sg_header))
req_pack_id = shp->pack_id;
srp = sg_get_request(sfp, req_pack_id);
- while(! srp) {
+ if (! srp) { /* now wait on packet to arrive */
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
- interruptible_sleep_on(&sfp->read_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- srp = sg_get_request(sfp, req_pack_id);
+ res = 0; /* following is a macro that beats race condition */
+ __wait_event_interruptible(sfp->read_wait,
+ (srp = sg_get_request(sfp, req_pack_id)),
+ res);
+ if (res)
+ return res; /* -ERESTARTSYS because signal hit process */
}
if (2 != sfp->underrun_flag)
srp->header.pack_len = srp->header.reply_len; /* Why ????? */
if (count > srp->header.reply_len)
count = srp->header.reply_len;
if (count > size_sg_header) /* release does copy_to_user */
- sg_sc_undo_rem(srp, buf, count - size_sg_header);
+ sg_finish_rem_req(srp, buf, count - size_sg_header);
else
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
}
else {
count = (srp->header.result == 0) ? 0 : -EIO;
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
}
return count;
}
SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n",
MINOR(sdp->i_rdev), (int)count));
-/* If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
-
if (ppos != &filp->f_pos)
; /* FIXME: Hmm. Seek to the right place, or fail? */
if ((k = verify_area(VERIFY_READ, buf, count)))
return k; /* protects following copy_from_user()s + get_user()s */
-/* The minimum scsi command length is 6 bytes. If we get anything
- * less than this, it is clearly bogus. */
if (count < (size_sg_header + 6))
- return -EIO;
+ return -EIO; /* The minimum scsi command length is 6 bytes. */
srp = sg_add_request(sfp);
if (! srp) {
buf += size_sg_header;
srp->header.pack_len = count;
__get_user(opcode, buf);
- cmd_size = COMMAND_SIZE(opcode);
- if ((opcode >= 0xc0) && srp->header.twelve_byte)
- cmd_size = 12;
+ if (sfp->next_cmd_len > 0) {
+ if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
+ SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
+ sfp->next_cmd_len = 0;
+ return -EDOM;
+ }
+ cmd_size = sfp->next_cmd_len;
+ sfp->next_cmd_len = 0; /* reset so only this write() effected */
+ }
+ else {
+ cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */
+ if ((opcode >= 0xc0) && srp->header.twelve_byte)
+ cmd_size = 12;
+ }
SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n",
(int)opcode, cmd_size));
/* Determine buffer size. */
input_size = count - cmd_size;
mxsize = (input_size > srp->header.reply_len) ? input_size :
srp->header.reply_len;
-/* Don't include the command header itself in the size. */
mxsize -= size_sg_header;
input_size -= size_sg_header;
-/* Verify user has actually passed enough bytes for this command. */
if (input_size < 0) {
- sg_sc_undo_rem(srp, NULL, 0);
- return -EIO;
+ sg_remove_request(sfp, srp);
+ return -EIO; /* User did not pass enough bytes for this command. */
}
-
-/* If we cannot allocate the buffer, report an error. */
- if ((k = sg_sc_build(srp, mxsize, buf + cmd_size, input_size))) {
+ if ((k = sg_start_req(srp, mxsize, buf + cmd_size, input_size))) {
SCSI_LOG_TIMEOUT(1, printk("sg_write: build err=%d\n", k));
- sg_sc_undo_rem(srp, NULL, 0);
- return k;
+ sg_finish_rem_req(srp, NULL, 0);
+ return k; /* probably out of space --> ENOMEM */
}
-
/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */
-/* Grab a command pointer for the device we want to talk to. If we
- * don't want to block, just return with the appropriate message. */
if (! (SCpnt = scsi_allocate_device(NULL, sdp->device,
!(filp->f_flags & O_NONBLOCK)))) {
- sg_sc_undo_rem(srp, NULL, 0);
- return -EAGAIN;
+ sg_finish_rem_req(srp, NULL, 0);
+ return -EAGAIN; /* No available command blocks at the moment */
}
/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */
-
srp->my_cmdp = SCpnt;
SCpnt->request.rq_dev = sdp->i_rdev;
SCpnt->request.rq_status = RQ_ACTIVE;
SCpnt->sense_buffer[0] = 0;
SCpnt->cmd_len = cmd_size;
- /* Now copy the SCSI command from the user's address space. */
__copy_from_user(cmnd, buf, cmd_size);
-
-/* Set the LUN field in the command structure. */
+/* Set the LUN field in the command structure, overriding user input */
cmnd[1]= (cmnd[1] & 0x1f) | (sdp->device->lun << 5);
+
/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */
-/* Now pass the actual command down to the low-level driver. We
- * do not do any more here - when the interrupt arrives, we will
- * then do the post-processing. */
spin_lock_irqsave(&io_request_lock, flags);
SCpnt->use_sg = srp->data.use_sg;
SCpnt->sglist_len = srp->data.sglist_len;
srp->data.sglist_len = 0;
srp->data.bufflen = 0;
srp->data.buffer = NULL;
+/* Now send everything of to mid-level. The next time we hear about this
+ packet is when sg_command_done() is called (ie a callback). */
scsi_do_cmd(SCpnt, (void *)cmnd,
(void *)SCpnt->buffer, mxsize,
sg_command_done, sfp->timeout, SG_DEFAULT_RETRIES);
return -ENXIO;
SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n",
MINOR(sdp->i_rdev), (int)cmd_in));
- /* If we are in the middle of error recovery, then don't allow any
- * access to this device. Also, error recovery *may* have taken the
- * device offline, in which case all further access is prohibited. */
if(! scsi_block_when_processing_errors(sdp->device) )
return -ENXIO;
{
case SG_SET_TIMEOUT:
return get_user(sfp->timeout, (int *)arg);
- case SG_GET_TIMEOUT:
+ case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */
return sfp->timeout; /* strange ..., for backward compatibility */
case SG_SET_FORCE_LOW_DMA:
result = get_user(val, (int *)arg);
if (result) return result;
if (val) {
- if ((0 == sfp->low_dma) && (0 == sg_fb_in_use(sfp))) {
- sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
- sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, 1,
- SG_HEAP_PAGE, &sfp->fb_size);
- }
sfp->low_dma = 1;
- if (! sfp->fst_buf)
- return -ENOMEM;
+ if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+ val = (int)sfp->reserve.bufflen;
+ sg_remove_scat(&sfp->reserve);
+ sg_build_reserve(sfp, val);
+ }
}
else
sfp->low_dma = sdp->device->host->unchecked_isa_dma;
case SG_GET_SG_TABLESIZE:
return put_user(sdp->sg_tablesize, (int *)arg);
case SG_SET_RESERVED_SIZE:
- /* currently ignored, future extension */
if (O_RDWR != (filp->f_flags & O_ACCMODE))
return -EACCES;
result = get_user(val, (int *)arg);
if (result) return result;
- /* logic should go here */
+ if (val != sfp->reserve.bufflen) {
+ if (sg_res_in_use(sfp))
+ return -EBUSY;
+ sg_remove_scat(&sfp->reserve);
+ sg_build_reserve(sfp, val);
+ }
return 0;
case SG_GET_RESERVED_SIZE:
- return put_user(sfp->fb_size, (int *)arg);
+ val = (int)sfp->reserve.bufflen;
+ return put_user(val, (int *)arg);
case SG_GET_MERGE_FD:
return put_user((int)sdp->merge_fd, (int *)arg);
case SG_SET_MERGE_FD:
return 0;
case SG_GET_UNDERRUN_FLAG:
return put_user((int)sfp->underrun_flag, (int *)arg);
+ case SG_NEXT_CMD_LEN:
+ result = get_user(val, (int *)arg);
+ if (result) return result;
+ sfp->next_cmd_len = (val > 0) ? val : 0;
+ return 0;
+ case SG_GET_VERSION_NUM:
+ return put_user(sg_version_num, (int *)arg);
case SG_EMULATED_HOST:
return put_user(sdp->device->host->hostt->emulated, (int *)arg);
case SCSI_IOCTL_SEND_COMMAND:
user already has read/write access to the generic device and so
can execute arbitrary SCSI commands. */
if (O_RDWR != (filp->f_flags & O_ACCMODE))
- return -EACCES; /* require write access since these could be
- dangerous */
+ return -EACCES; /* very dangerous things can be done here */
return scsi_ioctl_send_command(sdp->device, (void *)arg);
case SG_SET_DEBUG:
result = get_user(val, (int *)arg);
return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
default:
if (O_RDWR != (filp->f_flags & O_ACCMODE))
- return -EACCES; /* require write access since these could be
- dangerous */
+ return -EACCES; /* don't know so take safe approach */
return scsi_ioctl(sdp->device, cmd_in, (void *)arg);
}
}
}
/* This function is called by the interrupt handler when we
- * actually have a command that is complete. Change the
- * flags to indicate that we have a result. */
+ * actually have a command that is complete. */
static void sg_command_done(Scsi_Cmnd * SCpnt)
{
int dev = MINOR(SCpnt->request.rq_dev);
sg_clr_scpnt(SCpnt);
srp->my_cmdp = NULL;
- SCSI_LOG_TIMEOUT(4,
- printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n",
+ SCSI_LOG_TIMEOUT(4, printk("sg__done: dev=%d, scsi_stat=%d, res=0x%x\n",
dev, (int)status_byte(SCpnt->result), (int)SCpnt->result));
-/* See if the command completed normally, or whether something went wrong. */
memcpy(srp->header.sense_buffer, SCpnt->sense_buffer,
sizeof(SCpnt->sense_buffer));
switch (host_byte(SCpnt->result))
- {
+ { /* This setup of 'result' is for backward compatibility and is best
+ ignored by the user who should use target, host + driver status */
case DID_OK:
- case DID_PASSTHROUGH: /* just guessing */
- case DID_SOFT_ERROR: /* just guessing */
+ case DID_PASSTHROUGH:
+ case DID_SOFT_ERROR:
srp->header.result = 0;
break;
case DID_NO_CONNECT:
srp->header.result = EIO;
break;
case DID_ERROR:
- /* There really should be DID_UNDERRUN and DID_OVERRUN error values,
- * and a means for callers of scsi_do_cmd to indicate whether an
- * underrun or overrun should signal an error. Until that can be
- * implemented, this kludge allows for returning useful error values
- * except in cases that return DID_ERROR that might be due to an
- * underrun. */
if (SCpnt->sense_buffer[0] == 0 &&
status_byte(SCpnt->result) == GOOD)
srp->header.result = 0;
/* filesystems using this device. */
sdp->device->changed = 1;
}
-
-/* Pick up error and status information */
srp->header.target_status = status_byte(SCpnt->result);
if ((sdp->sgdebug > 0) &&
((CHECK_CONDITION == srp->header.target_status) ||
SCSI_LOG_TIMEOUT(1,
printk("sg__done: already closed, freeing ...\n"));
/* should check if module is unloaded <<<<<<< */
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
if (NULL == sfp->headrp) {
SCSI_LOG_TIMEOUT(1,
printk("sg__done: already closed, final cleanup\n"));
sg_remove_sfp(sdp, sfp);
}
}
-/* Now wake up the process that is waiting for the result. */
- /* A. Rubini says this is preferable+faster than wake_up() */
+/* Now wake up any sg_read() that is waiting for this packet. */
wake_up_interruptible(&sfp->read_wait);
if ((sfp->async_qp) && (! closed))
kill_fasync(sfp->async_qp, SIGPOLL);
printk(" *** Following data belongs to invoking FD ***\n");
else if (! fp->parentdp)
printk(">> Following FD has NULL parent pointer ???\n");
- printk(" FD(%d): timeout=%d, fb_size=%d, cmd_q=%d\n",
- k, fp->timeout, fp->fb_size, (int)fp->cmd_q);
- printk(" low_dma=%d, force_packid=%d, urun_flag=%d, closed=%d\n",
- (int)fp->low_dma, (int)fp->force_packid,
- (int)fp->underrun_flag, (int)fp->closed);
+ printk(" FD(%d): timeout=%d, bufflen=%d, use_sg=%d\n",
+ k, fp->timeout, fp->reserve.bufflen, (int)fp->reserve.use_sg);
+ printk(" low_dma=%d, cmd_q=%d, s_sc_len=%d, f_packid=%d\n",
+ (int)fp->low_dma, (int)fp->cmd_q, (int)fp->save_scat_len,
+ (int)fp->force_packid);
+ printk(" urun_flag=%d, next_cmd_len=%d, closed=%d\n",
+ (int)fp->underrun_flag, (int)fp->next_cmd_len,
+ (int)fp->closed);
srp = fp->headrp;
if (NULL == srp)
printk(" No requests active\n");
while (srp) {
- if (srp->fb_used)
- printk("using 1st buff >> ");
+ if (srp->res_used)
+ printk("reserved buff >> ");
else
printk(" ");
if (srp->my_cmdp)
SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
sdp->device = scsidp;
- sdp->generic_wait = NULL;
+ sdp->o_excl_wait = NULL;
sdp->headfp= NULL;
sdp->exclude = 0;
sdp->merge_fd = 0; /* Cope with SG_DEF_MERGE_FD on open */
}
scsidp->attached--;
sg_template.nr_dev--;
- /*
- * avoid associated device /dev/sg? bying incremented
- * each time module is inserted/removed , <dan@lectra.fr>
- */
+/* avoid associated device /dev/sg? being incremented
+ * each time module is inserted/removed , <dan@lectra.fr> */
sg_template.dev_noticed--;
return;
}
#endif
}
-static int sg_sc_build(Sg_request * srp, int max_buff_size,
- const char * inp, int num_write_xfer)
+static int sg_start_req(Sg_request * srp, int max_buff_size,
+ const char * inp, int num_write_xfer)
+{
+ int res;
+ Sg_fd * sfp = srp->parentfp;
+ Sg_scatter_hold * req_schp = &srp->data;
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_start_req: max_buff_size=%d\n",
+ max_buff_size));
+ if ((! sg_res_in_use(sfp)) && (max_buff_size <= rsv_schp->bufflen)) {
+ sg_link_reserve(sfp, srp, max_buff_size);
+ sg_write_xfer(req_schp, inp, num_write_xfer);
+ }
+ else {
+ res = sg_build_scat(req_schp, max_buff_size, sfp);
+ if (res) {
+ sg_remove_scat(req_schp);
+ return res;
+ }
+ sg_write_xfer(req_schp, inp, num_write_xfer);
+ }
+ return 0;
+}
+
+static void sg_finish_rem_req(Sg_request * srp, char * outp,
+ int num_read_xfer)
+{
+ Sg_fd * sfp = srp->parentfp;
+ Sg_scatter_hold * req_schp = &srp->data;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n",
+ (int)srp->res_used));
+ if (num_read_xfer > 0)
+ sg_read_xfer(req_schp, outp, num_read_xfer);
+ if (srp->res_used)
+ sg_unlink_reserve(sfp, srp);
+ else
+ sg_remove_scat(req_schp);
+ sg_remove_request(sfp, srp);
+}
+
+static int sg_build_scat(Sg_scatter_hold * schp, int buff_size,
+ const Sg_fd * sfp)
{
int ret_sz, mem_src;
- int blk_size = max_buff_size;
+ int blk_size = buff_size;
char * p = NULL;
- if ((blk_size < 0) || (! srp))
+ if ((blk_size < 0) || (! sfp))
return -EFAULT;
-
- SCSI_LOG_TIMEOUT(4, printk("sg_sc_build: m_b_s=%d, num_write_xfer=%d\n",
- max_buff_size, num_write_xfer));
if (0 == blk_size)
++blk_size; /* don't know why */
/* round request up to next highest SG_SECTOR_SZ byte boundary */
blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
- SCSI_LOG_TIMEOUT(5, printk("sg_sc_build: blk_size=%d\n", blk_size));
-
+ SCSI_LOG_TIMEOUT(4, printk("sg_build_scat: buff_size=%d, blk_size=%d\n",
+ buff_size, blk_size));
if (blk_size <= SG_SCATTER_SZ) {
- mem_src = SG_HEAP_FB;
- p = sg_malloc(srp, blk_size, &ret_sz, &mem_src);
+ mem_src = SG_HEAP_PAGE;
+ p = sg_malloc(sfp, blk_size, &ret_sz, &mem_src);
if (! p)
return -ENOMEM;
if (blk_size == ret_sz) { /* got it on the first attempt */
- srp->data.buffer = p;
- srp->data.bufflen = blk_size;
- srp->data.mem_src = mem_src;
- srp->data.b_malloc_len = blk_size;
- if (inp && (num_write_xfer > 0))
- __copy_from_user(srp->data.buffer, inp, num_write_xfer);
+ schp->use_sg = 0;
+ schp->buffer = p;
+ schp->bufflen = blk_size;
+ schp->mem_src = mem_src;
+ schp->b_malloc_len = blk_size;
return 0;
}
}
else {
mem_src = SG_HEAP_PAGE;
- p = sg_malloc(srp, SG_SCATTER_SZ, &ret_sz, &mem_src);
+ p = sg_malloc(sfp, SG_SCATTER_SZ, &ret_sz, &mem_src);
if (! p)
return -ENOMEM;
}
int k, rem_sz, num, nxt;
int sc_bufflen = PAGE_SIZE;
int mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1;
- int sg_tablesize = srp->parentfp->parentdp->sg_tablesize;
+ int sg_tablesize = sfp->parentdp->sg_tablesize;
int first = 1;
k = SG_HEAP_KMAL; /* want to protect mem_src, use k as scratch */
- srp->data.buffer = (struct scatterlist *)sg_malloc(srp,
+ schp->buffer = (struct scatterlist *)sg_malloc(sfp,
sc_bufflen, &num, &k);
- srp->data.mem_src = (char)k;
+ schp->mem_src = (char)k;
/* N.B. ret_sz and mem_src carried into this block ... */
- if (! srp->data.buffer)
+ if (! schp->buffer)
return -ENOMEM;
else if (num != sc_bufflen) {
sc_bufflen = num;
mx_sc_elems = (sc_bufflen / sizeof(struct scatterlist)) - 1;
}
- srp->data.sglist_len = sc_bufflen;
- memset(srp->data.buffer, 0, sc_bufflen);
- for (k = 0, sclp = srp->data.buffer, rem_sz = blk_size, nxt =0;
+ schp->sglist_len = sc_bufflen;
+ memset(schp->buffer, 0, sc_bufflen);
+ for (k = 0, sclp = schp->buffer, rem_sz = blk_size, nxt =0;
(k < sg_tablesize) && (rem_sz > 0) && (k < mx_sc_elems);
++k, rem_sz -= ret_sz, ++sclp) {
if (first)
else {
num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
mem_src = SG_HEAP_PAGE;
- p = sg_malloc(srp, num, &ret_sz, &mem_src);
+ p = sg_malloc(sfp, num, &ret_sz, &mem_src);
if (! p)
break;
}
sclp->length = ret_sz;
sclp->alt_address = (char *)(long)mem_src;
- if(inp && (num_write_xfer > 0)) {
- num = (ret_sz > num_write_xfer) ? num_write_xfer : ret_sz;
- __copy_from_user(sclp->address, inp, num);
- num_write_xfer -= num;
- inp += num;
- }
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_build: k=%d, a=0x%p, len=%d, ms=%d\n",
+ printk("sg_build_build: k=%d, a=0x%p, len=%d, ms=%d\n",
k, sclp->address, ret_sz, mem_src));
} /* end of for loop */
- srp->data.use_sg = k;
+ schp->use_sg = k;
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_build: use_sg=%d, rem_sz=%d\n", k, rem_sz));
- srp->data.bufflen = blk_size;
+ printk("sg_build_scat: use_sg=%d, rem_sz=%d\n", k, rem_sz));
+ schp->bufflen = blk_size;
if (rem_sz > 0) /* must have failed */
return -ENOMEM;
}
return 0;
}
-static int sg_sc_undo_rem(Sg_request * srp, char * outp,
- int num_read_xfer)
+static void sg_write_xfer(Sg_scatter_hold * schp, const char * inp,
+ int num_write_xfer)
{
- if (! srp)
- return -EFAULT;
- SCSI_LOG_TIMEOUT(4, printk("sg_sc_undo_rem: num_read_xfer=%d\n",
- num_read_xfer));
- if (! outp)
- num_read_xfer = 0;
- if(srp->data.use_sg) {
- int k, num, mem_src;
- struct scatterlist * sclp = (struct scatterlist *)srp->data.buffer;
-
- for (k = 0; (k < srp->data.use_sg) && sclp->address; ++k, ++sclp) {
- if (num_read_xfer > 0) {
- num = (int)sclp->length;
- if (num > num_read_xfer) {
- __copy_to_user(outp, sclp->address, num_read_xfer);
- outp += num_read_xfer;
- num_read_xfer = 0;
- }
- else {
- __copy_to_user(outp, sclp->address, num);
- outp += num;
- num_read_xfer -= num;
- }
+ SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_write_xfer=%d, use_sg=%d\n",
+ num_write_xfer, schp->use_sg));
+ if ((! inp) || (num_write_xfer <= 0))
+ return;
+ if (schp->use_sg > 0) {
+ int k, num;
+ struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+ for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
+ num = (int)sclp->length;
+ if (num > num_write_xfer) {
+ __copy_from_user(sclp->address, inp, num_write_xfer);
+ break;
}
+ else {
+ __copy_from_user(sclp->address, inp, num);
+ num_write_xfer -= num;
+ if (num_write_xfer <= 0)
+ break;
+ inp += num;
+ }
+ }
+ }
+ else
+ __copy_from_user(schp->buffer, inp, num_write_xfer);
+}
+
+static void sg_remove_scat(Sg_scatter_hold * schp)
+{
+ SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: use_sg=%d\n", schp->use_sg));
+ if(schp->use_sg > 0) {
+ int k, mem_src;
+ struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+ for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
mem_src = (int)(long)sclp->alt_address;
SCSI_LOG_TIMEOUT(5,
- printk("sg_sc_undo_rem: k=%d, a=0x%p, len=%d, ms=%d\n",
+ printk("sg_remove_scat: k=%d, a=0x%p, len=%d, ms=%d\n",
k, sclp->address, sclp->length, mem_src));
- sg_free(srp, sclp->address, sclp->length, mem_src);
+ sg_free(sclp->address, sclp->length, mem_src);
+ sclp->address = NULL;
+ sclp->length = 0;
}
- sg_free(srp, srp->data.buffer, srp->data.sglist_len,
- srp->data.mem_src);
+ sg_free(schp->buffer, schp->sglist_len, schp->mem_src);
+ }
+ else if (schp->buffer)
+ sg_free(schp->buffer, schp->b_malloc_len, schp->mem_src);
+ schp->buffer = NULL;
+ schp->bufflen = 0;
+ schp->use_sg = 0;
+ schp->sglist_len = 0;
+}
+
+static void sg_read_xfer(Sg_scatter_hold * schp, char * outp,
+ int num_read_xfer)
+{
+ SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_read_xfer=%d\n",
+ num_read_xfer));
+ if ((! outp) || (num_read_xfer <= 0))
+ return;
+ if(schp->use_sg > 0) {
+ int k, num;
+ struct scatterlist * sclp = (struct scatterlist *)schp->buffer;
+
+ for (k = 0; (k < schp->use_sg) && sclp->address; ++k, ++sclp) {
+ num = (int)sclp->length;
+ if (num > num_read_xfer) {
+ __copy_to_user(outp, sclp->address, num_read_xfer);
+ break;
+ }
+ else {
+ __copy_to_user(outp, sclp->address, num);
+ num_read_xfer -= num;
+ if (num_read_xfer <= 0)
+ break;
+ outp += num;
+ }
+ }
+ }
+ else
+ __copy_to_user(outp, schp->buffer, num_read_xfer);
+}
+
+static void sg_build_reserve(Sg_fd * sfp, int req_size)
+{
+ Sg_scatter_hold * schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size));
+ do {
+ if (req_size < PAGE_SIZE)
+ req_size = PAGE_SIZE;
+ if (0 == sg_build_scat(schp, req_size, sfp))
+ return;
+ else
+ sg_remove_scat(schp);
+ req_size >>= 1; /* divide by 2 */
+ } while (req_size > (PAGE_SIZE / 2));
+}
+
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
+{
+ Sg_scatter_hold * req_schp = &srp->data;
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
+ if (rsv_schp->use_sg > 0) {
+ int k, num;
+ int rem = size;
+ struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+ for (k = 0; k < rsv_schp->use_sg; ++k, ++sclp) {
+ num = (int)sclp->length;
+ if (rem <= num) {
+ sfp->save_scat_len = num;
+ sclp->length = (unsigned)rem;
+ break;
+ }
+ else
+ rem -= num;
+ }
+ if (k < rsv_schp->use_sg) {
+ req_schp->use_sg = k + 1; /* adjust scatter list length */
+ req_schp->bufflen = size;
+ req_schp->sglist_len = rsv_schp->sglist_len;
+ req_schp->buffer = rsv_schp->buffer;
+ req_schp->mem_src = rsv_schp->mem_src;
+ req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+ }
+ else
+ SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));
}
else {
- if (num_read_xfer > 0)
- __copy_to_user(outp, srp->data.buffer, num_read_xfer);
- sg_free(srp, srp->data.buffer, srp->data.b_malloc_len,
- srp->data.mem_src);
+ req_schp->use_sg = 0;
+ req_schp->bufflen = size;
+ req_schp->buffer = rsv_schp->buffer;
+ req_schp->mem_src = rsv_schp->mem_src;
+ req_schp->use_sg = rsv_schp->use_sg;
+ req_schp->b_malloc_len = rsv_schp->b_malloc_len;
}
- if (0 == sg_remove_request(srp->parentfp, srp)) {
- SCSI_LOG_TIMEOUT(1, printk("sg_sc_undo_rem: srp=0x%p not found\n",
- srp));
+ srp->res_used = 1;
+}
+
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
+{
+ Sg_scatter_hold * req_schp = &srp->data;
+ Sg_scatter_hold * rsv_schp = &sfp->reserve;
+
+ SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->use_sg=%d\n",
+ (int)req_schp->use_sg));
+ if (rsv_schp->use_sg > 0) {
+ struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
+
+ if (sfp->save_scat_len > 0)
+ (sclp + (req_schp->use_sg - 1))->length =
+ (unsigned)sfp->save_scat_len;
+ else
+ SCSI_LOG_TIMEOUT(1, printk(
+ "sg_unlink_reserve: BAD save_scat_len\n"));
}
- return 0;
+ req_schp->use_sg = 0;
+ req_schp->bufflen = 0;
+ req_schp->buffer = NULL;
+ req_schp->sglist_len = 0;
+ sfp->save_scat_len = 0;
+ srp->res_used = 0;
}
static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id)
if (resp) {
resp->parentfp = sfp;
resp->nextrp = NULL;
- resp->fb_used = 0;
+ resp->res_used = 0;
memset(&resp->data, 0, sizeof(Sg_scatter_hold));
memset(&resp->header, 0, sizeof(struct sg_header));
resp->my_cmdp = NULL;
sdp->device->host->unchecked_isa_dma : 1;
sfp->cmd_q = SG_DEF_COMMAND_Q;
sfp->underrun_flag = SG_DEF_UNDERRUN_FLAG;
- if (get_reserved)
- sfp->fst_buf = sg_low_malloc(SG_SCATTER_SZ, sfp->low_dma,
- SG_HEAP_PAGE, &sfp->fb_size);
- else
- sfp->fst_buf = NULL;
- if (! sfp->fst_buf)
- sfp->fb_size = 0;
sfp->parentdp = sdp;
if (! sdp->headfp)
sdp->headfp = sfp;
pfp = pfp->nextfp;
pfp->nextfp = sfp;
}
- sg_big_buff = sfp->fb_size; /* show sysctl most recent "fb" size */
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n",
sfp, (int)sfp->my_mem_src));
- SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: fb_sz=%d, fst_buf=0x%p\n",
- sfp->fb_size, sfp->fst_buf));
+ if (get_reserved) {
+ sg_build_reserve(sfp, SG_DEF_RESERVED_SIZE);
+ sg_big_buff = sfp->reserve.bufflen; /* sysctl shows most recent size */
+ SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, use_sg=%d\n",
+ sfp->reserve.bufflen, sfp->reserve.use_sg));
+ }
return sfp;
}
while (srp) {
tsrp = srp->nextrp;
if (! srp->my_cmdp)
- sg_sc_undo_rem(srp, NULL, 0);
+ sg_finish_rem_req(srp, NULL, 0);
else
++dirty;
srp = tsrp;
prev_fp = fp;
}
}
-SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: fb_sz=%d, fst_buf=0x%p\n",
- sfp->fb_size, sfp->fst_buf));
- sg_low_free(sfp->fst_buf, sfp->fb_size, SG_HEAP_PAGE);
+ if (sfp->reserve.bufflen > 0) {
+SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, use_sg=%d\n",
+ (int)sfp->reserve.bufflen, (int)sfp->reserve.use_sg));
+ sg_remove_scat(&sfp->reserve);
+ }
sfp->parentdp = NULL;
- sfp->fst_buf = NULL;
- sfp->fb_size = 0;
SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp));
sg_low_free((char *)sfp, sizeof(Sg_fd), sfp->my_mem_src);
res = 1;
return res;
}
-static int sg_fb_in_use(const Sg_fd * sfp)
+static int sg_res_in_use(const Sg_fd * sfp)
{
const Sg_request * srp = sfp->headrp;
while (srp) {
- if (srp->fb_used)
+ if (srp->res_used)
return 1;
srp = srp->nextrp;
}
return resp;
}
-static char * sg_malloc(Sg_request * srp, int size, int * retSzp,
+static char * sg_malloc(const Sg_fd * sfp, int size, int * retSzp,
int * mem_srcp)
{
char * resp = NULL;
if (size <= 0)
;
else {
- Sg_fd * sfp = srp->parentfp;
int low_dma = sfp->low_dma;
int l_ms = -1; /* invalid value */
switch (*mem_srcp)
{
case SG_HEAP_PAGE:
- case SG_HEAP_FB:
l_ms = (size < PAGE_SIZE) ? SG_HEAP_POOL : SG_HEAP_PAGE;
resp = sg_low_malloc(size, low_dma, l_ms, 0);
if (resp)
break;
- if ((size <= sfp->fb_size) && (0 == sg_fb_in_use(sfp))) {
- SCSI_LOG_TIMEOUT(6,
- printk("sg_malloc: scsi_malloc failed, get fst_buf\n"));
- resp = sfp->fst_buf;
- srp->fb_used = 1;
- l_ms = SG_HEAP_FB;
- break;
- }
resp = sg_low_malloc(size, low_dma, l_ms, &size);
if (! resp) {
l_ms = (SG_HEAP_POOL == l_ms) ? SG_HEAP_PAGE : SG_HEAP_POOL;
mem_src, buff, size);
}
-static void sg_free(Sg_request * srp, char * buff, int size, int mem_src)
+static void sg_free(char * buff, int size, int mem_src)
{
- Sg_fd * sfp = srp->parentfp;
-
SCSI_LOG_TIMEOUT(6,
printk("sg_free: buff=0x%p, size=%d\n", buff, size));
- if ((! sfp) || (! buff) || (size <= 0))
+ if ((! buff) || (size <= 0))
;
- else if (sfp->fst_buf == buff) {
- srp->fb_used = 0;
- SCSI_LOG_TIMEOUT(6, printk("sg_free: left cause fst_buf\n"));
- }
else
sg_low_free(buff, size, mem_src);
}
fi
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate 'NFS server support' CONFIG_NFSD
- fi
- if [ "$CONFIG_NFSD" != "n" ]; then
- bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
+ if [ "$CONFIG_NFSD" != "n" ]; then
+ bool ' Emulate SUN NFS server' CONFIG_NFSD_SUN
+ fi
fi
if [ "$CONFIG_NFS_FS" = "y" -o "$CONFIG_NFSD" = "y" ]; then
define_bool CONFIG_SUNRPC y
sb->s_dev = 0;
coda_cache_clear_all(sb);
sb_info = coda_sbp(sb);
- sb_info->sbi_vcomm->vc_inuse = 0;
+/* sb_info->sbi_vcomm->vc_inuse = 0; You can not do this: psdev_release would see usagecount == 0 and would refuse to decrease MOD_USE_COUNT --pavel */
coda_super_info.sbi_sb = NULL;
printk("Coda: Bye bye.\n");
memset(sb_info, 0, sizeof(* sb_info));
out_error:
clear_bit(PG_locked, &page->flags);
+ wake_up(&page->wait);
out_free:
free_page(page_address(page));
out:
#ifndef _ALPHA_INIT_H
#define _ALPHA_INIT_H
+#ifndef MODULE
#define __init __attribute__ ((__section__ (".text.init")))
#define __initdata __attribute__ ((__section__ (".data.init")))
#define __initfunc(__arginit) \
#define __INIT .section .text.init,"ax"
#define __FINIT .previous
#define __INITDATA .section .data.init,"a"
+#endif
#define __cacheline_aligned __attribute__((__aligned__(32)))
*/
static inline void __set_hae(unsigned long new_hae)
{
- unsigned long ipl = swpipl(7);
+ unsigned long flags;
+ __save_and_cli(flags);
alpha_mv.hae_cache = new_hae;
*alpha_mv.hae_register = new_hae;
mb();
-
/* Re-read to make sure it was written. */
new_hae = *alpha_mv.hae_register;
- setipl(ipl);
+
+ __restore_flags(flags);
}
static inline void set_hae(unsigned long new_hae)
if (mm) {
unsigned long asn = asn_cache;
/* Check if our ASN is of an older version,
- or on a different CPU, and thus invalid */
+ or on a different CPU, and thus invalid. */
if ((mm->context ^ asn) & ~HARDWARE_ASN_MASK)
get_new_mmu_context(p, mm);
}
unsigned long ld_lock; /* Contents of EV5 LD_LOCK register*/
};
-
-extern void wrent(void *, unsigned long);
-extern void wrkgp(unsigned long);
-extern void wrusp(unsigned long);
-extern unsigned long rdusp(void);
-extern unsigned long rdmces (void);
-extern void wrmces (unsigned long);
-extern unsigned long whami(void);
-extern void wripir(unsigned long);
-
extern void halt(void) __attribute__((noreturn));
#define switch_to(prev,next,last) \
AMASK_PRECISE_TRAP = (1UL << 9),
};
-enum amask_enum {
- AMASK_BWX = (1UL << 0),
- AMASK_FIX = (1UL << 1),
- AMASK_MAX = (1UL << 8),
- AMASK_PRECISE_TRAP = (1UL << 9),
-};
-
#define amask(mask) \
({ unsigned long __amask, __input = (mask); \
__asm__ ("amask %1,%0" : "=r"(__amask) : "rI"(__input)); \
__amask; })
-static inline unsigned long
-wrperfmon(unsigned long perf_fun, unsigned long arg)
-{
- register unsigned long __r0 __asm__("$0");
- register unsigned long __r16 __asm__("$16");
- register unsigned long __r17 __asm__("$17");
- __r16 = perf_fun;
- __r17 = arg;
- __asm__ __volatile__(
- "call_pal %1"
- : "=r"(__r0)
- : "i"(PAL_wrperfmon), "r"(__r16), "r"(__r17)
- : "$1", "$22", "$23", "$24", "$25", "$26");
- return __r0;
+#define __CALL_PAL_R0(NAME, TYPE) \
+static inline TYPE NAME(void) \
+{ \
+ register TYPE __r0 __asm__("$0"); \
+ __asm__ __volatile__( \
+ "call_pal %1 # " #NAME \
+ :"=r" (__r0) \
+ :"i" (PAL_ ## NAME) \
+ :"$1", "$16", "$22", "$23", "$24", "$25"); \
+ return __r0; \
}
+#define __CALL_PAL_W1(NAME, TYPE0) \
+static inline void NAME(TYPE0 arg0) \
+{ \
+ register TYPE0 __r16 __asm__("$16") = arg0; \
+ __asm__ __volatile__( \
+ "call_pal %1 # "#NAME \
+ : "=r"(__r16) \
+ : "i"(PAL_ ## NAME), "0"(__r16) \
+ : "$1", "$22", "$23", "$24", "$25"); \
+}
-#define call_pal1(palno,arg) \
-({ \
- register unsigned long __r0 __asm__("$0"); \
- register unsigned long __r16 __asm__("$16"); __r16 = arg; \
- __asm__ __volatile__( \
- "call_pal %3 #call_pal1" \
- :"=r" (__r0),"=r" (__r16) \
- :"1" (__r16),"i" (palno) \
- :"$1", "$22", "$23", "$24", "$25", "memory"); \
- __r0; \
-})
-
-#define getipl() \
-({ \
- register unsigned long r0 __asm__("$0"); \
- __asm__ __volatile__( \
- "call_pal %1 #getipl" \
- :"=r" (r0) \
- :"i" (PAL_rdps) \
- :"$1", "$16", "$22", "$23", "$24", "$25", "memory"); \
- r0; \
-})
+#define __CALL_PAL_W2(NAME, TYPE0, TYPE1) \
+static inline void NAME(TYPE0 arg0, TYPE1 arg1) \
+{ \
+ register TYPE0 __r16 __asm__("$16") = arg0; \
+ register TYPE1 __r17 __asm__("$17") = arg1; \
+ __asm__ __volatile__( \
+ "call_pal %2 # "#NAME \
+ : "=r"(__r16), "=r"(__r17) \
+ : "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17) \
+ : "$1", "$22", "$23", "$24", "$25"); \
+}
-#define setipl(ipl) \
-({ \
- register unsigned long __r16 __asm__("$16"); __r16 = (ipl); \
- __asm__ __volatile__( \
- "call_pal %2 #setipl" \
- :"=r" (__r16) \
- :"0" (__r16),"i" (PAL_swpipl) \
- :"$0", "$1", "$22", "$23", "$24", "$25", "memory"); \
-})
+#define __CALL_PAL_RW1(NAME, RTYPE, TYPE0) \
+static inline RTYPE NAME(TYPE0 arg0) \
+{ \
+ register RTYPE __r0 __asm__("$0"); \
+ register TYPE0 __r16 __asm__("$16") = arg0; \
+ __asm__ __volatile__( \
+ "call_pal %2 # "#NAME \
+ : "=r"(__r16), "=r"(__r0) \
+ : "i"(PAL_ ## NAME), "0"(__r16) \
+ : "$1", "$22", "$23", "$24", "$25"); \
+ return __r0; \
+}
-#define swpipl(ipl) \
-({ \
- register unsigned long __r0 __asm__("$0"); \
- register unsigned long __r16 __asm__("$16") = (ipl); \
+#define __CALL_PAL_RW2(NAME, RTYPE, TYPE0, TYPE1) \
+static inline RTYPE NAME(TYPE0 arg0, TYPE1 arg1) \
+{ \
+ register RTYPE __r0 __asm__("$0"); \
+ register TYPE0 __r16 __asm__("$16") = arg0; \
+ register TYPE1 __r17 __asm__("$17") = arg1; \
__asm__ __volatile__( \
- "call_pal %3 #swpipl" \
- :"=r" (__r0),"=r" (__r16) \
- :"1" (__r16),"i" (PAL_swpipl) \
- :"$1", "$22", "$23", "$24", "$25", "memory"); \
- __r0; \
-})
+ "call_pal %3 # "#NAME \
+ : "=r"(__r16), "=r"(__r17), "=r"(__r0) \
+ : "i"(PAL_ ## NAME), "0"(__r16), "1"(__r17) \
+ : "$1", "$22", "$23", "$24", "$25"); \
+ return __r0; \
+}
-#define __cli() setipl(7)
-#define __sti() setipl(0)
-#define __save_flags(flags) ((flags) = getipl())
+__CALL_PAL_R0(rdmces, unsigned long);
+__CALL_PAL_R0(rdps, unsigned long);
+__CALL_PAL_R0(rdusp, unsigned long);
+__CALL_PAL_RW1(swpipl, unsigned long, unsigned long);
+__CALL_PAL_R0(whami, unsigned long);
+__CALL_PAL_W2(wrent, void*, unsigned long);
+__CALL_PAL_W1(wripir, unsigned long);
+__CALL_PAL_W1(wrkgp, unsigned long);
+__CALL_PAL_W1(wrmces, unsigned long);
+__CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long);
+__CALL_PAL_W1(wrusp, unsigned long);
+__CALL_PAL_W1(wrvptptr, unsigned long);
+
+#define __cli() ((void) swpipl(7))
+#define __sti() ((void) swpipl(0))
+#define __save_flags(flags) ((flags) = rdps())
#define __save_and_cli(flags) ((flags) = swpipl(7))
-#define __restore_flags(flags) setipl(flags)
+#define __restore_flags(flags) ((void) swpipl(flags))
#ifdef __SMP__
__initfunc(static void check_cyrix_coma(void))
{
if (boot_cpu_data.coma_bug) {
- unsigned char ccr1;
+ unsigned char ccr3, tmp;
cli();
- ccr1 = getCx86 (CX86_CCR1);
- setCx86 (CX86_CCR1, ccr1 | 0x10);
+ ccr3 = getCx86(CX86_CCR3);
+ setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */
+ tmp = getCx86(0x31);
+ setCx86(0x31, tmp | 0xf8);
+ tmp = getCx86(0x32);
+ setCx86(0x32, tmp | 0x7f);
+ setCx86(0x33, 0);
+ tmp = getCx86(0x3c);
+ setCx86(0x3c, tmp | 0x87);
+ setCx86(CX86_CCR3, ccr3); /* disable MAPEN */
sti();
printk("Cyrix processor with \"coma bug\" found, workaround enabled\n");
}
#define PCI_VENDOR_ID_ADAPTEC 0x9004
#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078
+#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178
#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078
#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578
#define PCI_DEVICE_ID_ADAPTEC_5800 0x5800
+#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038
#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075
#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078
#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178
#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278
#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378
#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478
+#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578
+#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678
+#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778
+#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878
#define PCI_DEVICE_ID_ADAPTEC_1030 0x8b78
#define PCI_VENDOR_ID_ADAPTEC2 0x9005
#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010
-#define PCI_DEVICE_ID_ADAPTEC2_78902 0x0013
+#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011
+#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013
#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f
#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050
#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051
#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f
+#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080
+#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081
+#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083
+#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f
+#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0
+#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1
+#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3
+#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf
#define PCI_VENDOR_ID_ATRONICS 0x907f
#define PCI_DEVICE_ID_ATRONICS_2015 0x2015
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
+ * ==FILEDATE 19990523==
+ *
* Copyright (C) 1998 by Microgate Corporation
*
* Redistribution of this file is permitted under
#define HDLC_FLAG_AUTO_RTS 0x0080
#define HDLC_FLAG_RXC_DPLL 0x0100
#define HDLC_FLAG_RXC_BRG 0x0200
+#define HDLC_FLAG_RXC_TXCPIN 0x8000
+#define HDLC_FLAG_RXC_RXCPIN 0x0000
#define HDLC_FLAG_TXC_DPLL 0x0400
#define HDLC_FLAG_TXC_BRG 0x0800
+#define HDLC_FLAG_TXC_TXCPIN 0x0000
+#define HDLC_FLAG_TXC_RXCPIN 0x0008
#define HDLC_FLAG_DPLL_DIV8 0x1000
#define HDLC_FLAG_DPLL_DIV16 0x2000
#define HDLC_FLAG_DPLL_DIV32 0x0000
+#define HDLC_FLAG_HDLC_LOOPMODE 0x4000
#define HDLC_CRC_NONE 0
#define HDLC_CRC_16_CCITT 1
#define HDLC_ENCODING_NRZB 1
#define HDLC_ENCODING_NRZI_MARK 2
#define HDLC_ENCODING_NRZI_SPACE 3
+#define HDLC_ENCODING_NRZI HDLC_ENCODING_NRZI_SPACE
#define HDLC_ENCODING_BIPHASE_MARK 4
#define HDLC_ENCODING_BIPHASE_SPACE 5
#define HDLC_ENCODING_BIPHASE_LEVEL 6
* MGSL_IOCTXABORT abort transmitting frame (HDLC)
* MGSL_IOCGSTATS return current statistics
* MGSL_IOCWAITEVENT wait for specified event to occur
+ * MGSL_LOOPTXDONE transmit in HDLC LoopMode done
*/
#define MGSL_MAGIC_IOC 'm'
-#define MGSL_IOCSPARAMS _IOW(MGSL_MAGIC_IOC,0,sizeof(MGSL_PARAMS))
-#define MGSL_IOCGPARAMS _IOR(MGSL_MAGIC_IOC,1,sizeof(MGSL_PARAMS))
+#define MGSL_IOCSPARAMS _IOW(MGSL_MAGIC_IOC,0,struct _MGSL_PARAMS)
+#define MGSL_IOCGPARAMS _IOR(MGSL_MAGIC_IOC,1,struct _MGSL_PARAMS)
#define MGSL_IOCSTXIDLE _IO(MGSL_MAGIC_IOC,2)
#define MGSL_IOCGTXIDLE _IO(MGSL_MAGIC_IOC,3)
#define MGSL_IOCTXENABLE _IO(MGSL_MAGIC_IOC,4)
#define MGSL_IOCRXENABLE _IO(MGSL_MAGIC_IOC,5)
#define MGSL_IOCTXABORT _IO(MGSL_MAGIC_IOC,6)
#define MGSL_IOCGSTATS _IO(MGSL_MAGIC_IOC,7)
-#define MGSL_IOCWAITEVENT _IO(MGSL_MAGIC_IOC,8)
+#define MGSL_IOCWAITEVENT _IOWR(MGSL_MAGIC_IOC,8,int)
#define MGSL_IOCCLRMODCOUNT _IO(MGSL_MAGIC_IOC,15)
+#define MGSL_IOCLOOPTXDONE _IO(MGSL_MAGIC_IOC,9)
#endif /* _SYNCLINK_H_ */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Wed Oct 21 22:47:12 1998
- * Modified at: Mon May 10 14:51:06 1999
+ * Modified at: Sun May 16 13:40:03 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
ACTISYS_PLUS_DONGLE,
GIRBIL_DONGLE,
LITELINK_DONGLE,
-} DONGLE_T;
+} IRDA_DONGLE;
struct irda_device;
struct dongle {
- DONGLE_T type;
+ IRDA_DONGLE type;
void (*open)(struct irda_device *, int type);
void (*close)(struct irda_device *);
- void (*reset)( struct irda_device *, int unused);
+ void (*reset)( struct irda_device *);
void (*change_speed)( struct irda_device *, int baudrate);
void (*qos_init)( struct irda_device *, struct qos_info *);
};
#define IRCOMM_MAGIC 0x434f4d4d
#define COMM_INIT_CTRL_PARAM 3 /* length of initial control parameters */
-#define COMM_HEADER 1 /* length of clen field */
-#define COMM_HEADER_SIZE (TTP_MAX_HEADER+COMM_HEADER)
-#define COMM_DEFAULT_DATA_SIZE 64
+#define COMM_HEADER_SIZE 1 /* length of clen field */
+#define COMM_MAX_HEADER_SIZE (TTP_MAX_HEADER+COMM_HEADER_SIZE)
+#define COMM_DEFAULT_SDU_SIZE (64 - COMM_HEADER_SIZE)
#define IRCOMM_MAX_CONNECTION 1 /* Don't change for now */
int null_modem_mode; /* switch for null modem emulation */
int ttp_stop;
- int max_txbuff_size;
- __u32 max_sdu_size;
+ __u32 tx_max_sdu_size;
+ __u32 rx_max_sdu_size;
__u8 max_header_size;
__u32 daddr; /* Device address of the peer device */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Apr 14 12:41:42 1998
- * Modified at: Mon May 10 15:46:02 1999
+ * Modified at: Wed May 19 08:44:48 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
struct dongle *dongle; /* Dongle driver */
- /* spinlock_t lock; */ /* For serializing operations */
+ spinlock_t lock; /* For serializing operations */
/* Media busy stuff */
int media_busy;
struct timer_list media_busy_timer;
/* Callbacks for driver specific implementation */
- void (*change_speed)(struct irda_device *driver, int baud);
+ void (*change_speed)(struct irda_device *idev, int baud);
int (*is_receiving)(struct irda_device *); /* receiving? */
void (*set_dtr_rts)(struct irda_device *idev, int dtr, int rts);
int (*raw_write)(struct irda_device *idev, __u8 *buf, int len);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun May 9 11:45:33 1999
+ * Modified at: Mon May 31 13:54:20 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
int unicast_open;
int broadcast_open;
+ int tx_busy;
+ struct sk_buff_head txq; /* Transmit control queue */
+
struct timer_list kick_timer;
};
struct device dev; /* Ethernet device structure*/
struct enet_statistics stats;
- __u32 saddr; /* Source devcie address */
+ __u32 saddr; /* Source device address */
__u32 daddr; /* Destination device address */
int netdev_registered;
int notify_irmanager;
void irlan_open_data_tsap(struct irlan_cb *self);
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self);
+
void irlan_get_provider_info(struct irlan_cb *self);
void irlan_get_unicast_addr(struct irlan_cb *self);
void irlan_get_media_char(struct irlan_cb *self);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Oct 15 08:36:58 1998
- * Modified at: Thu Apr 22 14:09:37 1999
+ * Modified at: Fri May 14 23:29:00 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998 Dag Brattli, All Rights Reserved.
+ * Copyright (c) 1998-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
int irlan_eth_xmit(struct sk_buff *skb, struct device *dev);
void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow);
+void irlan_eth_send_gratuitous_arp(struct device *dev);
void irlan_eth_set_multicast_list( struct device *dev);
struct enet_statistics *irlan_eth_get_stats(struct device *dev);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 3 13:49:59 1997
- * Modified at: Mon May 10 22:12:56 1999
+ * Modified at: Wed May 19 15:31:16 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1998-1999 Dag Brattli <dagb@cs.uit.no>
#define FRAME_MAX_SIZE 2048
-void irport_start(int iobase);
-void irport_stop(int iobase);
+void irport_start(struct irda_device *idev, int iobase);
+void irport_stop(struct irda_device *idev, int iobase);
int irport_probe(int iobase);
void irport_change_speed(struct irda_device *idev, int speed);
void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
int irport_hard_xmit(struct sk_buff *skb, struct device *dev);
+void irport_wait_until_sent(struct irda_device *idev);
#endif
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Jun 9 13:26:50 1998
- * Modified at: Thu Feb 25 20:34:21 1999
+ * Modified at: Tue May 25 07:54:41 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (C) 1998, Aage Kvalnes <aage@cs.uit.no>
#include <linux/types.h>
#include <asm/spinlock.h>
-/* #include <net/irda/irda.h> */
-
#ifndef QUEUE_H
#define QUEUE_H
struct sk_buff_head rxbuff;
struct ircomm_cb *comm; /* ircomm instance */
+ __u32 tx_max_sdu_size;
+ __u32 max_header_size;
/*
* These members are used for compatibility with usual serial device.
* See linux/serial.h
struct wait_queue *delta_msr_wait;
struct wait_queue *tx_wait;
- struct timer_list timer;
+ struct timer_list tx_timer;
+ struct timer_list rx_timer;
long pgrp;
long session;
--- /dev/null
+/*********************************************************************
+ *
+ * Filename: smc.h
+ * Version:
+ * Description:
+ * Status: Experimental.
+ * Author: Thomas Davis (tadavis@jps.net)
+ *
+ * Copyright (c) 1998, 1999 Thomas Davis (tadavis@jps.net>
+ * 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.
+ *
+ * I, Thomas Davis, admit no liability nor provide warranty for any
+ * of this software. This material is provided "AS-IS" and at no charge.
+ *
+ * Definitions for the SMC IrCC controller.
+ *
+ ********************************************************************/
+
+#ifndef SMC_IRCC_H
+#define SMC_IRCC_H
+
+#define UART_MASTER 0x07
+#define UART_MASTER_POWERDOWN 1<<7
+#define UART_MASTER_RESET 1<<6
+#define UART_MASTER_INT_EN 1<<5
+#define UART_MASTER_ERROR_RESET 1<<4
+
+/* Register block 0 */
+
+#define UART_IIR 0x01
+#define UART_IER 0x02
+#define UART_LSR 0x03
+#define UART_LCR_A 0x04
+#define UART_LCR_B 0x05
+#define UART_BSR 0x06
+
+#define UART_IIR_ACTIVE_FRAME 1<<7
+#define UART_IIR_EOM 1<<6
+#define UART_IIR_RAW_MODE 1<<5
+#define UART_IIR_FIFO 1<<4
+
+#define UART_IER_ACTIVE_FRAME 1<<7
+#define UART_IER_EOM 1<<6
+#define UART_IER_RAW_MODE 1<<5
+#define UART_IER_FIFO 1<<4
+
+#define UART_LSR_UNDERRUN 1<<7
+#define UART_LSR_OVERRUN 1<<6
+#define UART_LSR_FRAME_ERROR 1<<5
+#define UART_LSR_SIZE_ERROR 1<<4
+#define UART_LSR_CRC_ERROR 1<<3
+#define UART_LSR_FRAME_ABORT 1<<2
+
+#define UART_LCR_A_FIFO_RESET 1<<7
+#define UART_LCR_A_FAST 1<<6
+#define UART_LCR_A_GP_DATA 1<<5
+#define UART_LCR_A_RAW_TX 1<<4
+#define UART_LCR_A_RAW_RX 1<<3
+#define UART_LCR_A_ABORT 1<<2
+#define UART_LCR_A_DATA_DONE 1<<1
+
+#define UART_LCR_B_SCE_DISABLED 0x00<<6
+#define UART_LCR_B_SCE_TRANSMIT 0x01<<6
+#define UART_LCR_B_SCE_RECEIVE 0x02<<6
+#define UART_LCR_B_SCE_UNDEFINED 0x03<<6
+#define UART_LCR_B_SIP_ENABLE 1<<5
+#define UART_LCR_B_BRICK_WALL 1<<4
+
+#define UART_BSR_NOT_EMPTY 1<<7
+#define UART_BSR_FIFO_FULL 1<<6
+#define UART_BSR_TIMEOUT 1<<5
+
+/* Register block 1 */
+
+#define UART_SCE_CFGA 0x00
+#define UART_SCE_CFGB 0x01
+#define UART_FIFO_THRESHOLD 0x02
+
+#define UART_CFGA_AUX_IR 0x01<<7
+#define UART_CFGA_HALF_DUPLEX 0x01<<2
+#define UART_CFGA_TX_POLARITY 0x01<<1
+#define UART_CFGA_RX_POLARITY 0x01
+
+#define UART_CFGA_COM 0x00<<3
+#define UART_CFGA_IRDA_SIR_A 0x01<<3
+#define UART_CFGA_ASK_SIR 0x02<<3
+#define UART_CFGA_IRDA_SIR_B 0x03<<3
+#define UART_CFGA_IRDA_HDLC 0x04<<3
+#define UART_CFGA_IRDA_4PPM 0x05<<3
+#define UART_CFGA_CONSUMER 0x06<<3
+#define UART_CFGA_RAW_IR 0x07<<3
+#define UART_CFGA_OTHER 0x08<<3
+
+#define UART_IR_HDLC 0x04
+#define UART_IR_4PPM 0x01
+#define UART_IR_CONSUMER 0x02
+
+#define UART_CFGB_LOOPBACK 0x01<<5
+#define UART_CFGB_LPBCK_TX_CRC 0x01<<4
+#define UART_CFGB_NOWAIT 0x01<<3
+#define UART_CFGB_STRING_MOVE 0x01<<2
+#define UART_CFGB_DMA_BURST 0x01<<1
+#define UART_CFGB_DMA_ENABLE 0x01
+
+#define UART_CFGB_COM 0x00<<6
+#define UART_CFGB_IR 0x01<<6
+#define UART_CFGB_AUX 0x02<<6
+#define UART_CFGB_INACTIVE 0x03<<6
+
+/* Register block 2 - Consumer IR - not used */
+
+/* Register block 3 - Identification Registers! */
+
+#define UART_ID_HIGH 0x00 /* 0x10 */
+#define UART_ID_LOW 0x01 /* 0xB8 */
+#define UART_CHIP_ID 0x02 /* 0xF1 */
+#define UART_VERSION 0x03 /* 0x01 */
+#define UART_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
+
+/* Register block 4 - IrDA */
+#define UART_CONTROL 0x00
+#define UART_BOF_COUNT_LO 0x01
+#define UART_BRICKWALL_CNT_LO 0x02
+#define UART_BRICKWALL_TX_CNT_HI 0x03
+#define UART_TX_SIZE_LO 0x04
+#define UART_RX_SIZE_HI 0x05
+#define UART_RX_SIZE_LO 0x06
+
+#define UART_1152 0x01<<7
+#define UART_CRC 0x01<<6
+
+/* For storing entries in the status FIFO */
+struct st_fifo_entry {
+ int status;
+ int len;
+};
+
+struct st_fifo {
+ struct st_fifo_entry entries[10];
+ int head;
+ int tail;
+ int len;
+};
+
+/* Private data for each instance */
+struct ircc_cb {
+ struct st_fifo st_fifo;
+
+ int tx_buff_offsets[10]; /* Offsets between frames in tx_buff */
+ int tx_len; /* Number of frames in tx_buff */
+
+ struct irda_device idev;
+};
+
+#endif
+++ /dev/null
-#if 0
-static char *rcsid = "$Id: smc_ircc.h,v 1.5 1998/07/27 01:25:29 ratbert Exp $";
-#endif
-
-#ifndef SMC_IRCC_H
-#define SMC_IRCC_H
-
-#define FIR_XMIT 1
-#define FIR_RECEIVE 2
-#define SIR_XMIT 3
-#define SIR_RECEIVE 4
-
-#define MASTER 0x07
-#define MASTER_POWERDOWN 1<<7
-#define MASTER_RESET 1<<6
-#define MASTER_INT_EN 1<<5
-#define MASTER_ERROR_RESET 1<<4
-
-/* Register block 0 */
-
-#define IIR 0x01
-#define IER 0x02
-#define LSR 0x03
-#define LCR_A 0x04
-#define LCR_B 0x05
-#define BSR 0x06
-
-#define IIR_ACTIVE_FRAME 1<<7
-#define IIR_EOM 1<<6
-#define IIR_RAW_MODE 1<<5
-#define IIR_FIFO 1<<4
-
-#define IER_ACTIVE_FRAME 1<<7
-#define IER_EOM 1<<6
-#define IER_RAW_MODE 1<<5
-#define IER_FIFO 1<<4
-
-#define LSR_UNDER_RUN 1<<7
-#define LSR_OVER_RUN 1<<6
-#define LSR_FRAME_ERROR 1<<5
-#define LSR_SIZE_ERROR 1<<4
-#define LSR_CRC_ERROR 1<<3
-#define LSR_FRAME_ABORT 1<<2
-
-#define LCR_A_FIFO_RESET 1<<7
-#define LCR_A_FAST 1<<6
-#define LCR_A_GP_DATA 1<<5
-#define LCR_A_RAW_TX 1<<4
-#define LCR_A_RAW_RX 1<<3
-#define LCR_A_ABORT 1<<2
-#define LCR_A_DATA_DONE 1<<1
-
-#define LCR_B_SCE_MODE_DISABLED 0x00<<6
-#define LCR_B_SCE_MODE_TRANSMIT 0x01<<6
-#define LCR_B_SCE_MODE_RECEIVE 0x02<<6
-#define LCR_B_SCE_MODE_UNDEFINED 0x03<<6
-#define LCR_B_SIP_ENABLE 1<<5
-#define LCR_B_BRICK_WALL 1<<4
-
-#define BSR_NOT_EMPTY 1<<7
-#define BSR_FIFO_FULL 1<<6
-#define BSR_TIMEOUT 1<<5
-
-/* Register block 1 */
-
-#define SCE_CFG_A 0x00
-#define SCE_CFG_B 0x01
-#define FIFO_THRESHOLD 0x02
-
-#define CFG_A_AUX_IR 0x01<<7
-#define CFG_A_HALF_DUPLEX 0x01<<2
-#define CFG_A_TX_POLARITY 0x01<<1
-#define CFG_A_RX_POLARITY 0x01
-
-#define CFG_A_COM 0x00<<3
-#define CFG_A_IRDA_SIR_A 0x01<<3
-#define CFG_A_ASK_SIR 0x02<<3
-#define CFG_A_IRDA_SIR_B 0x03<<3
-#define CFG_A_IRDA_HDLC 0x04<<3
-#define CFG_A_IRDA_4PPM 0x05<<3
-#define CFG_A_CONSUMER 0x06<<3
-#define CFG_A_RAW_IR 0x07<<3
-#define CFG_A_OTHER 0x08<<3
-
-#define IR_HDLC 0x04
-#define IR_4PPM 0x01
-#define IR_CONSUMER 0x02
-
-#define CFG_B_LOOPBACK 0x01<<5
-#define CFG_B_LPBCK_TX_CRC 0x01<<4
-#define CFG_B_NOWAIT 0x01<<3
-#define CFB_B_STRING_MOVE 0x01<<2
-#define CFG_B_DMA_BURST 0x01<<1
-#define CFG_B_DMA_ENABLE 0x01
-
-#define CFG_B_MUX_COM 0x00<<6
-#define CFG_B_MUX_IR 0x01<<6
-#define CFG_B_MUX_AUX 0x02<<6
-#define CFG_B_INACTIVE 0x03<<6
-
-/* Register block 2 - Consumer IR - not used */
-
-/* Register block 3 - Identification Registers! */
-
-#define SMSC_ID_HIGH 0x00 /* 0x10 */
-#define SMSC_ID_LOW 0x01 /* 0xB8 */
-#define CHIP_ID 0x02 /* 0xF1 */
-#define VERSION_NUMBER 0x03 /* 0x01 */
-#define HOST_INTERFACE 0x04 /* low 4 = DMA, high 4 = IRQ */
-
-/* Register block 4 - IrDA */
-#define IR_CONTROL 0x00
-#define BOF_COUNT_LO 0x01
-#define BRICK_WALL_CNT_LO 0x02
-#define BRICK_TX_CNT_HI 0x03
-#define TX_DATA_SIZE_LO 0x04
-#define RX_DATA_SIZE_HI 0x05
-#define RX_DATA_SIZE_LO 0x06
-
-#define SELECT_1152 0x01<<7
-#define CRC_SELECT 0x01<<6
-
-#endif
#define SCSICAM_H
#include <linux/kdev_t.h>
extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip);
+extern int scsi_partsize(struct buffer_head *bh, unsigned long capacity,
+ unsigned int *cyls, unsigned int *hds, unsigned int *secs);
#endif /* def SCSICAM_H */
* Copyright (C) 1998, 1999 Douglas Gilbert
- Version: 2.1.32 (990501)
- This version for later 2.1.x series and 2.2.x kernels
+ Version: 2.1.34 (990603)
+ This version for later 2.1.x and 2.2.x series kernels
D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au)
+ Changes since 2.1.33 (990521)
+ - implement SG_SET_RESERVED_SIZE and associated memory re-org.
+ - add SG_NEXT_CMD_LEN to override SCSI command lengths
+ - add SG_GET_VERSION_NUM to get version expressed as an integer
+ Changes since 2.1.32 (990501)
+ - fix race condition in sg_read() and sg_open()
Changes since 2.1.31 (990327)
- add ioctls SG_GET_UNDERRUN_FLAG and _SET_. Change the default
to _not_ flag underruns (affects aic7xxx driver)
Changes since 2.1.30 (990320)
- memory tweaks: change flags on kmalloc (GFP_KERNEL to GFP_ATOMIC)
- increase max allowable mid-level pool usage
- Changes since 2.1.21 (990315)
- - skipped to 2.1.30 indicating interface change (revert to 2.1.9)
- - remove attempt to accomodate cdrecord 1.8, will fix app
- - keep SG_?ET_RESERVED_SIZE naming for clarity
- Changes since 2.1.20 (990313)
- - ommission: left out logic for SG_?ET_ALT_INTERFACE, now added
- Changes since 2.1.9 (990309)
- - skipped to version 2.1.20 to indicate some interface changes
- - incorporate sg changes to make cdrecord 1.8 work (had its
- own patches that were different from the original)
- - change SG_?ET_BUFF_SIZE to SG_?ET_RESERVED_SIZE for clarity
- Changes since 2.1.8 (990303)
- - debug ">9" option dumps debug for _all_ active sg devices
- - increase allowable dma pool usage + increase minimum threshhold
- - pad out sg_scsi_id structure
- Changes since 2.1.7 (990227)
- - command queuing now "non-default" [back. compat. with cdparanoia]
- - Tighten access on some ioctls
New features and changes:
- the SCSI target, host and driver status are returned
in unused fields of sg_header (maintaining its original size).
- asynchronous notification support added (SIGPOLL, SIGIO) for
- read()s ( write()s should never block).
- - pack_id logic added so read() can be made to wait for a specific
- pack_id.
+ read()s (write()s should never block).
+ - pack_id logic added so read() can wait for a specific pack_id.
- uses memory > ISA_DMA_THRESHOLD if adapter allows it (e.g. a
pci scsi adapter).
- this driver no longer uses a single SG_BIG_BUFF sized buffer
- obtained at driver/module init time. Rather it obtains a
- SG_SCATTER_SZ buffer when a fd is open()ed and frees it at
- the corresponding release() (ie pr fd). Hence open() can return
- ENOMEM! If write() request > SG_SCATTER_SZ bytes for data then
- it can fail with ENOMEM as well (if so, scale back).
+ obtained at driver/module init time. Rather it tries to obtain a
+ SG_DEF_RESERVED_SIZE buffer when a fd is open()ed and frees it
+ at the corresponding release() (ie per fd). Actually the "buffer"
+ may be a collection of buffers if scatter-gather is being used.
+ - add SG_SET_RESERVED_SIZE ioctl allowing the user to request a
+ large buffer for duration of current file descriptor's lifetime.
+ - SG_GET_RESERVED_SIZE ioctl can be used to find out how much
+ actually has been reserved.
+ - add SG_NEXT_CMD_LEN ioctl to override SCSI command length on
+ the next write() to this file descriptor.
+ - SG_GET_RESERVED_SIZE's presence as a symbol can be used for
+ compile time identification of the version 2 sg driver.
+ However, it is recommended that run time identification based on
+ calling the ioctl of the same name is a more flexible and
+ safer approach.
- adds several ioctl calls, see ioctl section below.
- - SG_SCATTER_SZ's presence indicates this version of "sg" driver.
Good documentation on the original "sg" device interface and usage can be
- found in the Linux HOWTO document: "SCSI Programming HOWTO" by Heiko
- Eissfeldt; last updated 7 May 1996. I will add more info on using the
- extensions in this driver as required. A quick summary:
+ found in the Linux HOWTO document: "SCSI Programming HOWTO" (version 0.5)
+ by Heiko Eissfeldt; last updated 7 May 1996. Here is a quick summary of
+ sg basics:
An SG device is accessed by writing 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
The given SCSI command has its LUN field overwritten internally by the
value associated with the device that has been opened.
- Memory (RAM) is used within this driver for direct memory access (DMA)
- in transferring data to and from the SCSI device. The dreaded ENOMEM
- seems to be more prevalent under early 2.2.x kernels than under the
- 2.0.x kernel series. For a given (large) transfer the memory obtained by
- this driver must be contiguous or scatter-gather must be used (if
- supported by the adapter). [Furthermore, ISA SCSI adapters can only use
- memory below the 16MB level on a i386.]
- This driver tries hard to find some suitable memory before admitting
- defeat and returning ENOMEM. All is not lost if application writers
- then back off the amount they are requesting. The value returned by
- the SG_GET_RESERVED_SIZE ioctl is guaranteed to be available (one
- per fd). This driver does the following:
- - attempts to reserve a SG_SCATTER_SZ sized buffer on open(). The
- actual amount reserved is given by the SG_GET_RESERVED_SIZE ioctl().
- - each write() needs to reserve a DMA buffer of the size of the
- data buffer indicated (excluding sg_header and command overhead).
- This buffer, depending on its size, adapter type (ISA or not) and
- the amount of memory available will be obtained from the kernel
- directly (get_free_pages or kmalloc) or the from the scsi mid-level
- dma pool (taking care not to exhaust it).
- If the buffer requested is > SG_SCATTER_SZ or memory is tight then
- scatter-gather will be used if supported by the adapter.
- - write() will also attempt to use the buffer reserved on open()
- if it is large enough.
- The above strategy ensures that a write() can always depend on a buffer
- of the size indicated by the SG_GET_RESERVED_SIZE ioctl() (which could be
- 0, but at least the app knows things are tight in advance).
- Hence application writers can adopt quite aggressive strategies (e.g.
- requesting 512KB) and scale them back in the face of ENOMEM errors.
- N.B. Queuing up commands also ties up kernel memory.
-
- More documentation can be found at www.torque.net/sg
+ This device currently uses "indirect IO" in the sense that data is
+ DMAed into kernel buffers from the hardware and afterwards is
+ transferred into the user space (or vice versa if you are writing).
+ Transfer speeds or up to 20 to 30MBytes/sec have been measured using
+ indirect IO. For faster throughputs "direct IO" which cuts out the
+ double handling of data is required. This will also need a new interface.
+
+ Grabbing memory for those kernel buffers used in this driver for DMA may
+ cause the dreaded ENOMEM error. This error seems to be more prevalent
+ under early 2.2.x kernels than under the 2.0.x kernel series. For a given
+ (large) transfer the memory obtained by this driver must be contiguous or
+ scatter-gather must be used (if supported by the adapter). [Furthermore,
+ ISA SCSI adapters can only use memory below the 16MB level on a i386.]
+
+ When a "sg" device is open()ed O_RDWR then this driver will attempt to
+ reserve a buffer of SG_DEF_RESERVED_SIZE that will be used by subsequent
+ write()s on this file descriptor as long as:
+ - it is not already in use (eg when command queuing is in use)
+ - the write() does not call for a buffer size larger than the
+ reserved size.
+ In these cases the write() will attempt to find the memory it needs for
+ DMA buffers dynamically and in the worst case will fail with ENOMEM.
+ The amount of memory actually reserved depends on various dynamic factors
+ and can be checked with the SG_GET_RESERVED_SIZE ioctl(). [In a very
+ tight memory situation it may yield 0!] The size of the reserved buffer
+ can be changed with the SG_SET_RESERVED_SIZE ioctl(). It should be
+ followed with a call to the SG_GET_RESERVED_SIZE ioctl() to find out how
+ much was actually reserved.
+
+ More documentation plus test and utility programs can be found at
+ http://www.torque.net/sg
*/
#define SG_MAX_SENSE 16 /* too little, unlikely to change in 2.2.x */
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) */
+ int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */
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 */
int unused3;
} Sg_scsi_id;
-/* ioctls ( _GET_s yield result via 'int *' 3rd argument unless
- otherwise indicated */
-#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies, 10ms on i386 */
+/* IOCTLs: ( _GET_s yield result via 'int *' 3rd argument unless
+ otherwise indicated) */
+#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */
#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */
#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */
#define SG_SET_TRANSFORM 0x2204
#define SG_GET_TRANSFORM 0x2205
-#define SG_SET_RESERVED_SIZE 0x2275 /* currently ignored, future addition */
-/* Following yields buffer reserved by open(): 0 <= x <= SG_SCATTER_SZ */
-#define SG_GET_RESERVED_SIZE 0x2272
+#define SG_SET_RESERVED_SIZE 0x2275 /* request a new reserved buffer size */
+#define SG_GET_RESERVED_SIZE 0x2272 /* actual size of reserved buffer */
/* The following ioctl takes a 'Sg_scsi_id *' object as its 3rd argument. */
-#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus,chan,dev,lun+type */
+#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus, chan, dev, lun + type */
/* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */
-/* Override adapter setting and always DMA using low memory ( <16MB on i386).
- Default is 0 (off - use adapter setting) */
+/* Override host setting and always DMA using low memory ( <16MB on i386) */
#define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */
#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */
/* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which
will attempt to read that pack_id or block (or return EAGAIN). If
pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0
- (default) then pack_id ignored by read() and oldest readable fetched. */
+ then pack_id ignored by read() and oldest readable fetched. */
#define SG_SET_FORCE_PACK_ID 0x227b
#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */
/* Yields max scatter gather tablesize allowed by current host adapter */
#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */
-/* Control whether sequencing per file descriptor (default) or per device */
-#define SG_GET_MERGE_FD 0x2274 /* 0-> per fd (default), 1-> per device */
+/* Control whether sequencing per file descriptor or per device */
+#define SG_GET_MERGE_FD 0x2274 /* 0-> per fd, 1-> per device */
#define SG_SET_MERGE_FD 0x2273 /* Attempt to change sequencing state,
- if more than 1 fd open on device, will fail with EBUSY */
+ if more than current fd open on device, will fail with EBUSY */
/* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q) */
#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */
#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */
-/* Get/set whether DMA underrun will cause an error (DID_ERROR) [this only
- currently applies to the [much-used] aic7xxx driver) */
+/* Get/set whether DMA underrun will cause an error (DID_ERROR). This only
+ currently applies to the [much-used] aic7xxx driver. */
#define SG_GET_UNDERRUN_FLAG 0x2280 /* Yields 0 (don't flag) or 1 (flag) */
#define SG_SET_UNDERRUN_FLAG 0x2281 /* Change flag underrun state */
+#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */
+#define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given
+ number on the next write() on this file descriptor */
+
+
+#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
+/* Largest size (in bytes) a single scatter-gather list element can have.
+ The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on
+ i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
+ by adapter then this value is the largest data block that can be
+ read/written by a single scsi command. The user can find the value of
+ PAGE_SIZE by calling getpagesize() defined in unistd.h . */
#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */
#define SG_DEFAULT_RETRIES 1
-/* Default modes, commented if they differ from original sg driver */
+/* Defaults, commented if they differ from original sg driver */
#define SG_DEF_COMMAND_Q 0
#define SG_DEF_MERGE_FD 0 /* was 1 -> per device sequencing */
#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */
#define SG_DEF_FORCE_PACK_ID 0
#define SG_DEF_UNDERRUN_FLAG 0
+#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ
/* maximum outstanding requests, write() yields EDOM if exceeded */
#define SG_MAX_QUEUE 16
-#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
-/* Largest size (in bytes) a single scatter-gather list element can have.
- The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on
- i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
- by adapter then this value is the largest data block that can be
- read/written by a single scsi command. Max number of scatter-gather
- list elements seems to be limited to 255. */
-
-#define SG_BIG_BUFF SG_SCATTER_SZ /* for backward compatibility */
-/* #define SG_BIG_BUFF (SG_SCATTER_SZ * 8) */ /* =256KB, if you want */
+#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE /* for backward compatibility */
#endif
#include <linux/unistd.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <asm/uaccess.h>
if (nr_queued_signals < max_queued_signals) {
q = (struct signal_queue *)
- kmem_cache_alloc(signal_queue_cachep, GFP_KERNEL);
+ kmem_cache_alloc(signal_queue_cachep, GFP_ATOMIC);
}
if (q) {
if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
sigdelset(&t->blocked, sig);
+ recalc_sigpending(t);
spin_unlock_irqrestore(&t->sigmask_lock, flags);
return send_sig_info(sig, info, t);
return -EINVAL;
if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
return -EFAULT;
+ if (new_rlim.rlim_cur < 0 || new_rlim.rlim_max < 0)
+ return -EINVAL;
old_rlim = current->rlim + resource;
if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
(new_rlim.rlim_max > old_rlim->rlim_max)) &&
pte = *page_table;
new_page = __get_free_page(GFP_USER);
- /* Did someone else copy this page for us while we slept? */
+ /* Did swap_out() unmapped the protected page while we slept? */
if (pte_val(*page_table) != pte_val(pte))
goto end_wp_page;
if (!pte_present(pte))
delete_from_swap_cache(page_map);
/* FallThrough */
case 1:
- /* We can release the kernel lock now.. */
- unlock_kernel();
-
flush_cache_page(vma, address);
set_pte(page_table, pte_mkdirty(pte_mkwrite(pte)));
flush_tlb_page(vma, address);
end_wp_page:
+ /*
+ * We can release the kernel lock now.. Now swap_out will see
+ * a dirty page and so won't get confused and flush_tlb_page
+ * won't SMP race. -Andrea
+ */
+ unlock_kernel();
+
if (new_page)
free_page(new_page);
return 1;
}
- unlock_kernel();
if (!new_page)
- return 0;
+ goto no_new_page;
- if (PageReserved(mem_map + MAP_NR(old_page)))
+ if (PageReserved(page_map))
++vma->vm_mm->rss;
copy_cow_page(old_page,new_page);
flush_page_to_ram(old_page);
flush_page_to_ram(new_page);
flush_cache_page(vma, address);
set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
- free_page(old_page);
flush_tlb_page(vma, address);
+ unlock_kernel();
+ __free_page(page_map);
return 1;
bad_wp_page:
printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
send_sig(SIGKILL, tsk, 1);
+no_new_page:
+ unlock_kernel();
if (new_page)
free_page(new_page);
return 0;
* Swap reorganised 29.12.95, Stephen Tweedie
*/
+#include <linux/config.h>
#include <linux/malloc.h>
#include <linux/smp_lock.h>
#include <linux/kernel_stat.h>
} else if (S_ISREG(swap_dentry->d_inode->i_mode)) {
error = -EBUSY;
for (i = 0 ; i < nr_swapfiles ; i++) {
- if (i == type)
+ if (i == type || !swap_info[i].swap_file)
continue;
if (swap_dentry->d_inode == swap_info[i].swap_file->d_inode)
goto bad_swap;
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.52 1999/03/21 12:04:11 davem Exp $
+ * Version: $Id: icmp.c,v 1.52.2.1 1999/06/09 01:56:07 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
printk(" O=0x%8.8X", *opt++);
- printk(" %s(#%d)\n", tcpsyn ? "SYN " : /* "PENANCE" */ "", count);
+ printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count);
}
/* function for checking chain labels for user space. */
f->counters[slot].bcnt+=ntohs(ip->tot_len);
f->counters[slot].pcnt++;
if (f->ipfw.fw_flg & IP_FW_F_PRN) {
- dump_packet(ip,rif,f,label,src_port,dst_port,count,syn);
+ dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);
}
ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: ipmr.c,v 1.40 1999/03/25 10:04:25 davem Exp $
+ * Version: $Id: ipmr.c,v 1.40.2.1 1999/06/09 01:56:17 davem Exp $
*
* Fixes:
* Michael Chastain : Incorrect size of copying.
# IrDA protocol configuration
#
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- if [ "$CONFIG_NET" != "n" ] ; then
+if [ "$CONFIG_NET" != "n" ] ; then
- mainmenu_option next_comment
- comment 'IrDA subsystem support'
- dep_tristate 'IrDA subsystem support' CONFIG_IRDA $CONFIG_EXPERIMENTAL $CONFIG_NET
+ mainmenu_option next_comment
+ comment 'IrDA subsystem support'
+ dep_tristate 'IrDA subsystem support' CONFIG_IRDA $CONFIG_NET
- if [ "$CONFIG_IRDA" != "n" ] ; then
- comment 'IrDA protocols'
- source net/irda/irlan/Config.in
- source net/irda/ircomm/Config.in
- source net/irda/irlpt/Config.in
+ if [ "$CONFIG_IRDA" != "n" ] ; then
+ comment 'IrDA protocols'
+ source net/irda/irlan/Config.in
+ source net/irda/ircomm/Config.in
+ source net/irda/irlpt/Config.in
- bool 'IrDA protocol options' CONFIG_IRDA_OPTIONS
- if [ "$CONFIG_IRDA_OPTIONS" != "n" ] ; then
- comment ' IrDA options'
- bool ' Cache last LSAP' CONFIG_IRDA_CACHE_LAST_LSAP
- bool ' Fast RRs' CONFIG_IRDA_FAST_RR
- bool ' Debug information' CONFIG_IRDA_DEBUG
- fi
+ bool 'IrDA protocol options' CONFIG_IRDA_OPTIONS
+ if [ "$CONFIG_IRDA_OPTIONS" != "n" ] ; then
+ comment ' IrDA options'
+ bool ' Cache last LSAP' CONFIG_IRDA_CACHE_LAST_LSAP
+ bool ' Fast RRs' CONFIG_IRDA_FAST_RR
+ bool ' Debug information' CONFIG_IRDA_DEBUG
fi
+ fi
- if [ "$CONFIG_IRDA" != "n" ] ; then
- source net/irda/compressors/Config.in
- source drivers/net/irda/Config.in
- fi
- endmenu
-
+ if [ "$CONFIG_IRDA" != "n" ] ; then
+ source net/irda/compressors/Config.in
+ source drivers/net/irda/Config.in
fi
+ endmenu
fi
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun May 31 10:12:43 1998
- * Modified at: Tue May 11 12:42:26 1999
+ * Modified at: Wed May 19 16:12:06 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
* Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
*
else
self->max_data_size = max_sdu_size;
- DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+ DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
else
self->max_data_size = max_sdu_size;
- DEBUG(0, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
+ DEBUG(1, __FUNCTION__ "(), max_data_size=%d\n", self->max_data_size);
memcpy(&self->qos_tx, qos, sizeof(struct qos_info));
switch (flow) {
case FLOW_STOP:
- DEBUG( 0, __FUNCTION__ "(), IrTTP wants us to slow down\n");
+ DEBUG(1, __FUNCTION__ "(), IrTTP wants us to slow down\n");
self->tx_flow = flow;
break;
case FLOW_START:
self->tx_flow = flow;
- DEBUG(0, __FUNCTION__ "(), IrTTP wants us to start again\n");
+ DEBUG(1, __FUNCTION__ "(), IrTTP wants us to start again\n");
wake_up_interruptible(sk->sleep);
break;
default:
sock_init_data(sock, sk);
- sock->ops = &irda_stream_ops;
+ if (sock->type == SOCK_STREAM)
+ sock->ops = &irda_stream_ops;
+ else
+ sock->ops = &irda_dgram_ops;
+
sk->protocol = protocol;
/* Register as a client with IrLMP */
{
struct sock *sk = sock->sk;
- DEBUG(0, __FUNCTION__ "(), cmd=%#x\n", cmd);
+ DEBUG(4, __FUNCTION__ "(), cmd=%#x\n", cmd);
switch (cmd) {
case TIOCOUTQ: {
return -EINVAL;
default:
- DEBUG(0, __FUNCTION__ "(), doing device ioctl!\n");
+ DEBUG(1, __FUNCTION__ "(), doing device ioctl!\n");
return dev_ioctl(cmd, (void *) arg);
}
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Apr 6 15:33:50 1999
- * Modified at: Sun May 9 22:40:43 1999
+ * Modified at: Fri May 28 20:46:38 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1999 Dag Brattli, All Rights Reserved.
discovery = (discovery_t *) hashbin_get_first(cachelog);
while ( discovery != NULL) {
- len += sprintf( buf+len, " name: %s,",
- discovery->info);
+ len += sprintf(buf+len, "name: %s,", discovery->info);
- len += sprintf( buf+len, " hint: ");
+ len += sprintf(buf+len, " hint: 0x%02x%02x",
+ discovery->hints.byte[0],
+ discovery->hints.byte[1]);
+#if 0
if ( discovery->hints.byte[0] & HINT_PNP)
len += sprintf( buf+len, "PnP Compatible ");
if ( discovery->hints.byte[0] & HINT_PDA)
len += sprintf( buf+len, "IrCOMM ");
if ( discovery->hints.byte[1] & HINT_OBEX)
len += sprintf( buf+len, "IrOBEX ");
-
+#endif
len += sprintf(buf+len, ", saddr: 0x%08x",
discovery->saddr);
len += sprintf(buf+len, ", daddr: 0x%08x\n",
discovery->daddr);
- len += sprintf( buf+len, "\n");
+ len += sprintf(buf+len, "\n");
discovery = (discovery_t *) hashbin_get_next(cachelog);
}
#include <net/irda/ircomm_common.h>
-static char *revision_date = "Sun Apr 18 00:40:19 1999";
+static char *revision_date = "Tue May 18 03:11:39 1999";
static void ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event,
ircomm[i]->enq_char = 0x05;
ircomm[i]->ack_char = 0x06;
- ircomm[i]->max_txbuff_size = COMM_DEFAULT_DATA_SIZE; /* 64 */
- ircomm[i]->max_sdu_size = SAR_DISABLE;
- ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ ircomm[i]->max_header_size = COMM_MAX_HEADER_SIZE;
+ ircomm[i]->tx_max_sdu_size = COMM_DEFAULT_SDU_SIZE;
+ ircomm[i]->rx_max_sdu_size = SAR_DISABLE;
+ ircomm[i]->ctrl_skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE
+ + COMM_MAX_HEADER_SIZE);
if (ircomm[i]->ctrl_skb == NULL){
DEBUG(0,"ircomm:init_module:alloc_skb failed!\n");
return -ENOMEM;
}
- skb_reserve(ircomm[i]->ctrl_skb,COMM_HEADER_SIZE);
+ skb_reserve(ircomm[i]->ctrl_skb,COMM_MAX_HEADER_SIZE);
}
DEBUG(0,__FUNCTION__"(): got connected!\n");
if (max_sdu_size == SAR_DISABLE)
- self->max_txbuff_size = qos->data_size.value - max_header_size;
+ self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+ - COMM_HEADER_SIZE);
else {
- ASSERT(max_sdu_size >= COMM_DEFAULT_DATA_SIZE, return;);
- self->max_txbuff_size = max_sdu_size; /* use fragmentation */
+ ASSERT(max_sdu_size >= COMM_DEFAULT_SDU_SIZE, return;);
+ /* use fragmentation */
+ self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
}
self->qos = qos;
- self->max_header_size = max_header_size;
+ self->max_header_size = max_header_size + COMM_HEADER_SIZE;
self->null_modem_mode = 0; /* disable null modem emulation */
ircomm_do_event(self, TTP_CONNECT_CONFIRM, skb);
DEBUG(0,__FUNCTION__"()\n");
if (max_sdu_size == SAR_DISABLE)
- self->max_txbuff_size = qos->data_size.value - max_header_size;
+ self->tx_max_sdu_size =(qos->data_size.value - max_header_size
+ - COMM_HEADER_SIZE);
else
- self->max_txbuff_size = max_sdu_size;
+ self->tx_max_sdu_size = max_sdu_size - COMM_HEADER_SIZE;
self->qos = qos;
- self->max_header_size = max_header_size;
+ self->max_header_size = max_header_size + COMM_HEADER_SIZE;
ircomm_do_event( self, TTP_CONNECT_INDICATION, skb);
irttp_connect_request(self->tsap, self->dlsap,
self->saddr, self->daddr,
- NULL, self->max_sdu_size, userdata);
+ NULL, self->rx_max_sdu_size, userdata);
break;
default:
if (self->notify.connect_indication)
self->notify.connect_indication(self->notify.instance, self,
- qos, 0, 0, skb);
+ qos, self->tx_max_sdu_size,
+ self->max_header_size, skb);
}
#if 0
/* give a connect_confirm to the client */
if( self->notify.connect_confirm )
self->notify.connect_confirm(self->notify.instance,
- self, NULL, SAR_DISABLE, 0, skb);
+ self, NULL, self->tx_max_sdu_size,
+ self->max_header_size, skb);
}
static void issue_connect_response(struct ircomm_cb *self,
DEBUG(0,__FUNCTION__"():THREE_WIRE_RAW is not implemented yet\n");
/* irlmp_connect_rsp(); */
} else
- irttp_connect_response(self->tsap, self->max_sdu_size, skb);
+ irttp_connect_response(self->tsap, self->rx_max_sdu_size, skb);
}
static void issue_disconnect_request(struct ircomm_cb *self,
hints = irlmp_service_to_hint(S_COMM);
- DEBUG(0,__FUNCTION__"():start discovering..\n");
+ DEBUG(1,__FUNCTION__"():start discovering..\n");
switch (ircomm_cs) {
case 0:
MOD_INC_USE_COUNT;
ASSERT( self->magic == IRCOMM_MAGIC, return;);
- DEBUG(0, __FUNCTION__"():sending connect_request...\n");
+ DEBUG(1, __FUNCTION__"():sending connect_request...\n");
self->servicetype= servicetype;
/* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
- self->max_sdu_size = SAR_DISABLE;
+ self->rx_max_sdu_size = SAR_DISABLE;
ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, NULL);
}
if (!userdata){
/* FIXME: check for errors and initialize? DB */
- userdata = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ userdata = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
if (userdata == NULL)
return;
- skb_reserve(userdata,COMM_HEADER_SIZE);
+ skb_reserve(userdata,COMM_MAX_HEADER_SIZE);
}
/* enable null-modem emulation (i.e. server mode )*/
self->null_modem_mode = 1;
- self->max_sdu_size = max_sdu_size;
- if (max_sdu_size != SAR_DISABLE)
- self->max_txbuff_size = max_sdu_size;
-
+ self->rx_max_sdu_size = max_sdu_size;
+
ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata);
}
ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb);
self->control_ch_pending = 0;
- skb = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ skb = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
ASSERT(skb != NULL, return ;);
- skb_reserve(skb,COMM_HEADER_SIZE);
+ skb_reserve(skb,COMM_MAX_HEADER_SIZE);
self->ctrl_skb = skb;
}
static int irvtd_refcount;
struct irvtd_cb **irvtd = NULL;
-static char *revision_date = "Sun Apr 18 17:31:53 1999";
+static char *revision_date = "Wed May 26 00:49:11 1999";
/*
static void irvtd_send_xchar(struct tty_struct *tty, char ch);
static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout);
-static void irvtd_start_timer( struct irvtd_cb *driver);
-static void irvtd_timer_expired(unsigned long data);
+static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout);
+static void irvtd_tx_timer_expired(unsigned long data);
+static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout);
+static void irvtd_rx_timer_expired(unsigned long data);
static int line_info(char *buf, struct irvtd_cb *driver);
static int irvtd_read_proc(char *buf, char **start, off_t offset, int len,
if(driver->rx_disable)
return;
- skb = skb_dequeue(&driver->rxbuff);
+ skb = skb_dequeue(&driver->rxbuff);
if(skb == NULL)
return; /* there's nothing */
if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW &&
driver->ttp_stoprx){
- irttp_flow_request(driver->comm->tsap, FLOW_START);
+ DEBUG(1, __FUNCTION__"():FLOW_START\n");
+ /*
+ * next 2 lines must follow this order since irttp_flow_request()
+ * will run its rx queue
+ */
driver->ttp_stoprx = 0;
+ irttp_flow_request(driver->comm->tsap, FLOW_START);
}
if(skb_queue_empty(&driver->rxbuff) && driver->disconnect_pend){
skb_queue_tail( &driver->rxbuff, skb );
if(skb_queue_len(&driver->rxbuff) > IRVTD_RX_QUEUE_HIGH){
+ DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
irttp_flow_request(driver->comm->tsap, FLOW_STOP);
driver->ttp_stoprx = 1;
}
irvtd_write_to_tty(driver);
+
+ if(!skb_queue_empty(&driver->rxbuff))
+ irvtd_start_rx_timer(driver,0);
return 0;
}
*/
-static void irvtd_start_timer( struct irvtd_cb *driver)
+static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout)
+{
+ ASSERT( driver != NULL, return;);
+ ASSERT( driver->magic == IRVTD_MAGIC, return;);
+
+ del_timer( &driver->tx_timer);
+
+ driver->tx_timer.data = (unsigned long) driver;
+ driver->tx_timer.function = &irvtd_tx_timer_expired;
+ driver->tx_timer.expires = jiffies + timeout;
+
+ add_timer( &driver->tx_timer);
+}
+
+static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout)
{
ASSERT( driver != NULL, return;);
ASSERT( driver->magic == IRVTD_MAGIC, return;);
- del_timer( &driver->timer);
+ del_timer( &driver->rx_timer);
- driver->timer.data = (unsigned long) driver;
- driver->timer.function = &irvtd_timer_expired;
- driver->timer.expires = jiffies + (HZ / 5); /* 200msec */
+ driver->rx_timer.data = (unsigned long) driver;
+ driver->rx_timer.function = &irvtd_rx_timer_expired;
+ driver->rx_timer.expires = jiffies + timeout;
- add_timer( &driver->timer);
+ add_timer( &driver->rx_timer);
}
-static void irvtd_timer_expired(unsigned long data)
+static void irvtd_tx_timer_expired(unsigned long data)
{
struct irvtd_cb *driver = (struct irvtd_cb *)data;
DEBUG(4, __FUNCTION__"()\n");
irvtd_send_data_request(driver);
+}
- irvtd_write_to_tty(driver);
+static void irvtd_rx_timer_expired(unsigned long data)
+{
+ struct irvtd_cb *driver = (struct irvtd_cb *)data;
- /* start our timer again and again */
- irvtd_start_timer(driver);
+ ASSERT(driver != NULL,return;);
+ ASSERT(driver->magic == IRVTD_MAGIC,return;);
+ DEBUG(4, __FUNCTION__"()\n");
+
+ while(TTY_FLIPBUF_SIZE - driver->tty->flip.count
+ && !skb_queue_empty(&driver->rxbuff))
+ irvtd_write_to_tty(driver);
+
+ DEBUG(1, __FUNCTION__"(): room in flip_buffer = %d\n",
+ TTY_FLIPBUF_SIZE - driver->tty->flip.count);
+
+ if(!skb_queue_empty(&driver->rxbuff))
+ /* handle it later */
+ irvtd_start_rx_timer(driver, 1);
}
}
#endif
- DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
+ DEBUG(1, __FUNCTION__"():len = %d, room = %d\n",(int)skb->len,
+ skb_tailroom(skb));
driver->icount.tx += skb->len;
err = ircomm_data_request(driver->comm, driver->txbuff);
if (err){
ASSERT(err == 0,;);
- DEBUG(0,"%d chars are lost\n",(int)skb->len);
+ DEBUG(1,"%d chars are lost\n",(int)skb->len);
skb_trim(skb, 0);
}
/* allocate a new frame */
- skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
+ skb = driver->txbuff
+ = dev_alloc_skb(driver->tx_max_sdu_size + driver->max_header_size);
if (skb == NULL){
printk(__FUNCTION__"():alloc_skb failed!\n");
} else {
- skb_reserve(skb, COMM_HEADER_SIZE);
+ skb_reserve(skb, driver->max_header_size);
}
wake_up_interruptible(&driver->tty->write_wait);
ASSERT(driver != NULL, return;);
ASSERT(driver->magic == IRVTD_MAGIC, return;);
+
+ driver->tx_max_sdu_size = max_sdu_size;
+ driver->max_header_size = max_header_size;
/*
* set default value
*/
ASSERT(comm != NULL, return;);
ASSERT(comm->magic == IRCOMM_MAGIC, return;);
+ driver->tx_max_sdu_size = max_sdu_size;
+ driver->max_header_size = max_header_size;
DEBUG(4, __FUNCTION__ "():sending connect_response...\n");
ircomm_connect_response(comm, NULL, SAR_DISABLE );
if(cmd == TX_READY){
driver->ttp_stoptx = 0;
driver->tty->hw_stopped = driver->cts_stoptx;
- irvtd_start_timer( driver);
if(driver->cts_stoptx)
return;
+ /* push tx queue so that client can send at least 1 octet */
+ irvtd_send_data_request(driver);
/*
* driver->tty->write_wait will keep asleep if
* our txbuff is full.
if(cmd == TX_BUSY){
driver->ttp_stoptx = driver->tty->hw_stopped = 1;
- del_timer( &driver->timer);
+ del_timer( &driver->tx_timer);
return;
}
driver->blocked_open--;
- DEBUG(0, __FUNCTION__"():after blocking\n");
+ DEBUG(1, __FUNCTION__"():after blocking\n");
if (retval)
return retval;
struct notify_t irvtd_notify;
/* FIXME: it should not be hard coded */
- __u8 oct_seq[6] = { 0,1,4,1,1,1 };
+ __u8 oct_seq[6] = { 0,1,6,1,1,1 };
DEBUG(4,__FUNCTION__"()\n" );
if(driver->flags & ASYNC_INITIALIZED)
*/
skb_queue_head_init(&driver->rxbuff);
- driver->txbuff = dev_alloc_skb(COMM_DEFAULT_DATA_SIZE);
+ driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE);
if (!driver->txbuff){
DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n");
return -ENOMEM;
}
- skb_reserve(driver->txbuff, COMM_HEADER_SIZE);
+ skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE);
irda_notify_init(&irvtd_notify);
irvtd_notify.data_indication = irvtd_receive_data;
driver->flags |= ASYNC_INITIALIZED;
- /*
- * discover a peer device
- * TODO: other servicetype(i.e. 3wire,3wireraw) support
- */
- 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....
- */
-
if (driver->tty)
clear_bit(TTY_IO_ERROR, &driver->tty->flags);
change_speed(driver);
- irvtd_start_timer( driver);
+
+ /*
+ * discover a peer device
+ */
+ if(driver->tty->termios->c_cflag & CRTSCTS)
+ ircomm_connect_request(driver->comm, NINE_WIRE);
+ else
+ ircomm_connect_request(driver->comm, THREE_WIRE);
+
+ /* irvtd_start_timer( driver); */
driver->rx_disable = 0;
driver->tx_disable = 1;
if (driver->tty)
set_bit(TTY_IO_ERROR, &driver->tty->flags);
- del_timer( &driver->timer);
+ del_timer( &driver->tx_timer);
+ del_timer( &driver->rx_timer);
irias_delete_object("IrDA:IrCOMM");
DEBUG(4, __FUNCTION__"()\n");
save_flags(flags);
- while(1){
+ while(count > 0){
cli();
skb = driver->txbuff;
ASSERT(skb != NULL, break;);
c = MIN(count, (skb_tailroom(skb)));
if (c <= 0)
- break;
+ {
+ if(!driver->ttp_stoptx)
+ {
+ irvtd_send_data_request(driver);
+ continue;
+ }
+ else
+ break;
+ }
/* write to the frame */
wrote += c;
count -= c;
buf += c;
- irvtd_send_data_request(driver);
}
restore_flags(flags);
+ irvtd_send_data_request(driver);
return (wrote);
}
DEBUG(4, __FUNCTION__"()\n");
+ again:
save_flags(flags);cli();
skb = driver->txbuff;
ASSERT(skb != NULL,return;);
+ if(!skb_tailroom(skb))
+ {
+ restore_flags(flags);
+ irvtd_send_data_request(driver);
+ goto again;
+ }
ASSERT(skb_tailroom(skb) > 0, return;);
- DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) MAX(%d):\n",
+ DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) room(%d):\n",
(int)ch ,(int)skb->len,
- driver->comm->max_txbuff_size - COMM_HEADER_SIZE);
+ skb_tailroom(skb));
/* append a character */
frame = skb_put(skb,1);
frame[0] = ch;
restore_flags(flags);
+ irvtd_start_tx_timer(driver,20);
return;
}
driver->comm->dte = driver->mcr;
ircomm_control_request(driver->comm, DTELINE_STATE );
+ DEBUG(1, __FUNCTION__"():FLOW_STOP\n");
irttp_flow_request(driver->comm->tsap, FLOW_STOP);
}
driver->comm->dte = driver->mcr;
ircomm_control_request(driver->comm, DTELINE_STATE );
+ DEBUG(1, __FUNCTION__"():FLOW_START\n");
irttp_flow_request(driver->comm->tsap, FLOW_START);
}
if (driver->msr & MSR_RI)
ret += sprintf(buf+ret, "|RI");
+ ret += sprintf(buf+ret, "\n");
+ ret += sprintf(buf+ret, "rx queue:%d",
+ skb_queue_len( &driver->rxbuff));
+ ret += sprintf(buf+ret, "ttp_stoprx:%s",
+ driver->ttp_stoprx?"TRUE":"FALSE");
+
exit:
ret += sprintf(buf+ret, "\n");
return ret;
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Wed Sep 2 20:22:08 1998
- * Modified at: Mon May 10 23:02:47 1999
+ * Modified at: Tue Jun 1 09:05:13 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
#ifdef CONFIG_NSC_FIR
pc87108_init();
#endif
+#ifdef CONFIG_TOSHIBA_FIR
+ toshoboe_init();
+#endif
+#ifdef CONFIG_SMC_IRCC_FIR
+ ircc_init();
+#endif
#ifdef CONFIG_ESI_DONGLE
esi_init();
#endif
#ifdef CONFIG_GIRBIL_DONGLE
girbil_init();
#endif
+#ifdef CONFIG_GIRBIL_DONGLE
+ litelink_init();
+#endif
+
return 0;
}
/* Initialize timers */
init_timer(&self->media_busy_timer);
+ self->lock = SPIN_LOCK_UNLOCKED;
+
/* A pointer to the low level implementation */
self->priv = priv;
/* Open network device */
dev_open(&self->netdev);
- MESSAGE("IrDA: Registred device %s\n", self->name);
+ MESSAGE("IrDA: Registered device %s\n", self->name);
irda_device_set_media_busy(self, FALSE);
*/
static void __irda_device_change_speed(struct irda_device *self, int speed)
{
+ int n = 0;
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
* Is is possible to change speed yet? Wait until the last byte
* has been transmitted.
*/
- if (self->wait_until_sent) {
- self->wait_until_sent(self);
-
- if (self->dongle)
- self->dongle->change_speed(self, speed);
-
- if (self->change_speed) {
- self->change_speed(self, speed);
-
- /* Update the QoS value only */
- self->qos.baud_rate.value = speed;
+ if (!self->wait_until_sent) {
+ ERROR("IrDA: wait_until_sent() "
+ "has not implemented by the IrDA device driver!\n");
+ return;
+ }
+
+ /* Make sure all transmitted data has actually been sent */
+ self->wait_until_sent(self);
+
+ /* Make sure nobody tries to transmit during the speed change */
+ while (irda_lock((void *) &self->netdev.tbusy) == FALSE) {
+ WARNING(__FUNCTION__ "(), device locked!\n");
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(MSECS_TO_JIFFIES(10));
+
+ if (n++ > 10) {
+ WARNING(__FUNCTION__ "(), breaking loop!\n");
+ break;
}
- } else {
- WARNING("IrDA: wait_until_sent() "
- "has not implemented by the IrDA device driver!\n");
}
+
+ if (self->dongle)
+ self->dongle->change_speed(self, speed);
+
+ if (self->change_speed) {
+ self->change_speed(self, speed);
+
+ /* Update the QoS value only */
+ self->qos.baud_rate.value = speed;
+ }
+ self->netdev.tbusy = FALSE;
}
/*
*/
inline void irda_device_change_speed(struct irda_device *self, int speed)
{
- DEBUG(4, __FUNCTION__ "()\n");
-
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRDA_DEVICE_MAGIC, return;);
inline int irda_device_is_media_busy( struct irda_device *self)
{
- ASSERT( self != NULL, return FALSE;);
- ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+ ASSERT(self != NULL, return FALSE;);
+ ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
return self->media_busy;
}
inline int irda_device_is_receiving( struct irda_device *self)
{
- ASSERT( self != NULL, return FALSE;);
- ASSERT( self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
+ ASSERT(self != NULL, return FALSE;);
+ ASSERT(self->magic == IRDA_DEVICE_MAGIC, return FALSE;);
- if ( self->is_receiving)
- return self->is_receiving( self);
+ if (self->is_receiving)
+ return self->is_receiving(self);
else
return FALSE;
}
-inline struct qos_info *irda_device_get_qos( struct irda_device *self)
+inline struct qos_info *irda_device_get_qos(struct irda_device *self)
{
- ASSERT( self != NULL, return NULL;);
- ASSERT( self->magic == IRDA_DEVICE_MAGIC, return NULL;);
+ ASSERT(self != NULL, return NULL;);
+ ASSERT(self->magic == IRDA_DEVICE_MAGIC, return NULL;);
return &self->qos;
}
{
struct irda_device *self;
- DEBUG(4, __FUNCTION__ "()\n");
-
ASSERT(dev != NULL, return -1;);
self = (struct irda_device *) dev->priv;
return 0;
}
+
+#define SIOCSDONGLE SIOCDEVPRIVATE
static int irda_device_net_ioctl(struct device *dev, /* ioctl device */
struct ifreq *rq, /* Data passed */
int cmd) /* Ioctl number */
#endif
break;
#endif
+ case SIOCSDONGLE: /* Set dongle */
+ /* Initialize dongle */
+ irda_device_init_dongle(self, (int) rq->ifr_data);
+ break;
default:
ret = -EOPNOTSUPP;
}
ERROR("IrDA: Unable to find requested dongle\n");
return;
}
+
+ /* Check if we're already using a dongle */
+ if (self->dongle) {
+ self->dongle->close(self);
+ }
/* Set the dongle to be used by this driver */
self->dongle = node->dongle;
node->dongle->qos_init(self, &self->qos);
/* Reset dongle */
- node->dongle->reset(self, 0);
+ node->dongle->reset(self);
/* Set to default baudrate */
irda_device_change_speed(self, 9600);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Tue May 11 00:22:39 1999
+ * Modified at: Mon May 31 14:19:34 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>
{
struct irlan_cb *self;
- DEBUG(4, __FUNCTION__ "()\n");
+ DEBUG(2, __FUNCTION__ "()\n");
self = (struct irlan_cb *) instance;
irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb);
+ /* Ready for a new command */
+ self->client.tx_busy = FALSE;
+
+ /* Check if we have some queued commands waiting to be sent */
+ irlan_run_ctrl_tx_queue(self);
+
return 0;
}
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Thu May 6 13:42:38 1999
+ * Modified at: Fri May 14 23:08:15 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:37 1997
- * Modified at: Sun May 9 11:48:49 1999
+ * Modified at: Mon May 31 14:25:19 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
init_timer(&self->client.kick_timer);
hashbin_insert(irlan, (QUEUE *) self, daddr, NULL);
-
+
+ skb_queue_head_init(&self->client.txq);
+
irlan_next_client_state(self, IRLAN_IDLE);
irlan_next_provider_state(self, IRLAN_IDLE);
*/
static void __irlan_close(struct irlan_cb *self)
{
- DEBUG(0, __FUNCTION__ "()\n");
+ DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
{
struct irlan_cb *self;
- DEBUG(2, __FUNCTION__ "()\n");
-
self = (struct irlan_cb *) instance;
ASSERT(self != NULL, return;);
*/
irlan_get_unicast_addr(self);
irlan_open_unicast_addr(self);
+
+ /* Open broadcast and multicast filter by default */
+ irlan_set_broadcast_filter(self, TRUE);
+ irlan_set_multicast_filter(self, TRUE);
/* Ready to transfer Ethernet frames */
self->dev.tbusy = 0;
+
+ irlan_eth_send_gratuitous_arp(&self->dev);
}
/*
break;
}
- /* Stop IP from transmitting more packets */
- /* irlan_client_flow_indication(handle, FLOW_STOP, priv); */
-
irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);
}
struct notify_t notify;
struct tsap_cb *tsap;
- DEBUG(0, __FUNCTION__ "()\n");
+ DEBUG(2, __FUNCTION__ "()\n");
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
notify.udata_indication = irlan_eth_receive;
notify.connect_indication = irlan_connect_indication;
notify.connect_confirm = irlan_connect_confirm;
- notify.flow_indication = irlan_eth_flow_indication;
+ /*notify.flow_indication = irlan_eth_flow_indication;*/
notify.disconnect_indication = irlan_disconnect_indication;
notify.instance = self;
strncpy(notify.name, "IrLAN data", NOTIFY_MAX_NAME);
irttp_disconnect_request(self->tsap_data, NULL, P_NORMAL);
irttp_close_tsap(self->tsap_data);
self->tsap_data = NULL;
-
}
if (self->client.tsap_ctrl) {
irttp_disconnect_request(self->client.tsap_ctrl, NULL,
irias_add_string_attrib(obj, "Name", "Linux");
#endif
irias_add_string_attrib(obj, "DeviceID", "HWP19F0");
- irias_add_integer_attrib(obj, "CompCnt", 2);
- irias_add_string_attrib(obj, "Comp#01", "PNP8294");
- irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+ irias_add_integer_attrib(obj, "CompCnt", 1);
+ if (self->provider.access_type == ACCESS_PEER)
+ irias_add_string_attrib(obj, "Comp#02", "PNP8389");
+ else
+ irias_add_string_attrib(obj, "Comp#01", "PNP8294");
+
irias_add_string_attrib(obj, "Manufacturer", "Linux-IrDA Project");
irias_insert_object(obj);
}
}
+/*
+ * Function irlan_run_ctrl_tx_queue (self)
+ *
+ * Try to send the next command in the control transmit queue
+ *
+ */
+int irlan_run_ctrl_tx_queue(struct irlan_cb *self)
+{
+ struct sk_buff *skb;
+
+ if (irda_lock(&self->client.tx_busy) == FALSE)
+ return -EBUSY;
+
+ skb = skb_dequeue(&self->client.txq);
+ if (!skb) {
+ self->client.tx_busy = FALSE;
+ return 0;
+ }
+ if (self->client.tsap_ctrl == NULL) {
+ self->client.tx_busy = FALSE;
+ dev_kfree_skb(skb);
+ return -1;
+ }
+
+ return irttp_data_request(self->client.tsap_ctrl, skb);
+}
+
+/*
+ * Function irlan_ctrl_data_request (self, skb)
+ *
+ * This function makes sure that commands on the control channel is being
+ * sent in a command/response fashion
+ */
+void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb)
+{
+ /* Queue command */
+ skb_queue_tail(&self->client.txq, skb);
+
+ /* Try to send command */
+ irlan_run_ctrl_tx_queue(self);
+}
+
/*
* Function irlan_get_provider_info (self)
*
frame[0] = CMD_GET_PROVIDER_INFO;
frame[1] = 0x00; /* Zero parameters */
- irttp_data_request(self->client.tsap_ctrl, skb);
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
/* self->use_udata = TRUE; */
- irttp_data_request(self->client.tsap_ctrl, skb);
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
void irlan_close_data_channel(struct irlan_cb *self)
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
+ /* Check if the TSAP is still there */
+ if (self->client.tsap_ctrl == NULL)
+ return;
+
skb = dev_alloc_skb(64);
if (!skb)
return;
irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
- irttp_data_request(self->client.tsap_ctrl, skb);
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
- irttp_data_request(self->client.tsap_ctrl, skb);
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
irlan_insert_string_param(skb, "FILTER_MODE", "FILTER");
else
irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
-
- irttp_data_request(self->client.tsap_ctrl, skb);
+
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
irlan_insert_string_param(skb, "FILTER_MODE", "ALL");
else
irlan_insert_string_param(skb, "FILTER_MODE", "NONE");
-
- irttp_data_request(self->client.tsap_ctrl, skb);
+
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
irlan_insert_string_param(skb, "FILTER_TYPE", "DIRECTED");
irlan_insert_string_param(skb, "FILTER_OPERATION", "DYNAMIC");
- irttp_data_request(self->client.tsap_ctrl, skb);
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
irlan_insert_string_param(skb, "MEDIA", "802.3");
- irttp_data_request(self->client.tsap_ctrl, skb);
+ /* irttp_data_request(self->client.tsap_ctrl, skb); */
+ irlan_ctrl_data_request(self, skb);
}
/*
printk(KERN_INFO "Success\n");
break;
case 1:
- printk(KERN_WARNING "Insufficient resources\n");
+ WARNING("IrLAN: Insufficient resources\n");
break;
case 2:
- printk(KERN_WARNING "Invalid command format\n");
+ WARNING("IrLAN: Invalid command format\n");
break;
case 3:
- printk(KERN_WARNING "Command not supported\n");
+ WARNING("IrLAN: Command not supported\n");
break;
case 4:
- printk(KERN_WARNING "Parameter not supported\n");
+ WARNING("IrLAN: Parameter not supported\n");
break;
case 5:
- printk(KERN_WARNING "Value not supported\n");
+ WARNING("IrLAN: Value not supported\n");
break;
case 6:
- printk(KERN_WARNING "Not open\n");
+ WARNING("IrLAN: Not open\n");
break;
case 7:
- printk(KERN_WARNING "Authentication required\n");
+ WARNING("IrLAN: Authentication required\n");
break;
case 8:
- printk(KERN_WARNING "Invalid password\n");
+ WARNING("IrLAN: Invalid password\n");
break;
case 9:
- printk(KERN_WARNING "Protocol error\n");
+ WARNING("IrLAN: Protocol error\n");
break;
case 255:
- printk(KERN_WARNING "Asynchronous status\n");
+ WARNING("IrLAN: Asynchronous status\n");
break;
}
}
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Oct 15 08:37:58 1998
- * Modified at: Mon May 10 20:23:49 1999
+ * Modified at: Mon May 31 19:57:08 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>
struct irmanager_event mgr_event;
struct irlan_cb *self;
- DEBUG(0, __FUNCTION__"()\n");
+ DEBUG(2, __FUNCTION__"()\n");
ASSERT(dev != NULL, return -1;);
ether_setup(dev);
- dev->tx_queue_len = TTP_MAX_QUEUE;
+ /*
+ * Lets do all queueing in IrTTP instead of this device driver.
+ * Queueing here as well can introduce some strange latency
+ * problems, which we will avoid by setting the queue size to 0.
+ */
+ dev->tx_queue_len = 0;
if (self->provider.access_type == ACCESS_DIRECT) {
/*
{
struct irlan_cb *self;
- DEBUG(0, __FUNCTION__ "()\n");
+ DEBUG(2, __FUNCTION__ "()\n");
ASSERT(dev != NULL, return -1;);
{
struct irlan_cb *self = (struct irlan_cb *) dev->priv;
- DEBUG(0, __FUNCTION__ "()\n");
+ DEBUG(2, __FUNCTION__ "()\n");
/* Stop device */
dev->tbusy = 1;
int irlan_eth_xmit(struct sk_buff *skb, struct device *dev)
{
struct irlan_cb *self;
+ int ret;
self = (struct irlan_cb *) dev->priv;
ASSERT(self != NULL, return 0;);
ASSERT(self->magic == IRLAN_MAGIC, return 0;);
- /* Lock transmit buffer */
- if (irda_lock((void *) &dev->tbusy) == FALSE) {
- /*
- * If we get here, some higher level has decided we are broken.
- * There should really be a "kick me" function call instead.
- */
- int tickssofar = jiffies - dev->trans_start;
-
- if (tickssofar < 5)
- return -EBUSY;
-
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- }
+ /* Check if IrTTP can accept more frames */
+ if (dev->tbusy)
+ return -EBUSY;
/* skb headroom large enough to contain all IrDA-headers? */
if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
}
dev->trans_start = jiffies;
- self->stats.tx_packets++;
- self->stats.tx_bytes += skb->len;
/* Now queue the packet in the transport layer */
if (self->use_udata)
- irttp_udata_request(self->tsap_data, skb);
- else {
- if (irttp_data_request(self->tsap_data, skb) < 0) {
- /*
- * IrTTPs tx queue is full, so we just have to
- * drop the frame! You might think that we should
- * just return -1 and don't deallocate the frame,
- * but that is dangerous since it's possible that
- * we have replaced the original skb with a new
- * one with larger headroom, and that would really
- * confuse do_dev_queue_xmit() in dev.c! I have
- * tried :-) DB
- */
- dev_kfree_skb(skb);
- ++self->stats.tx_dropped;
-
- return 0;
- }
+ ret = irttp_udata_request(self->tsap_data, skb);
+ else
+ ret = irttp_data_request(self->tsap_data, skb);
+
+ if (ret < 0) {
+ /*
+ * IrTTPs tx queue is full, so we just have to
+ * drop the frame! You might think that we should
+ * just return -1 and don't deallocate the frame,
+ * but that is dangerous since it's possible that
+ * we have replaced the original skb with a new
+ * one with larger headroom, and that would really
+ * confuse do_dev_queue_xmit() in dev.c! I have
+ * tried :-) DB
+ */
+ dev_kfree_skb(skb);
+ self->stats.tx_dropped++;
+ } else {
+ self->stats.tx_packets++;
+ self->stats.tx_bytes += skb->len;
}
- dev->tbusy = 0; /* Finished! */
return 0;
}
skb->dev = &self->dev;
skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */
- netif_rx(skb); /* Eat it! */
-
self->stats.rx_packets++;
self->stats.rx_bytes += skb->len;
+ netif_rx(skb); /* Eat it! */
+
return 0;
}
struct irlan_cb *self;
struct device *dev;
- DEBUG(4, __FUNCTION__ "()\n");
-
self = (struct irlan_cb *) instance;
ASSERT(self != NULL, return;);
* 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)
+void irlan_eth_send_gratuitous_arp(struct device *dev)
{
struct in_device *in_dev;
self = dev->priv;
- DEBUG(0, __FUNCTION__ "()\n");
- return;
+ DEBUG(2, __FUNCTION__ "()\n");
+
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
- if (dev->flags&IFF_PROMISC) {
- /* Enable promiscuous mode */
- DEBUG(0, "Promiscous mode not implemented\n");
- /* outw(MULTICAST|PROMISC, ioaddr); */
+ /* Check if data channel has been connected yet */
+ if (self->client.state != IRLAN_DATA) {
+ DEBUG(1, __FUNCTION__ "(), delaying!\n");
+ return;
}
+
+ if (dev->flags & IFF_PROMISC) {
+ /* Enable promiscuous mode */
+ WARNING("Promiscous mode not implemented by IrLAN!\n");
+ }
else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) {
/* Disable promiscuous mode, use normal mode. */
DEBUG(4, __FUNCTION__ "(), Setting multicast filter\n");
irlan_set_multicast_filter(self, FALSE);
}
- if (dev->flags & IFF_BROADCAST) {
- DEBUG(4, __FUNCTION__ "(), Setting broadcast filter\n");
+ if (dev->flags & IFF_BROADCAST)
irlan_set_broadcast_filter(self, TRUE);
- } else {
- DEBUG(4, __FUNCTION__ "(), Clearing broadcast filter\n");
+ else
irlan_set_broadcast_filter(self, FALSE);
- }
}
/*
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Fri Jan 29 11:16:38 1999
- * Modified at: Sat May 8 15:25:23 1999
+ * Modified at: Fri May 14 23:11:01 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
********************************************************************/
#include <linux/skbuff.h>
+#include <linux/random.h>
#include <net/irda/irlan_common.h>
/*********************************************************************
*
* Filename: irlap.c
- * Version: 0.9
- * Description: An IrDA LAP driver for Linux
- * Status: Stable.
+ * Version: 1.0
+ * Description: IrLAP implementation for Linux
+ * Status: Stable
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Fri Apr 23 10:12:29 1999
+ * Modified at: Mon May 31 21:43:55 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
- * All Rights Reserved.
+ * Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
*
- * This program is free software; you can redistribute iyt and/or
+ * 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.
- *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
********************************************************************/
#include <linux/config.h>
};
#ifdef CONFIG_PROC_FS
-int irlap_proc_read( char *, char **, off_t, int, int);
+int irlap_proc_read(char *, char **, off_t, int, int);
#endif /* CONFIG_PROC_FS */
-__initfunc(int irlap_init( void))
+__initfunc(int irlap_init(void))
{
/* Allocate master array */
- irlap = hashbin_new( HB_LOCAL);
- if ( irlap == NULL) {
- printk( KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
+ irlap = hashbin_new(HB_LOCAL);
+ if (irlap == NULL) {
+ printk(KERN_WARNING "IrLAP: Can't allocate irlap hashbin!\n");
return -ENOMEM;
}
#ifdef CONFIG_IRDA_COMPRESSION
- irlap_compressors = hashbin_new( HB_LOCAL);
- if ( irlap_compressors == NULL) {
- printk( KERN_WARNING "IrLAP: Can't allocate compressors hashbin!\n");
+ irlap_compressors = hashbin_new(HB_LOCAL);
+ if (irlap_compressors == NULL) {
+ printk(KERN_WARNING "IrLAP: Can't allocate compressors hashbin!\n");
return -ENOMEM;
}
#endif
void irlap_cleanup(void)
{
- ASSERT( irlap != NULL, return;);
+ ASSERT(irlap != NULL, return;);
- hashbin_delete( irlap, (FREE_FUNC) __irlap_close);
+ hashbin_delete(irlap, (FREE_FUNC) __irlap_close);
#ifdef CONFIG_IRDA_COMPRESSION
- hashbin_delete( irlap_compressors, (FREE_FUNC) kfree);
+ hashbin_delete(irlap_compressors, (FREE_FUNC) kfree);
#endif
}
* Initialize IrLAP layer
*
*/
-struct irlap_cb *irlap_open( struct irda_device *irdev)
+struct irlap_cb *irlap_open(struct irda_device *irdev)
{
struct irlap_cb *self;
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
- ASSERT( irdev != NULL, return NULL;);
- ASSERT( irdev->magic == IRDA_DEVICE_MAGIC, return NULL;);
+ ASSERT(irdev != NULL, return NULL;);
+ ASSERT(irdev->magic == IRDA_DEVICE_MAGIC, return NULL;);
/* Initialize the irlap structure. */
- self = kmalloc( sizeof( struct irlap_cb), GFP_KERNEL);
- if ( self == NULL)
+ self = kmalloc(sizeof(struct irlap_cb), GFP_KERNEL);
+ if (self == NULL)
return NULL;
- memset( self, 0, sizeof(struct irlap_cb));
+ memset(self, 0, sizeof(struct irlap_cb));
self->magic = LAP_MAGIC;
/* Make a binding between the layers */
self->irdev = irdev;
self->netdev = &irdev->netdev;
- irlap_next_state( self, LAP_OFFLINE);
+ irlap_next_state(self, LAP_OFFLINE);
/* Initialize transmitt queue */
- skb_queue_head_init( &self->tx_list);
- skb_queue_head_init( &self->wx_list);
+ skb_queue_head_init(&self->tx_list);
+ skb_queue_head_init(&self->wx_list);
/* My unique IrLAP device address! */
get_random_bytes(&self->saddr, sizeof(self->saddr));
self->caddr &= 0xfe;
}
- init_timer( &self->slot_timer);
- init_timer( &self->query_timer);
- init_timer( &self->discovery_timer);
- init_timer( &self->final_timer);
- init_timer( &self->poll_timer);
- init_timer( &self->wd_timer);
- init_timer( &self->backoff_timer);
+ init_timer(&self->slot_timer);
+ init_timer(&self->query_timer);
+ init_timer(&self->discovery_timer);
+ init_timer(&self->final_timer);
+ init_timer(&self->poll_timer);
+ init_timer(&self->wd_timer);
+ init_timer(&self->backoff_timer);
- irlap_apply_default_connection_parameters( self);
+ irlap_apply_default_connection_parameters(self);
- irlap_next_state( self, LAP_NDM);
+ irlap_next_state(self, LAP_NDM);
- hashbin_insert( irlap, (QUEUE *) self, self->saddr, NULL);
+ hashbin_insert(irlap, (QUEUE *) self, self->saddr, NULL);
- irlmp_register_link( self, self->saddr, &self->notify);
+ irlmp_register_link(self, self->saddr, &self->notify);
return self;
}
* Remove IrLAP and all allocated memory. Stop any pending timers.
*
*/
-static void __irlap_close( struct irlap_cb *self)
+static void __irlap_close(struct irlap_cb *self)
{
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
/* Stop timers */
- del_timer( &self->slot_timer);
- del_timer( &self->query_timer);
- del_timer( &self->discovery_timer);
- del_timer( &self->final_timer);
- del_timer( &self->poll_timer);
- del_timer( &self->wd_timer);
- del_timer( &self->backoff_timer);
-
- irlap_flush_all_queues( self);
+ del_timer(&self->slot_timer);
+ del_timer(&self->query_timer);
+ del_timer(&self->discovery_timer);
+ del_timer(&self->final_timer);
+ del_timer(&self->poll_timer);
+ del_timer(&self->wd_timer);
+ del_timer(&self->backoff_timer);
+
+ irlap_flush_all_queues(self);
self->irdev = NULL;
self->magic = 0;
- kfree( self);
+ kfree(self);
}
/*
* Remove IrLAP instance
*
*/
-void irlap_close( struct irlap_cb *self)
+void irlap_close(struct irlap_cb *self)
{
struct irlap_cb *lap;
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
- irlap_disconnect_indication( self, LAP_DISC_INDICATION);
+ irlap_disconnect_indication(self, LAP_DISC_INDICATION);
irlmp_unregister_link(self->saddr);
self->notify.instance = NULL;
/* Be sure that we manage to remove ourself from the hash */
- lap = hashbin_remove( irlap, self->saddr, NULL);
- if ( !lap) {
- DEBUG( 1, __FUNCTION__ "(), Didn't find myself!\n");
+ lap = hashbin_remove(irlap, self->saddr, NULL);
+ if (!lap) {
+ DEBUG(1, __FUNCTION__ "(), Didn't find myself!\n");
return;
}
- __irlap_close( lap);
+ __irlap_close(lap);
}
/*
*/
void irlap_connect_response(struct irlap_cb *self, struct sk_buff *skb)
{
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
irlap_do_event(self, CONNECT_RESPONSE, skb, NULL);
}
* Received some data that was sent unreliable
*
*/
-void irlap_unit_data_indication( struct irlap_cb *self, struct sk_buff *skb)
+void irlap_unit_data_indication(struct irlap_cb *self, struct sk_buff *skb)
{
- DEBUG( 1, __FUNCTION__ "()\n");
+ DEBUG(1, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
- ASSERT( skb != NULL, return;);
+ 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) {
+ if (self->qos_tx.compression.value) {
- skb = irlap_decompress_frame( self, skb);
- if ( !skb) {
- DEBUG( 1, __FUNCTION__ "(), Decompress error!\n");
+ skb = irlap_decompress_frame(self, skb);
+ if (!skb) {
+ DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
return;
}
}
* Queue data for transmission, must wait until XMIT state
*
*/
-inline void irlap_data_request( struct irlap_cb *self, struct sk_buff *skb,
+inline void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb,
int reliable)
{
- DEBUG( 4, __FUNCTION__ "()\n");
-
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
- ASSERT( skb != NULL, return;);
-
- DEBUG( 4, __FUNCTION__ "(), tx_list=%d\n",
- skb_queue_len( &self->tx_list));
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+ ASSERT(skb != NULL, return;);
#ifdef CONFIG_IRDA_COMPRESSION
- if ( self->qos_tx.compression.value) {
- skb = irlap_compress_frame( self, skb);
- if ( !skb) {
- DEBUG( 1, __FUNCTION__ "(), Compress error!\n");
+ if (self->qos_tx.compression.value) {
+ skb = irlap_compress_frame(self, skb);
+ if (!skb) {
+ DEBUG(1, __FUNCTION__ "(), Compress error!\n");
return;
}
}
#endif
- ASSERT( skb_headroom( skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
- return;);
- skb_push( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+ ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER),
+ return;);
+ skb_push(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
/*
* Must set frame format now so that the rest of the code knows
* if its dealing with an I or an UI frame
*/
- if ( reliable)
+ if (reliable)
skb->data[1] = I_FRAME;
else {
- DEBUG( 4, __FUNCTION__ "(), queueing unreliable frame\n");
+ DEBUG(4, __FUNCTION__ "(), queueing unreliable frame\n");
skb->data[1] = UI_FRAME;
}
* Send event if this frame only if we are in the right state
* FIXME: udata should be sent first! (skb_queue_head?)
*/
- if (( self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
+ if ((self->state == LAP_XMIT_P) || (self->state == LAP_XMIT_S)) {
/*
* Check if the transmit queue contains some unsent frames,
* and if so, make sure they are sent first
*/
- if ( !skb_queue_empty( &self->tx_list)) {
- skb_queue_tail( &self->tx_list, skb);
- skb = skb_dequeue( &self->tx_list);
+ if (!skb_queue_empty(&self->tx_list)) {
+ skb_queue_tail(&self->tx_list, skb);
+ skb = skb_dequeue(&self->tx_list);
- ASSERT( skb != NULL, return;);
+ ASSERT(skb != NULL, return;);
}
- irlap_do_event( self, SEND_I_CMD, skb, NULL);
+ irlap_do_event(self, SEND_I_CMD, skb, NULL);
} else
- skb_queue_tail( &self->tx_list, skb);
+ skb_queue_tail(&self->tx_list, skb);
}
/*
* Disconnect request from other device
*
*/
-void irlap_disconnect_indication( struct irlap_cb *self, LAP_REASON reason)
+void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason)
{
- DEBUG( 1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]);
+ DEBUG(1, __FUNCTION__ "(), reason=%s\n", lap_reasons[reason]);
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
#ifdef CONFIG_IRDA_COMPRESSION
- irda_free_compression( self);
+ irda_free_compression(self);
#endif
/* Flush queues */
- irlap_flush_all_queues( self);
+ irlap_flush_all_queues(self);
- switch( reason) {
+ switch(reason) {
case LAP_RESET_INDICATION:
- DEBUG( 1, __FUNCTION__ "(), Sending reset request!\n");
- irlap_do_event( self, RESET_REQUEST, NULL, NULL);
+ DEBUG(1, __FUNCTION__ "(), Sending reset request!\n");
+ irlap_do_event(self, RESET_REQUEST, NULL, NULL);
break;
case LAP_NO_RESPONSE: /* FALLTROUGH */
case LAP_DISC_INDICATION: /* FALLTROUGH */
case LAP_FOUND_NONE: /* FALLTROUGH */
case LAP_MEDIA_BUSY:
- irlmp_link_disconnect_indication( self->notify.instance,
+ irlmp_link_disconnect_indication(self->notify.instance,
self, reason, NULL);
break;
default:
- DEBUG( 1, __FUNCTION__ "(), Reason %d not implemented!\n",
+ DEBUG(1, __FUNCTION__ "(), Reason %d not implemented!\n",
reason);
}
}
{
struct irlap_info info;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
- ASSERT( discovery != NULL, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+ ASSERT(discovery != NULL, return;);
- DEBUG( 4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
+ DEBUG(4, __FUNCTION__ "(), nslots = %d\n", discovery->nslots);
- ASSERT(( discovery->nslots == 1) || ( discovery->nslots == 6) ||
- ( discovery->nslots == 8) || ( discovery->nslots == 16),
+ ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) ||
+ (discovery->nslots == 8) || (discovery->nslots == 16),
return;);
/*
* Discovery is only possible in NDM mode
*/
- if ( self->state == LAP_NDM) {
- ASSERT( self->discovery_log == NULL, return;);
- self->discovery_log= hashbin_new( HB_LOCAL);
+ if (self->state == LAP_NDM) {
+ ASSERT(self->discovery_log == NULL, return;);
+ self->discovery_log= hashbin_new(HB_LOCAL);
info.S = discovery->nslots; /* Number of slots */
info.s = 0; /* Current slot */
self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
- irlap_do_event( self, DISCOVERY_REQUEST, NULL, &info);
+ irlap_do_event(self, DISCOVERY_REQUEST, NULL, &info);
} else {
- DEBUG( 4, __FUNCTION__
+ DEBUG(4, __FUNCTION__
"(), discovery only possible in NDM mode\n");
- irlap_discovery_confirm( self, NULL);
+ irlap_discovery_confirm(self, NULL);
}
}
* A device has been discovered in front of this station, we
* report directly to LMP.
*/
-void irlap_discovery_confirm( struct irlap_cb *self, hashbin_t *discovery_log)
+void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log)
{
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
- ASSERT( self->notify.instance != NULL, return;);
+ ASSERT(self->notify.instance != NULL, return;);
/*
* Check for successful discovery, since we are then allowed to clear
irda_device_set_media_busy(self->irdev, FALSE);
/* Inform IrLMP */
- irlmp_link_discovery_confirm( self->notify.instance, discovery_log);
+ irlmp_link_discovery_confirm(self->notify.instance, discovery_log);
/*
* IrLMP has now the responsibilities for the discovery_log
*/
void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery)
{
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
- ASSERT( discovery != NULL, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+ ASSERT(discovery != NULL, return;);
- ASSERT( self->notify.instance != NULL, return;);
+ ASSERT(self->notify.instance != NULL, return;);
irlmp_link_discovery_indication(self->notify.instance, discovery);
}
*/
void irlap_status_indication(int quality_of_link)
{
- switch( quality_of_link) {
+ switch(quality_of_link) {
case STATUS_NO_ACTIVITY:
- printk( KERN_INFO "IrLAP, no activity on link!\n");
+ printk(KERN_INFO "IrLAP, no activity on link!\n");
break;
case STATUS_NOISY:
- printk( KERN_INFO "IrLAP, noisy link!\n");
+ printk(KERN_INFO "IrLAP, noisy link!\n");
break;
default:
break;
*
*
*/
-void irlap_reset_indication( struct irlap_cb *self)
+void irlap_reset_indication(struct irlap_cb *self)
{
- DEBUG( 1, __FUNCTION__ "()\n");
+ DEBUG(1, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
- if ( self->state == LAP_RESET_WAIT)
- irlap_do_event( self, RESET_REQUEST, NULL, NULL);
+ if (self->state == LAP_RESET_WAIT)
+ irlap_do_event(self, RESET_REQUEST, NULL, NULL);
else
- irlap_do_event( self, RESET_RESPONSE, NULL, NULL);
+ irlap_do_event(self, RESET_RESPONSE, NULL, NULL);
}
/*
*/
void irlap_reset_confirm(void)
{
- DEBUG( 1, __FUNCTION__ "()\n");
+ DEBUG(1, __FUNCTION__ "()\n");
}
/*
* S = Number of slots (0 -> S-1)
* s = Current slot
*/
-int irlap_generate_rand_time_slot( int S, int s)
+int irlap_generate_rand_time_slot(int S, int s)
{
int slot;
- ASSERT(( S - s) > 0, return 0;);
+ ASSERT((S - s) > 0, return 0;);
slot = s + jiffies % (S-s);
- ASSERT(( slot >= s) || ( slot < S), return 0;);
+ ASSERT((slot >= s) || (slot < S), return 0;);
return slot;
}
* not intuitive and you should not try to change it. If you think it
* contains bugs, please mail a patch to the author instead.
*/
-void irlap_update_nr_received( struct irlap_cb *self, int nr)
+void irlap_update_nr_received(struct irlap_cb *self, int nr)
{
struct sk_buff *skb = NULL;
int count = 0;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
/*
* Remove all the ack-ed frames from the window queue.
*/
- DEBUG( 4, "--> wx_list=%d, va=%d, nr=%d\n",
- skb_queue_len( &self->wx_list), self->va, nr);
+ DEBUG(4, "--> wx_list=%d, va=%d, nr=%d\n",
+ skb_queue_len(&self->wx_list), self->va, nr);
/*
* Optimize for the common case. It is most likely that the receiver
* will acknowledge all the frames we have sent! So in that case we
* delete all frames stored in window.
*/
- if ( nr == self->vs) {
- while (( skb = skb_dequeue( &self->wx_list)) != NULL) {
+ if (nr == self->vs) {
+ while ((skb = skb_dequeue(&self->wx_list)) != NULL) {
dev_kfree_skb(skb);
}
/* The last acked frame is the next to send minus one */
self->va = nr - 1;
} else {
/* Remove all acknowledged frames in current window */
- while (( skb_peek( &self->wx_list) != NULL) &&
- ((( self->va+1) % 8) != nr))
+ while ((skb_peek(&self->wx_list) != NULL) &&
+ (((self->va+1) % 8) != nr))
{
- skb = skb_dequeue( &self->wx_list);
+ skb = skb_dequeue(&self->wx_list);
dev_kfree_skb(skb);
self->va = (self->va + 1) % 8;
count++;
}
- DEBUG( 4, "irlap_update_nr_received(), removed %d\n", count);
- DEBUG( 4, "wx_list=%d, va=%d, nr=%d -->\n",
- skb_queue_len( &self->wx_list), self->va, nr);
+ DEBUG(4, "irlap_update_nr_received(), removed %d\n", count);
+ DEBUG(4, "wx_list=%d, va=%d, nr=%d -->\n",
+ skb_queue_len(&self->wx_list), self->va, nr);
}
/* Advance window */
- self->window = self->window_size - skb_queue_len( &self->wx_list);
+ self->window = self->window_size - skb_queue_len(&self->wx_list);
}
/*
*
* Validate the next to send (ns) field from received frame.
*/
-int irlap_validate_ns_received( struct irlap_cb *self, int ns)
+int irlap_validate_ns_received(struct irlap_cb *self, int ns)
{
- ASSERT( self != NULL, return -ENODEV;);
- ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+ ASSERT(self != NULL, return -ENODEV;);
+ ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
/* ns as expected? */
- if ( ns == self->vr) {
- DEBUG( 4, __FUNCTION__ "(), expected!\n");
+ if (ns == self->vr) {
+ DEBUG(4, __FUNCTION__ "(), expected!\n");
return NS_EXPECTED;
}
/*
* Validate the next to receive (nr) field from received frame.
*
*/
-int irlap_validate_nr_received( struct irlap_cb *self, int nr)
+int irlap_validate_nr_received(struct irlap_cb *self, int nr)
{
- ASSERT( self != NULL, return -ENODEV;);
- ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+ ASSERT(self != NULL, return -ENODEV;);
+ ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
/* nr as expected? */
- if ( nr == self->vs) {
- DEBUG( 4, __FUNCTION__ "(), expected!\n");
+ if (nr == self->vs) {
+ DEBUG(4, __FUNCTION__ "(), expected!\n");
return NR_EXPECTED;
}
* unexpected nr? (but within current window), first we check if the
* ns numbers of the frames in the current window wrap.
*/
- if ( self->va < self->vs) {
- if (( nr >= self->va) && ( nr <= self->vs))
+ if (self->va < self->vs) {
+ if ((nr >= self->va) && (nr <= self->vs))
return NR_UNEXPECTED;
} else {
- if (( nr >= self->va) || ( nr <= self->vs))
+ if ((nr >= self->va) || (nr <= self->vs))
return NR_UNEXPECTED;
}
* Initialize the connection state parameters
*
*/
-void irlap_initiate_connection_state( struct irlap_cb *self)
+void irlap_initiate_connection_state(struct irlap_cb *self)
{
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
/* Next to send and next to receive */
self->vs = self->vr = 0;
* Flush all queues
*
*/
-void irlap_flush_all_queues( struct irlap_cb *self)
+void irlap_flush_all_queues(struct irlap_cb *self)
{
struct sk_buff* skb;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
/* Free transmission queue */
- while (( skb = skb_dequeue( &self->tx_list)) != NULL)
- dev_kfree_skb( skb);
+ while ((skb = skb_dequeue(&self->tx_list)) != NULL)
+ dev_kfree_skb(skb);
/* Free sliding window buffered packets */
- while (( skb = skb_dequeue( &self->wx_list)) != NULL)
- dev_kfree_skb( skb);
+ while ((skb = skb_dequeue(&self->wx_list)) != NULL)
+ dev_kfree_skb(skb);
#ifdef CONFIG_IRDA_RECYCLE_RR
- if ( self->recycle_rr_skb) {
- dev_kfree_skb( self->recycle_rr_skb);
+ if (self->recycle_rr_skb) {
+ dev_kfree_skb(self->recycle_rr_skb);
self->recycle_rr_skb = NULL;
}
#endif
ASSERT(self->magic == LAP_MAGIC, return;);
if (!self->irdev) {
- DEBUG( 1, __FUNCTION__ "(), driver missing!\n");
+ DEBUG(1, __FUNCTION__ "(), driver missing!\n");
return;
}
__u8 mask; /* Current bit tested */
int i;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
/*
* Find out which compressors we support. We do this be checking that
* actually been loaded. Ths is sort of hairy code but that is what
* you get when you do a little bit flicking :-)
*/
- DEBUG( 4, __FUNCTION__ "(), comp bits 0x%02x\n",
+ DEBUG(4, __FUNCTION__ "(), comp bits 0x%02x\n",
self->qos_rx.compression.bits);
mask = 0x80; /* Start with testing MSB */
- for ( i=0;i<8;i++) {
- DEBUG( 4, __FUNCTION__ "(), testing bit %d\n", 8-i);
- if ( self->qos_rx.compression.bits & mask) {
- DEBUG( 4, __FUNCTION__ "(), bit %d is set by defalt\n",
+ for (i=0;i<8;i++) {
+ DEBUG(4, __FUNCTION__ "(), testing bit %d\n", 8-i);
+ if (self->qos_rx.compression.bits & mask) {
+ DEBUG(4, __FUNCTION__ "(), bit %d is set by defalt\n",
8-i);
- comp = hashbin_find( irlap_compressors,
+ comp = hashbin_find(irlap_compressors,
compression[ msb_index(mask)],
NULL);
- if ( !comp) {
+ if (!comp) {
/* Protocol not supported, so clear the bit */
- DEBUG( 4, __FUNCTION__ "(), Compression "
+ DEBUG(4, __FUNCTION__ "(), Compression "
"protocol %d has not been loaded!\n",
compression[msb_index(mask)]);
self->qos_rx.compression.bits &= ~mask;
- DEBUG( 4, __FUNCTION__
+ DEBUG(4, __FUNCTION__
"(), comp bits 0x%02x\n",
self->qos_rx.compression.bits);
}
void irlap_init_qos_capabilities(struct irlap_cb *self,
struct qos_info *qos_user)
{
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
- ASSERT( self->irdev != NULL, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
+ ASSERT(self->irdev != NULL, return;);
/* Start out with the maximum QoS support possible */
- irda_init_max_qos_capabilies( &self->qos_rx);
+ irda_init_max_qos_capabilies(&self->qos_rx);
#ifdef CONFIG_IRDA_COMPRESSION
- irlap_init_comp_qos_capabilities( self);
+ irlap_init_comp_qos_capabilities(self);
#endif
/* Apply drivers QoS capabilities */
- irda_qos_compute_intersection( &self->qos_rx,
- irda_device_get_qos( self->irdev));
+ irda_qos_compute_intersection(&self->qos_rx,
+ irda_device_get_qos(self->irdev));
/*
* Check for user supplied QoS parameters. The service user is only
* user may not have set all of them.
*/
if (qos_user) {
- DEBUG( 1, __FUNCTION__ "(), Found user specified QoS!\n");
+ DEBUG(1, __FUNCTION__ "(), Found user specified QoS!\n");
- if ( qos_user->baud_rate.bits)
+ if (qos_user->baud_rate.bits)
self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits;
- if ( qos_user->max_turn_time.bits)
+ if (qos_user->max_turn_time.bits)
self->qos_rx.max_turn_time.bits &= qos_user->max_turn_time.bits;
- if ( qos_user->data_size.bits)
+ if (qos_user->data_size.bits)
self->qos_rx.data_size.bits &= qos_user->data_size.bits;
- if ( qos_user->link_disc_time.bits)
+ if (qos_user->link_disc_time.bits)
self->qos_rx.link_disc_time.bits &= qos_user->link_disc_time.bits;
#ifdef CONFIG_IRDA_COMPRESSION
self->qos_rx.compression.bits &= qos_user->compression.bits;
/* Set disconnect time */
self->qos_rx.link_disc_time.bits &= 0x07;
- irda_qos_bits_to_value( &self->qos_rx);
+ irda_qos_bits_to_value(&self->qos_rx);
}
/*
* Use the default connection and transmission parameters
*
*/
-void irlap_apply_default_connection_parameters( struct irlap_cb *self)
+void irlap_apply_default_connection_parameters(struct irlap_cb *self)
{
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
- irlap_change_speed( self, 9600);
+ irlap_change_speed(self, 9600);
/* Default value in NDM */
self->bofs_count = 11;
void irlap_apply_connection_parameters(struct irlap_cb *self,
struct qos_info *qos)
{
- DEBUG( 4, __FUNCTION__ "()\n");
+ DEBUG(4, __FUNCTION__ "()\n");
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
+ ASSERT(self != NULL, return;);
+ ASSERT(self->magic == LAP_MAGIC, return;);
- irlap_change_speed( self, qos->baud_rate.value);
+ irlap_change_speed(self, qos->baud_rate.value);
self->window_size = qos->window_size.value;
self->window = qos->window_size.value;
*/
self->window_bytes = qos->baud_rate.value
* qos->max_turn_time.value / 10000;
- DEBUG( 4, "Setting window_bytes = %d\n", self->window_bytes);
+ DEBUG(4, "Setting window_bytes = %d\n", self->window_bytes);
/*
* Set N1 to 0 if Link Disconnect/Threshold Time = 3 and set it to
else
self->N1 = 3000 / qos->max_turn_time.value;
- DEBUG( 4, "Setting N1 = %d\n", self->N1);
+ DEBUG(4, "Setting N1 = %d\n", self->N1);
self->N2 = qos->link_disc_time.value * 1000 / qos->max_turn_time.value;
- DEBUG( 4, "Setting N2 = %d\n", self->N2);
+ DEBUG(4, "Setting N2 = %d\n", self->N2);
/*
* Initialize timeout values, some of the rules are listed on
self->wd_timeout = self->poll_timeout * 2;
#ifdef CONFIG_IRDA_COMPRESSION
- if ( qos->compression.value) {
- DEBUG( 1, __FUNCTION__ "(), Initializing compression\n");
- irda_set_compression( self, qos->compression.value);
+ if (qos->compression.value) {
+ DEBUG(1, __FUNCTION__ "(), Initializing compression\n");
+ irda_set_compression(self, qos->compression.value);
- irlap_compressor_init( self, 0);
+ irlap_compressor_init(self, 0);
}
#endif
}
* Give some info to the /proc file system
*
*/
-int irlap_proc_read( char *buf, char **start, off_t offset, int len,
+int irlap_proc_read(char *buf, char **start, off_t offset, int len,
int unused)
{
struct irlap_cb *self;
len = 0;
- self = (struct irlap_cb *) hashbin_get_first( irlap);
- while ( self != NULL) {
- ASSERT( self != NULL, return -ENODEV;);
- ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
+ self = (struct irlap_cb *) hashbin_get_first(irlap);
+ while (self != NULL) {
+ ASSERT(self != NULL, return -ENODEV;);
+ ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
- len += sprintf( buf+len, "irlap%d <-> %s ",
+ len += sprintf(buf+len, "irlap%d <-> %s ",
i++, self->irdev->name);
- len += sprintf( buf+len, "state: %s\n",
+ len += sprintf(buf+len, "state: %s\n",
irlap_state[ self->state]);
- len += sprintf( buf+len, " caddr: %#02x, ", self->caddr);
- len += sprintf( buf+len, "saddr: %#08x, ", self->saddr);
- len += sprintf( buf+len, "daddr: %#08x\n", self->daddr);
+ len += sprintf(buf+len, " caddr: %#02x, ", self->caddr);
+ len += sprintf(buf+len, "saddr: %#08x, ", self->saddr);
+ len += sprintf(buf+len, "daddr: %#08x\n", self->daddr);
- len += sprintf( buf+len, " win size: %d, ",
+ len += sprintf(buf+len, " win size: %d, ",
self->window_size);
- len += sprintf( buf+len, "win: %d, ", self->window);
- len += sprintf( buf+len, "win bytes: %d, ", self->window_bytes);
- len += sprintf( buf+len, "bytes left: %d\n", self->bytes_left);
-
- len += sprintf( buf+len, " tx queue len: %d ",
- skb_queue_len( &self->tx_list));
- len += sprintf( buf+len, "win queue len: %d ",
- skb_queue_len( &self->wx_list));
- len += sprintf( buf+len, "rbusy: %s\n", self->remote_busy ?
+ len += sprintf(buf+len, "win: %d, ", self->window);
+ len += sprintf(buf+len, "win bytes: %d, ", self->window_bytes);
+ len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left);
+
+ len += sprintf(buf+len, " tx queue len: %d ",
+ skb_queue_len(&self->tx_list));
+ len += sprintf(buf+len, "win queue len: %d ",
+ skb_queue_len(&self->wx_list));
+ len += sprintf(buf+len, "rbusy: %s\n", self->remote_busy ?
"TRUE" : "FALSE");
- len += sprintf( buf+len, " retrans: %d ", self->retry_count);
- len += sprintf( buf+len, "vs: %d ", self->vs);
- len += sprintf( buf+len, "vr: %d ", self->vr);
- len += sprintf( buf+len, "va: %d\n", self->va);
+ len += sprintf(buf+len, " retrans: %d ", self->retry_count);
+ len += sprintf(buf+len, "vs: %d ", self->vs);
+ len += sprintf(buf+len, "vr: %d ", self->vr);
+ len += sprintf(buf+len, "va: %d\n", self->va);
- len += sprintf( buf+len, " qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
+ len += sprintf(buf+len, " qos\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\tcomp\n");
- len += sprintf( buf+len, " tx\t%d\t",
+ len += sprintf(buf+len, " tx\t%d\t",
self->qos_tx.baud_rate.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_tx.max_turn_time.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_tx.data_size.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_tx.window_size.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_tx.additional_bofs.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_tx.min_turn_time.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_tx.link_disc_time.value);
#ifdef CONFIG_IRDA_COMPRESSION
- len += sprintf( buf+len, "%d",
+ len += sprintf(buf+len, "%d",
self->qos_tx.compression.value);
#endif
- len += sprintf( buf+len, "\n");
+ len += sprintf(buf+len, "\n");
- len += sprintf( buf+len, " rx\t%d\t",
+ len += sprintf(buf+len, " rx\t%d\t",
self->qos_rx.baud_rate.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_rx.max_turn_time.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_rx.data_size.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_rx.window_size.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_rx.additional_bofs.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_rx.min_turn_time.value);
- len += sprintf( buf+len, "%d\t",
+ len += sprintf(buf+len, "%d\t",
self->qos_rx.link_disc_time.value);
#ifdef CONFIG_IRDA_COMPRESSION
- len += sprintf( buf+len, "%d",
+ len += sprintf(buf+len, "%d",
self->qos_rx.compression.value);
#endif
- len += sprintf( buf+len, "\n");
+ len += sprintf(buf+len, "\n");
- self = (struct irlap_cb *) hashbin_get_next( irlap);
+ self = (struct irlap_cb *) hashbin_get_next(irlap);
}
restore_flags(flags);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sat Aug 16 00:59:29 1997
- * Modified at: Sun May 9 22:44:32 1999
+ * Modified at: Mon May 31 21:55:42 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
* Rushes through the state machine without any delay. If state == XMIT
* then send queued data frames.
*/
-void irlap_do_event( struct irlap_cb *self, IRLAP_EVENT event,
- struct sk_buff *skb, struct irlap_info *info)
+void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
+ struct sk_buff *skb, struct irlap_info *info)
{
int ret;
return;
DEBUG(4, __FUNCTION__ "(), event = %s, state = %s\n",
- irlap_event[ event], irlap_state[ self->state]);
+ irlap_event[event], irlap_state[self->state]);
ret = (*state[ self->state]) (self, event, skb, info);
if (skb_queue_len(&self->tx_list)) {
/* Try to send away all queued data frames */
while ((skb = skb_dequeue(&self->tx_list)) != NULL) {
- ret = (*state[ self->state])(self, SEND_I_CMD,
- skb, NULL);
+ ret = (*state[self->state])(self, SEND_I_CMD,
+ skb, NULL);
if ( ret == -EPROTO)
break; /* Try again later! */
}
} else if (self->disconnect_pending) {
- DEBUG(0, __FUNCTION__ "(), disconnecting!\n");
self->disconnect_pending = FALSE;
ret = (*state[self->state])(self, DISCONNECT_REQUEST,
* stations.
*
*/
-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_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
+ struct sk_buff *skb, struct irlap_info *info)
{
int ret = 0;
- ASSERT( self != NULL, return -ENODEV;);
- ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
-
- DEBUG( 4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d",
- irlap_event[ event], self->vs, self->vr);
+ DEBUG(4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d",
+ irlap_event[event], self->vs, self->vr);
switch (event) {
case SEND_I_CMD:
- ASSERT( skb != NULL, return -1;);
- DEBUG( 4, __FUNCTION__ "(), Window=%d\n", self->window);
-
/*
* Only send frame if send-window > 0.
*/
- if (( self->window > 0) && ( !self->remote_busy)) {
+ if ((self->window > 0) && (!self->remote_busy)) {
/*
* Test if we have transmitted more bytes over the
* link than its possible to do with the current
* speed and turn-around-time.
*/
- if (( skb->len+self->bofs_count) > self->bytes_left) {
- DEBUG( 4, __FUNCTION__ "(), Not allowed to "
- "transmit more bytes!\n");
- skb_queue_head( &self->tx_list, skb);
+ if ((skb->len+self->bofs_count) > self->bytes_left) {
+ DEBUG(4, __FUNCTION__ "(), Not allowed to "
+ "transmit more bytes!\n");
+ skb_queue_head(&self->tx_list, skb);
/*
* We should switch state to LAP_NRM_P, but
*/
return -EPROTO;
}
- self->bytes_left -= ( skb->len + self->bofs_count);
+ self->bytes_left -= (skb->len + self->bofs_count);
/*
* Send data with poll bit cleared only if window > 1
if (( self->window > 1) &&
skb_queue_len( &self->tx_list) > 0)
{
- DEBUG( 4, __FUNCTION__ "(), window > 1\n");
irlap_send_data_primary( self, skb);
irlap_next_state( self, LAP_XMIT_P);
} else {
- DEBUG( 4, __FUNCTION__ "(), window <= 1\n");
irlap_send_data_primary_poll( self, skb);
irlap_next_state( self, LAP_NRM_P);
int ns_status;
int nr_status;
- ASSERT(self != NULL, return -1;);
- ASSERT(self->magic == LAP_MAGIC, return -1;);
-
switch (event) {
case RECV_I_RSP: /* Optimize for the common case */
/* FIXME: must check for remote_busy below */
*/
self->fast_RR = FALSE;
#endif
-
ASSERT( info != NULL, return -1;);
ns_status = irlap_validate_ns_received(self, info->ns);
}
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
/* 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 "
irlap_next_state( self, LAP_RESET_WAIT);
- irlap_disconnect_indication( self,
- LAP_RESET_INDICATION);
+ irlap_disconnect_indication(self, LAP_RESET_INDICATION);
self->xmitflag = TRUE;
}
if (skb)
/*
* Send frame only if send window > 1
*/
- if (( self->window > 0) && ( !self->remote_busy)) {
+ if ((self->window > 0) && ( !self->remote_busy)) {
/*
* Test if we have transmitted more bytes over the
* link than its possible to do with the current
* speed and turn-around-time.
*/
- if (( skb->len+self->bofs_count) > self->bytes_left) {
+ if ((skb->len+self->bofs_count) > self->bytes_left) {
DEBUG( 4, "IrDA: Not allowed to transmit more bytes!\n");
skb_queue_head( &self->tx_list, skb);
/*
if (( self->window > 1) &&
skb_queue_len( &self->tx_list) > 0)
{
- DEBUG( 4, __FUNCTION__ "(), window > 1\n");
irlap_send_data_secondary( self, skb);
irlap_next_state( self, LAP_XMIT_S);
} else {
- DEBUG( 4, "(), window <= 1\n");
irlap_send_data_secondary_final( self, skb);
irlap_next_state( self, LAP_NRM_S);
/*
* Check for Unexpected next to send (Ns)
*/
- if (( ns_status == NS_UNEXPECTED) &&
- ( nr_status == NR_EXPECTED))
+ if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
{
/* Unexpected next to send, with final bit cleared */
if ( !info->pf) {
/*
* 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) {
DEBUG( 4, "RECV_I_RSP: frame(s) lost\n");
irlap_update_nr_received( self, info->nr);
del_timer( &self->wd_timer);
- irlap_wait_min_turn_around( self, &self->qos_tx);
+ 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_update_nr_received(self, info->nr);
+ irlap_wait_min_turn_around(self, &self->qos_tx);
- irlap_send_rr_frame( self, RSP_FRAME);
+ irlap_send_rr_frame(self, RSP_FRAME);
- irlap_start_wd_timer( self, self->wd_timeout);
- irlap_next_state( self, LAP_NRM_S);
+ irlap_start_wd_timer(self, self->wd_timeout);
+ irlap_next_state(self, LAP_NRM_S);
}
- } else if ( nr_status == NR_UNEXPECTED) {
+ } else if (nr_status == NR_UNEXPECTED) {
self->remote_busy = FALSE;
irlap_update_nr_received( self, info->nr);
irlap_resend_rejected_frames( self, RSP_FRAME);
} else {
DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
}
- if ( skb)
- dev_kfree_skb( skb);
+ if (skb)
+ dev_kfree_skb(skb);
break;
case RECV_SNRM_CMD:
ASSERT( self != NULL, return -ENODEV;);
ASSERT( self->magic == LAP_MAGIC, return -EBADR;);
- switch( event) {
+ switch(event) {
case RESET_RESPONSE:
irlap_send_ua_response_frame( self, &self->qos_rx);
irlap_initiate_connection_state( self);
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Aug 19 10:27:26 1997
- * Modified at: Sun May 9 22:55:11 1999
+ * Modified at: Mon May 31 09:29:13 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
{
__u8 *frame;
- ASSERT( self != NULL, return;);
- ASSERT( self->magic == LAP_MAGIC, return;);
- ASSERT( skb != NULL, return;);
-
frame = skb->data;
/* Insert connection address */
/* 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);
}
* Optimize for the common case and check if the frame is an
* I(nformation) frame. Only I-frames have bit 0 set to 0
*/
- if(~control & 0x01) {
+ if (~control & 0x01) {
irlap_recv_i_frame(self, skb, &info, command);
self->stats.rx_packets++;
return 0;
* Status: Stable.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 17 20:54:32 1997
- * Modified at: Sun May 9 22:45:06 1999
+ * Modified at: Mon May 31 21:49:41 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
ASSERT(skb != NULL, return;);
ASSERT(self->lap != NULL, return;);
- DEBUG(0, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
+ DEBUG(2, __FUNCTION__ "(), slsap_sel=%02x, dlsap_sel=%02x\n",
self->slsap_sel, self->dlsap_sel);
self->qos = *self->lap->qos;
- lap_header_size = irlap_get_header_size(self->lap->irlap);
-
- max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
- lap_header_size;
+ max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+ lap_header_size = irlap_get_header_size(self->lap->irlap);
+
max_header_size = LMP_HEADER + lap_header_size;
DEBUG(2, __FUNCTION__ "(), max_header_size=%d\n", max_header_size);
ASSERT(self->lap != NULL, return;);
self->qos = *self->lap->qos;
- lap_header_size = irlap_get_header_size(self->lap->irlap);
-
- max_seg_size = self->lap->qos->data_size.value-LMP_HEADER-
- lap_header_size;
+ max_seg_size = self->lap->qos->data_size.value-LMP_HEADER;
DEBUG(2, __FUNCTION__ "(), max_seg_size=%d\n", max_seg_size);
+
+ lap_header_size = irlap_get_header_size(self->lap->irlap);
max_header_size = LMP_HEADER + lap_header_size;
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Tue Aug 19 02:09:59 1997
- * Modified at: Sun May 9 21:00:05 1999
+ * Modified at: Mon May 31 09:53:16 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>
self->lsaps);
if (lsap == NULL) {
- DEBUG(0, "IrLMP, Sorry, no LSAP for received frame!\n");
- DEBUG(0, __FUNCTION__
+ DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n");
+ DEBUG(2, __FUNCTION__
"(), slsap_sel = %02x, dlsap_sel = %02x\n", slsap_sel,
dlsap_sel);
if (fp[0] & CONTROL_BIT) {
- DEBUG(0, __FUNCTION__
+ DEBUG(2, __FUNCTION__
"(), received control frame %02x\n", fp[2]);
} else {
- DEBUG(0, __FUNCTION__ "(), received data frame\n");
+ DEBUG(2, __FUNCTION__ "(), received data frame\n");
}
- dev_kfree_skb( skb);
+ dev_kfree_skb(skb);
return;
}
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Dec 15 13:55:39 1997
- * Modified at: Mon May 10 15:28:49 1999
+ * Modified at: Fri May 14 13:46:02 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1997, 1999 Dag Brattli, All Rights Reserved.
#include <net/irda/wrapper.h>
#include <net/irda/timer.h>
-extern struct proc_dir_entry proc_irda;
+extern struct proc_dir_entry *proc_irda;
struct irda_cb irda; /* One global instance */
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Sun Aug 31 20:14:31 1997
- * Modified at: Mon May 10 17:12:53 1999
+ * Modified at: Mon May 31 10:29:56 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
#include <net/irda/irlmp.h>
#include <net/irda/irttp.h>
-struct irttp_cb *irttp = NULL;
+static struct irttp_cb *irttp = NULL;
static void __irttp_close_tsap(struct tsap_cb *self);
static int irttp_udata_indication(void *instance, void *sap,
struct sk_buff *skb);
static void irttp_disconnect_indication(void *instance, void *sap,
- LM_REASON reason,
- struct sk_buff *);
+ LM_REASON reason, struct sk_buff *);
static void irttp_connect_indication(void *instance, void *sap,
struct qos_info *qos, __u32 max_sdu_size,
__u8 header_size, struct sk_buff *skb);
static void irttp_flush_queues(struct tsap_cb *self);
static void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *skb);
-static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
static void irttp_start_todo_timer(struct tsap_cb *self, int timeout);
+static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self);
/*
* Function irttp_init (void)
/* Check that nothing bad happens */
if ((skb->len == 0) || (!self->connected)) {
- DEBUG(4, __FUNCTION__ "(), No data, or not connected\n");
+ ERROR(__FUNCTION__ "(), No data, or not connected\n");
return -ENOTCONN;
}
* inside an IrLAP frame
*/
if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) {
- DEBUG(1, __FUNCTION__
- "(), SAR disabled, and data is to large for IrLAP!\n");
+ ERROR(__FUNCTION__
+ "(), SAR disabled, and data is to large for IrLAP!\n");
return -EMSGSIZE;
}
(self->tx_max_sdu_size != SAR_UNBOUND) &&
(skb->len > self->tx_max_sdu_size))
{
- DEBUG(1, __FUNCTION__ "(), SAR enabled, "
- "but data is larger than TxMaxSduSize!\n");
+ ERROR(__FUNCTION__ "(), SAR enabled, "
+ "but data is larger than TxMaxSduSize!\n");
return -EMSGSIZE;
}
/*
frame = skb_push(skb, TTP_HEADER);
frame[0] = 0x00; /* Clear more bit */
- DEBUG(4, __FUNCTION__ "(), queueing original skb\n");
skb_queue_tail(&self->tx_queue, skb);
} else {
/*
{
struct sk_buff *skb = NULL;
unsigned long flags;
- __u8 *frame;
int n;
- ASSERT(self != NULL, return;);
- ASSERT(self->magic == TTP_TSAP_MAGIC, return;);
-
if (irda_lock(&self->tx_queue_lock) == FALSE)
return;
* More bit must be set by the data_request() or fragment()
* functions
*/
- frame = skb->data;
-
- DEBUG(4, __FUNCTION__ "(), More=%s\n", frame[0] & 0x80 ?
- "TRUE" : "FALSE" );
-
- frame[0] |= (__u8) (n & 0x7f);
+ skb->data[0] |= (n & 0x7f);
irlmp_data_request(self->lsap, skb);
self->stats.tx_packets++;
/* Check if we can accept more frames from client */
if ((self->tx_sdu_busy) &&
(skb_queue_len(&self->tx_queue) < LOW_THRESHOLD))
- {
+ {
self->tx_sdu_busy = FALSE;
if (self->notify.flow_indication)
self->notify.flow_indication(
- self->notify.instance, self,
+ self->notify.instance, self,
FLOW_START);
}
}
struct sk_buff *skb)
{
struct tsap_cb *self;
- int more;
int n;
- __u8 *frame;
-
+
self = (struct tsap_cb *) instance;
ASSERT(self != NULL, return -1;);
ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;);
- ASSERT(skb != NULL, return -1;);
- frame = skb->data;
-
- n = frame[0] & 0x7f; /* Extract the credits */
- more = frame[0] & 0x80;
-
- DEBUG(3, __FUNCTION__"(), got %d credits, TSAP sel=%02x\n",
- n, self->stsap_sel);
+ n = skb->data[0] & 0x7f; /* Extract the credits */
self->stats.rx_packets++;
* Data or dataless frame? Dataless frames only contain the
* TTP_HEADER
*/
- if (skb->len == 1) {
- /* Dataless flowdata TTP-PDU */
- self->send_credit += n;
- } else {
+ if (skb->len == 1)
+ self->send_credit += n; /* Dataless flowdata TTP-PDU */
+ else {
/* Deal with inbound credit */
self->send_credit += n;
self->remote_credit--;
self->connected = TRUE;
parameters = frame[0] & 0x80;
+
+ ASSERT(skb->len >= TTP_HEADER, return;);
+ skb_pull(skb, TTP_HEADER);
+
if (parameters) {
plen = frame[1];
pi = frame[2];
DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n",
self->tx_max_sdu_size);
+
+ /* Remove parameters */
+ ASSERT(skb->len >= (plen+1), return;);
+ skb_pull(skb, plen+1);
}
DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n",
self->send_credit, self->avail_credit, self->remote_credit);
- skb_pull(skb, TTP_HEADER);
-
if (self->notify.connect_confirm) {
self->notify.connect_confirm(self->notify.instance, self, qos,
self->tx_max_sdu_size,
*
*/
void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos,
- __u32 max_seg_size, __u8 max_header_size,
+ __u32 max_seg_size, __u8 max_header_size,
struct sk_buff *skb)
{
struct tsap_cb *self;
self->send_credit = n;
self->tx_max_sdu_size = 0;
- parameters = frame[0] & 0x80;
+ parameters = frame[0] & 0x80;
+
+ ASSERT(skb->len >= TTP_HEADER, return;);
+ skb_pull(skb, TTP_HEADER);
+
if (parameters) {
DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
plen = frame[1];
"() illegal value length for max_sdu_size!\n");
self->tx_max_sdu_size = 0;
};
-
+
+ /* Remove parameters */
+ ASSERT(skb->len >= (plen+1), return;);
+ skb_pull(skb, plen+1);
DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n",
self->tx_max_sdu_size);
DEBUG(4, __FUNCTION__ "(), initial send_credit=%d\n", n);
- skb_pull(skb, 1); /* Remove TTP header */
-
if (self->notify.connect_indication) {
self->notify.connect_indication(self->notify.instance, self,
qos, self->rx_max_sdu_size,
irttp_run_tx_queue(self);
/* Give avay some credits to peer? */
- if ((skb_queue_empty(&self->tx_queue)) &&
- (self->remote_credit < LOW_THRESHOLD) &&
- (self->avail_credit > 0))
+ if ((self->remote_credit < LOW_THRESHOLD) &&
+ (self->avail_credit > 0) && (skb_queue_empty(&self->tx_queue)))
{
- DEBUG(4, __FUNCTION__ "(), sending credit!\n");
irttp_give_credit(self);
}
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Mon Aug 4 20:40:53 1997
- * Modified at: Sun May 2 21:58:00 1999
+ * Modified at: Fri May 28 20:30:24 1999
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
* Copyright (c) 1998-1999 Dag Brattli <dagb@cs.uit.no>,
/*
* Function state_begin_frame (idev, byte)
*
- *
+ * Begin of frame detected
*
*/
static void state_begin_frame(struct irda_device *idev, __u8 byte)
case CE:
/* Stuffed byte */
idev->rx_buff.state = LINK_ESCAPE;
+
+ /* Time to initialize receive buffer */
+ idev->rx_buff.data = idev->rx_buff.head;
+ idev->rx_buff.len = 0;
break;
case EOF:
/* Abort frame */
idev->stats.rx_errors++;
idev->stats.rx_frame_errors++;
break;
- default:
- /* Got first byte of frame */
+ default:
+ /* Time to initialize receive buffer */
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 = irda_fcs(INIT_FCS, byte);
/*
* Function state_inside_frame (idev, byte)
*
- *
+ * Handle bytes received within a frame
*
*/
static void state_inside_frame(struct irda_device *idev, __u8 byte)