D: Small/Industrial Driver Project
N: Nick Holloway
-E: Nick.Holloway@alfie.demon.co.uk
-E: Nick.Holloway@parallax.co.uk
-W: http://www.alfie.demon.co.uk/
-P: 1024/75C49395 3A F0 E3 4E B7 9F E0 7E 47 A3 B0 D5 68 6A C2 FB
+E: Nick.Holloway@pyrites.org.uk
+W: http://www.pyrites.org.uk/
+P: 1024/36115A04 F4E1 3384 FCFD C055 15D6 BA4C AB03 FBF8 3611 5A04
D: Occasional Linux hacker...
-S: 15 Duke Street
-S: Chapelfields
-S: Coventry
-S: CV5 8BZ
+S: (ask for current address)
S: United Kingdom
N: Ron Holt
S: Niwot, Colorado 80503
S: USA
+N: Robert M. Love
+E: rml@tech9.net
+E: rml@ufl.edu
+D: misc. kernel hacking and debugging
+S: FL, USA
+
N: Martin von Löwis
E: loewis@informatik.hu-berlin.de
D: script binary format
- Consistent DMA mappings which are usually mapped at driver
initialization, unmapped at the end and for which the hardware should
- guarentee that the device and the cpu can access the data
+ guarantee that the device and the cpu can access the data
in parallel and will see updates made by each other without any
explicit software flushing.
The invariant these examples all require is that any cpu store
to memory is immediately visible to the device, and vice
- versa. Consistent mappings guarentee this.
+ versa. Consistent mappings guarantee this.
- Streaming DMA mappings which are usually mapped for one DMA transfer,
unmapped right after it (unless you use pci_dma_sync below) and for which
The cpu return address and the DMA bus master address are both
guaranteed to be aligned to the smallest PAGE_SIZE order which
is greater than or equal to the requested size. This invariant
-exists (for example) to guarentee that if you allocate a chunk
+exists (for example) to guarantee that if you allocate a chunk
which is smaller than or equal to 64 kilobytes, the extent of the
-buffer you receive will not cross a 64K boundry.
+buffer you receive will not cross a 64K boundary.
To unmap and free such a DMA region, you call:
If you absolutely cannot know the direction of the DMA transfer,
specify PCI_DMA_BIDIRECTIONAL. It means that the DMA can go in
-either direction. The platform guarentees that you may legally
+either direction. The platform guarantees that you may legally
specify this, and that it will work, but this may be at the
cost of performance for example.
didn't think straight when I wrote it originally. People who have to
support both can do something like:
- /* support old naming sillyness */
+ /* support old naming silliness */
#if LINUX_VERSION_CODE < 0x020100
#define ioremap vremap
#define iounmap vfree
<nico@cam.org>.
It's currently possible to mount a root filesystem via NFS providing a
-complete Linux environment. Otherwyse a ramdisk image may be used. Use
+complete Linux environment. Otherwise a ramdisk image may be used. Use
'make thinclient_config' before any 'make config'. This will set up
defaults for ThinClient support.
Go low for less than 2T (Around 750us)
Rather than repeat a signal when the button is held down certain buttons
-generate the following code to indicate repitition.
+generate the following code to indicate repetition.
Go low for approx 16T
Go high for approx 4T
important.
Another choice I made was in the file structure. I have attempted to
-contain all operating system specfic code in one module (fpmodule.*).
+contain all operating system specific code in one module (fpmodule.*).
All the other files contain emulator specific code. This should allow
others to port the emulator to NetBSD for instance relatively easily.
than fixing this interface by changing the assumptions it was made
under, thereby breaking all user applications that use this
function, the \UCD\ implements this $ioctl$ as follows: If the CD in
- question has audio tracks on it, and it has absolutly no CD-I, XA,
+ question has audio tracks on it, and it has absolutely no CD-I, XA,
or data tracks on it, it will be reported as $CDS_AUDIO$. If it has
both audio and data tracks, it will return $CDS_MIXED$. If there
are no audio tracks on the disc, and if the CD in question has any
Unfortunately, these drives seem to become very confused when we perform
the standard Linux ATA disk drive probe. If you own one of these drives,
you can bypass the ATA probing which confuses these CDROM drives, by
- adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and runing
+ adding `append="hdX=noprobe hdX=cdrom"' to your lilo.conf file and running
lilo (again where X is the drive letter corresponding to where your drive
is installed.)
to update the character drivers' makefile and configuration file, and other
kernel source files. A build script (ip2build) was included which applies
the patches if needed, and build any utilities needed.
-What you recieve may be a single patch file in conventional kernel
+What you receive may be a single patch file in conventional kernel
patch format build script. That form can also be applied by
running patch -p1 < ThePatchFile. Otherwise run ip2build.
Intelliport II installations using the PowerPort expansion module can
use the custom speed setting to select the highest speeds: 153,600 bps,
230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
-custom baud rate configuration is fixed at 921,600 for cards/expantion
+custom baud rate configuration is fixed at 921,600 for cards/expansion
modules with ST654's and 115200 for those with Cirrus CD1400's. This
corresponds to the maximum bit rates those chips are capable.
For example if the baud base is 921600 and the baud divisor is 18 then
2.2.x kernels and available as a configuration option in 2.3.46 and higher.
Devfs allows for the automatic creation and management of device names
under control of the device drivers themselves. The Devfs namespace is
-hierarchial and reduces the clutter present in the normal flat /dev
+hierarchical and reduces the clutter present in the normal flat /dev
namespace. Devfs names and conventional device names may be intermixed.
A userspace daemon, devfsd, exists to allow for automatic creation and
management of symbolic links from the devfs name space to the conventional
names. More details on devfs can be found on the DEVFS home site at
<http://www.atnf.csiro.au/~rgooch/linux/> or in the file kernel
-documenation files, .../linux/Documenation/filesystems/devfs/REAME.
+documentation files, .../linux/Documentation/filesystems/devfs/REAME.
If you are using devfs, existing devices are automatically created within
the devfs name space. Normal devices will be ttf/0 - ttf/255 and callout
-This driver is for Compaq's SMART2 Intellegent Disk Array Controllers.
+This driver is for Compaq's SMART2 Intelligent Disk Array Controllers.
Supported Cards:
----------------
There are known and unknown bugs, features and misfeatures.
Currently there are following known bugs:
+ This driver is still experimental and is not finished. Too many
- bugs/eratta to list here.
+ bugs/errata to list here.
--
Brad Douglas <brad@neruo.com>
XF86_FBDev.
dfp - enables digital flat panel interface. This option is incompatible with
secondary (TV) output - if DFP is active, TV output must be
- inactive and vice versa. DFP always uses same timming as primary
+ inactive and vice versa. DFP always uses same timing as primary
(monitor) output.
vesa:X - selects startup videomode. X is number from 0 to 0x1FF, see table
above for detailed explanation. Default is 640x480x8bpp if driver
16M | 0x312 0x315 0x318 0x31B
To enable one of those modes you have to specify "vga=ask" in the
-lilo.conf file and rerun LILO. Then you can type in the descired
+lilo.conf file and rerun LILO. Then you can type in the desired
mode at the "vga=ask" prompt. For example if you like to use
1024x768x256 colors you have to say "305" at this prompt.
may be called from the request handler (/dev/loop).
->sync_page() locking rules are not well-defined - usually it is called
with lock on page, but that is not guaranteed. Considering the currently
-existsing instances of this method ->sync_page() itself doesn't look
+existing instances of this method ->sync_page() itself doesn't look
well-defined...
->bmap() is currently used by legacy ioctl() (FIBMAP) provided by some
filesystems and by the swapper. The latter will eventually go away. All
have an Amiga harddisk connected to your PC, it will overwrite
the bytes 0x00dc..0x00df of block 0 with garbage, thus invalidating
the Rigid Disk Block. Sheer luck has it that this is an unused
-area of the RDB, so only the checksum doesn's match anymore.
+area of the RDB, so only the checksum doesn't match anymore.
Linux will ignore this garbage and recognize the RDB anyway, but
before you connect that drive to your Amiga again, you must
restore or repair your RDB. So please do make a backup copy of it
D\bDe\bes\bsc\bcr\bri\bip\bpt\bti\bio\bon\bn Remove all entries in the cache lying in a directory
- CodaFid, and all children of this directory. This call is issed when
+ CodaFid, and all children of this directory. This call is issued when
Venus receives a callback on the directory.
The following requirements should be accommodated:
- 1. The message queueus should have open and close routines. On Unix
+ 1. The message queues should have open and close routines. On Unix
the opening of the character devices are such routines.
+\bo Before opening, no messages can be placed.
THE KIND OF CVF I SUPPORT". The function must maintain the module
usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning
and MOD_DEC_USE_COUNT at the end. The function *must not* assume that
- successful recongition would lead to a call of the mount_cvf function
+ successful recognition would lead to a call of the mount_cvf function
later.
- mount_cvf:
A function that sets up some values or initializes something additional
- there is a list of text extensions (I thing it's better to not convert
text file than to damage binary file). If you want to change that list,
change it in the source. Original readonly HPFS contained some strange
- heuristic alghoritm that I removed. I thing it's danger to let the
+ heuristic algorithm that I removed. I thing it's danger to let the
computer decide whether file is text or binary. For example, DJGPP
binaries contain small text message at the beginning and they could be
misidentified and damaged under some circumstances.
check=none,normal,strict (default normal)
Check level. Selecting none will cause only little speedup and big
danger. I tried to write it so that it won't crash if check=normal on
- corrupted filesystems. check=strict means many superflous checks -
+ corrupted filesystems. check=strict means many superfluous checks -
used for debugging (for example it checks if file is allocated in
bitmaps when accessing it).
errors=continue,remount-ro,panic (default remount-ro)
Extended attributes
-On HPFS partion, OS/2 can associate to each file a special information called
+On HPFS partitions, OS/2 can associate to each file a special information called
extended attributes. Extended attributes are pairs of (key,value) where key is
an ascii string identifying that attribute and value is any string of bytes of
variable length. OS/2 stores window and icon positions and file types there. So
why not use it for unix-specific info like file owner or access rights? This
-driver can do it. If you chown/chgrp/chmod on a hpfs partion, extended
+driver can do it. If you chown/chgrp/chmod on a hpfs partition, extended
attributes with keys "UID", "GID" or "MODE" and 2-byte values are created. Only
that extended attributes those value differs from defaults specified in mount
options are created. Once created, the extended attributes are never deleted,
Symlinks
-You can do symlinks on HPFS partion, symlinks are achieved by setting extended
+You can do symlinks on HPFS partition, symlinks are achieved by setting extended
attribute named "SYMLINK" with symlink value. Like on ext2, you can chown and
chgrp symlinks but I don't know what is it good for. chmoding symlink results
in chmoding file where symlink points. These symlinks are just for Linux use and
America where people don't care much about codepages and so multiple codepages
support is quite buggy. I have Czech OS/2 working in codepage 852 on my disk.
Once I booted English OS/2 working in cp 850 and I created a file on my 852
-partion. It marked file name codepage as 850 - good. But when I again booted
+partition. It marked file name codepage as 850 - good. But when I again booted
Czech OS/2, the file was completely inaccessible under any name. It seems that
OS/2 uppercases the search pattern with it's system code page (852) and file
name it's comparing to with its code page (850). These could never match. Is it
-really what IBM developers wanted? But problems countinue. When I created in
-Czech OS/2 another file in that direcotry, that file was inaccesible too. OS/2
+really what IBM developers wanted? But problems continued. When I created in
+Czech OS/2 another file in that directory, that file was inaccessible too. OS/2
probably uses different uppercasing method when searching where to place a file
(note, that files in HPFS directory must be sorted) and when searching for
a file. Finally when I opened this directory in PmShell, PmShell crashed (the
marks them as short (and writes "minor fs error corrected"). This bug is not in
HPFS386.
-Codepage bugs decsribed above.
+Codepage bugs described above.
If you don't install fixpacks, there are many, many more...
1.99 Corrected a possible problem when there's not enough space while deleting
file
Now it tries to truncate the file if there's not enough space when deleting
- Removed a lot of redundat code
+ Removed a lot of redundant code
2.00 Fixed a bug in rename (it was there since 1.96)
Better anti-fragmentation strategy
On a low-memory, single CPU system, you can safely set these values to 0 so
you don't waste memory. It is used on SMP systems so that the system can
-perform fast pagetable allocations without having to aquire the kernel memory
+perform fast pagetable allocations without having to acquire the kernel memory
lock.
For large systems, the settings are probably fine. For normal systems they
ufstype=type_of_ufs
UFS is a file system widely used in different operating systems.
- The problem are differencies among implementations. Features of
+ The problem are differences among implementations. Features of
some implementations are undocumented, so its hard to recognize
type of ufs automatically. That's why user must specify type of
ufs manually by mount option ufstype. Possible values are:
The Virtual File System (otherwise known as the Virtual Filesystem
Switch) is the software layer in the kernel that provides the
-filesystem interface to userspace programmes. It also provides an
+filesystem interface to userspace programs. It also provides an
abstraction within the kernel which allows different filesystem
implementations to co-exist.
In this section I'll briefly describe how things work, before
launching into the details. I'll start with describing what happens
-when user programmes open and manipulate files, and then look from the
+when user programs open and manipulate files, and then look from the
other view which is how a filesystem is supported and subsequently
mounted.
If you have a FIFO-able FDC, the floppy driver automatically
falls back on non DMA mode if no DMA-able memory can be found.
- If you want to avoid this, explicitely ask for 'yesdma'.
+ If you want to avoid this, explicitly ask for 'yesdma'.
floppy=yesdma
Tells the floppy driver that a workable DMA channel is available.
- Decide whether or not to keep backwards compatibility with the system
accounting file, or if we should break it as the comments suggest
(currently, the old 16-bit UID and GID are still written to disk, and
- part of the former pad sparce is used to store separate 32-bit UID and
+ part of the former pad space is used to store separate 32-bit UID and
GID)
- Need to validate that OS emulation calls the 16-bit UID
__s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
__s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length,
__u8 *values);
-All these tranactions return -1 on failure; you can read errno to see
+All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
[..]: Data sent by I2C device, as opposed to data sent by the host adapter.
-Simple send tranaction
+Simple send transaction
======================
This corresponds to i2c_master_send.
S Addr Rd [A] [Data] A [Data] A ... A [Data] NA P
-Combined tranactions
+Combined transactions
====================
This corresponds to i2c_transfer
Flag I2C_M_NOSTART:
In a combined transaction, no 'S Addr' is generated at some point.
For example, setting I2C_M_NOSTART on the second partial message
- generateds something like:
+ generates something like:
S Addr Rd [A] [Data] NA Wr [A] Data [A] P
If you set the I2C_M_NOSTART variable for the first partial message,
we do not generate Addr, but we do generate the startbit S. This will
/* dec_use */ &foo_dev_use /* May be NULL */
}
-The name can be choosen freely, and may be upto 40 characters long. Please
+The name can be chosen freely, and may be upto 40 characters long. Please
use something descriptive here.
The id should be a unique ID. The range 0xf000 to 0xffff is reserved for
Command function
================
-A generic ioctl-like function call back is supported. You will seldomly
+A generic ioctl-like function call back is supported. You will seldom
need this. You may even set it to NULL.
/* No commands defined */
u8 command, u8 length,
u8 *values);
-All these tranactions return -1 on failure. The 'write' transactions
+All these transactions return -1 on failure. The 'write' transactions
return 0 on success; the 'read' transactions return the read value, except
for read_block, which returns the number of values read. The block buffers
need not be longer than 32 bytes.
before.
/* This call returns a unique low identifier for each registered adapter,
- * or -1 if the adapter was not regisitered.
+ * or -1 if the adapter was not registered.
*/
extern int i2c_adapter_id(struct i2c_adapter *adap);
fourth should always be 0. The fifth is the mode of the /proc file;
0644 is safe, as the file will be owned by root:root.
-The seventh and eigth parameters should be &sensors_proc_real and
+The seventh and eighth parameters should be &sensors_proc_real and
&sensors_sysctl_real if you want to export lists of reals (scaled
integers). You can also use your own function for them, as usual.
Finally, the last parameter is the call-back to gather the data
table and only if that fails fall back on walking the page table
tree.
- o Discontigous large memory support; memory above 4GB will be
- discontigous since the 4GB-64MB is reserved for firmware and I/O
+ o Discontinuous large memory support; memory above 4GB will be
+ discontinuous since the 4GB-64MB is reserved for firmware and I/O
space.
o Correct mapping for PAL runtime code; PAL code needs to be
expose this new way of representing time. Instead we use something very
similar to the struct tm, i.e. struct rtc_time, as used by hwclock.
One of the reasons for doing it this way is to allow for EFI to still evolve
-without necessarily impatcing any of the user applications. The decoupling
+without necessarily impacting any of the user applications. The decoupling
enables flexibility and permits writing wrapper code is ncase things change.
The driver exposes two interfaces, one via the device file and a set of ioctl()s.
README.eicon
- info on driver for Eicon active cards.
README.concap
- - info on "CONCAP" ecapsulation protocol interface used for X.25.
+ - info on "CONCAP" encapsulation protocol interface used for X.25.
README.diversion
- info on module for isdn diversion services.
README.sc
Description of the fax-subinterface between linklevel and hardwarelevel of
isdn4linux.
- The communication between linklevel (LL) and harwarelevel (HL) for fax
+ The communication between linklevel (LL) and hardwarelevel (HL) for fax
is based on the struct T30_s (defined in isdnif.h).
This struct is allocated in the LL.
In order to use fax, the LL provides the pointer to this struct with the
depending on progress and type of connection.
If the phase changes because of an AT command, the LL driver
changes this value. Otherwise the HL-driver takes care of it, but
- only neccessary on call establishment (from IDLE to PHASE_A).
+ only necessary on call establishment (from IDLE to PHASE_A).
(one of the constants ISDN_FAX_PHASE_[IDLE,A,B,C,D,E])
- direction
x = 38400: 198
Note on value in Reg 19:
There is _NO_ common convention for 38400 baud.
- The value 198 is choosen arbitrarily. Users
+ The value 198 is chosen arbitrarily. Users
_MUST_ negotiate this value before establishing
a connection.
AT&Sx Set window-size (x = 1..8) (not yet implemented)
If you know other passive cards with the Siemens chipset, please let me know.
To use the PNP cards you need the isapnptools.
-You can combine any card, if there is no conflict between the ressources
+You can combine any card, if there is no conflict between the resources
(io, mem, irq).
/sbin/isdnctrl huptimeout isdn0 0
/sbin/isdnctrl l2_prot isdn0 hdlc
# Attention you must not set an outgoing number !!! This won't work !!!
- # The incomming number is LEASED0 for the first card, LEASED1 for the
+ # The incoming number is LEASED0 for the first card, LEASED1 for the
# second and so on.
/sbin/isdnctrl addphone isdn0 in LEASED0
# Here is no need to bind the channel.
Here an example script:
#!/bin/sh
-# Start/Stop ISDN lesaed line connection
+# Start/Stop ISDN leased line connection
I4L_AS_MODULE=yes
I4L_REMOTE_IS_CISCO=no
Version. Currently, only the ISA-Bus version of the card is supported.
However MCA and PCMCIA will follow soon.
-The ISA-Bus Version uses 8 IO-ports. The base port adress has to be set
+The ISA-Bus Version uses 8 IO-ports. The base port address has to be set
manually using the DIP switches.
Setting up the DIP switches for the IBM Active 2000 ISDN card:
subscribe linux-avmb1
in the body.
-German documentaion and several scripts can be found at
+German documentation and several scripts can be found at
ftp://ftp.avm.de/cardware/b1/linux/
Bugs
Likewise, a similar encapsulation protocol will frequently be needed by
several different interfaces of even different hardware type, e.g. the
synchronous ppp implementation used by the isdn driver and the
-asyncronous ppp implementation used by the ppp driver have a lot of
+asynchronous ppp implementation used by the ppp driver have a lot of
similar code in them. By cleanly separating the encapsulation protocol
from the hardware specific interface stuff such code could be shared
better in future.
compared to the mechanism of ipfwadm or ipchains. If a given rule matches
the checking process is finished and the rule matching will be applied
to the call.
- The rules include primary and secondary service indentifiers, called
+ The rules include primary and secondary service identifiers, called
number and subaddress, callers number and subaddress and whether the rule
matches to all filtered calls or only those when all B-channel resources
are exhausted.
available in some countries (for example germany). Countries requiring the
keypad protocol for activating static diversions (like the netherlands) are
not supported but may use the tty devices for this purpose.
- The dynamic diversion servives may be used in all countries if the provider
+ The dynamic diversion services may be used in all countries if the provider
enables the feature CF (call forwarding). This should work on both MSN- and
point-to-point lines.
To add and delete rules the additional divertctrl program is needed. This
3 -> card is booted and active
And the last field (device) shows the name of the ethernet device assigned
- to this card. Up to the first successfull boot this field only shows a -
+ to this card. Up to the first successful boot this field only shows a -
to tell that no net device has been allocated up to now. Once a net device
has been allocated it remains assigned to this card, even if a card is
rebooted and an boot error occurs.
get the cards and drivers log data. Card messages always start with the
keyword LOG. All other lines are output from the driver.
The driver log data may be redirected to the syslog by selecting the
- approriate bitmask. The cards log messages will always be send to this
+ appropriate bitmask. The cards log messages will always be send to this
interface but never to the syslog.
A root user may write a decimal or hex (with 0x) value t this file to select
desired output options. As mentioned above the cards log dat is always
- written to the cardlog file independant of the following options only used
+ written to the cardlog file independent of the following options only used
to check and debug the driver itself:
For example:
To load a 4B-card, the same command is used, except a second firmware
file is appended to the commandline of icnctrl.
- -> After dowloading firmware, the two LEDs at the back cover of the card
+ -> After downloading firmware, the two LEDs at the back cover of the card
(ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection
is up, the corresponding led is lit continuously.
this driver release?
Before you can compile, install and use the SpellCaster ISA ISDN driver, you
-must ensure that the following software is installed, configuraed and running:
+must ensure that the following software is installed, configured and running:
- Linux kernel 2.0.20 or later with the required init and ps
versions. Please see your distribution vendor for the correct
basic HDLC connection between its two channels. Two network
interfaces are created and two routes added between the channels.
- i) using the isdnctrl utitity, add an interface with "addif" and
+ i) using the isdnctrl utility, add an interface with "addif" and
name it "isdn0"
ii) add the outgoing and inbound telephone numbers
iii) set the Layer 2 protocol to hdlc
This file is a script used to configure a BRI ISDN TA to establish a
PPP connection between the two channels. The file is almost
identical to the HDLC connection example except that the packet
- ecapsulation type has to be set.
+ encapsulation type has to be set.
use the same procedure as in the HDLC connection from steps i) to
iii) then, after the Layer 2 protocol is set, set the encapsulation
This file is a script used to configure a BRI ISDN TA to accept a
Multi Link PPP connection.
- i) using the isdnctrl utitity, add an interface with "addif" and
+ i) using the isdnctrl utility, add an interface with "addif" and
name it "ippp0"
ii) add the inbound telephone number
iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to
where js_event is defined as
struct js_event {
- __u32 time; /* event timestamp in miliseconds */
+ __u32 time; /* event timestamp in milliseconds */
__s16 value; /* value */
__u8 type; /* event type */
__u8 number; /* axis/button number */
};
-If the read is successfull, it will return sizeof(struct js_event), unless
+If the read is successful, it will return sizeof(struct js_event), unless
you wanted to read more than one event per read as described in section 3.1.
~~~~~~~~~~~~~~
JSIOCGNAME(len) allows you to get the name string of the joystick - the same
-as is being printed at boot time. The 'len' argument is the lenght of the
+as is being printed at boot time. The 'len' argument is the length of the
buffer provided by the application asking for the name. It is used to avoid
possible overrun should the name be too long.
2. Devices supported
~~~~~~~~~~~~~~~~~~~~
- Many console and 8-bit coputer gamepads and joysticks are supported. The
+ Many console and 8-bit computer gamepads and joysticks are supported. The
following subsections discuss usage of each.
2.1 NES and SNES
~~~~~~~~
All the Sega controllers are more or less based on the standard 2-button
Multisystem joystick. However, since they don't use switches and use TTL
-logic, the only driver useable with them is the db9.c driver.
+logic, the only driver usable with them is the db9.c driver.
2.4.1 Sega Master System
~~~~~~~~~~~~~~~~~~~~~~~~
It also supports extensions like additional hats and buttons compatible
with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button gamepads. Saitek
-Cyborg 'digital' joysticks are also supportted by this driver, because
+Cyborg 'digital' joysticks are also supported by this driver, because
they're basically souped up CHF sticks.
However the only types that can be autodetected are:
inputattach --magellan /dev/tts/x &
command. After that the Magellan will be detected, initialized, will beep,
-and the /dev/input/jsX device should become useable.
+and the /dev/input/jsX device should become usable.
3.17 I-Force devices
~~~~~~~~~~~~~~~~~~~~
inputattach --iforce /dev/tts/x &
command. After that the I-Force device will be detected, and the
-/dev/input/jsX device should become useable.
+/dev/input/jsX device should become usable.
In case you're using the device via the USB port, the inputattach command
isn't needed.
occasionally. If you are adding configuration options, it's
nice if you do it before you publish your patch!
- You can run 'make checkhelp' withoug configuring the kernel.
+ You can run 'make checkhelp' without configuring the kernel.
Also, 'make checkhelp' does not modify any files.
make dep, make depend
A /word/ is a single unquoted word, a single-quoted string, or a
double-quoted string. If the word is unquoted or double quoted,
- then $-substition will be performed on the word.
+ then $-substitution will be performed on the word.
A /symbol/ is a single unquoted word. A symbol must have a name of
the form CONFIG_*. scripts/mkdep.c relies on this convention in order
trying to write Config Language scripts with a default value for bool,
but *all* of the existing language interpreters discard additional values.
Feel free to submit a multi-interpreter patch to linux-kbuild if you
-want to implement this as an enhancment.
+want to implement this as an enhancement.
Configure: implemented
Menuconfig: implemented
The card should be a Z-II board, size 64K, not for freemem
list, Rom-Vektor is valid, no second Autoconfig-board on the
-same card, no space preferrence, supports "Shutup_forever".
+same card, no space preference, supports "Shutup_forever".
Setting the base address should be done in two steps, just
as the Amiga Kickstart does: The lower nibble of the 8-Bit
$48, while it doesn't matter how often you're writing to $4a
as long as $48 is not touched. After $48 has been written,
the whole card disappears from $e8 and is mapped to the new
-addrress just written. Make shure $4a is written befor $48,
+address just written. Make shure $4a is written before $48,
otherwise your chance is only 1:16 to find the board :-).
The local memory-map is even active when mapped to $e8:
for Buddha-only) registers $f00, $f40 and $f80. This way
more than one I/O request can be handled and you can easily
determine what driver has to serve the INT2. Buddha and
-Catweasel expansion boards can issue an INT6. A seperate
+Catweasel expansion boards can issue an INT6. A separate
memory map is available for the I/O module and the sysop's
I/O module.
xres_virtual must be set to 2048. For ET4000, xres_virtual depends on the
initialisation of the video-card.
If you're missing a corresponding yres_virtual: the external part is legacy,
-therefore we don't support hardware-dependend functions like hardware-scroll,
+therefore we don't support hardware-dependent functions like hardware-scroll,
panning or blanking.
4.1.7) eclock:
You can boot (if you selected boot support in the configuration) with your md
device with the following kernel command lines:
-for old raid arrays without persistant superblocks:
+for old raid arrays without persistent superblocks:
md=<md device no.>,<raid level>,<chunk size factor>,<fault level>,dev0,dev1,...,devn
for raid arrays with persistant superblocks
-C168P/H/HS, C168H/PCI 8 port multiport board.
This driver has been modified a little and cleaned up from the Moxa
- contributed driver code and merged into Linux 2.2.14pre. In paticular
+ contributed driver code and merged into Linux 2.2.14pre. In particular
official major/minor numbers have been assigned which are different to
those the original Moxa supplied driver used.
PCI board
---------
- You may need to adjust IRQ useage in BIOS to avoid from IRQ conflict
+ You may need to adjust IRQ usage in BIOS to avoid from IRQ conflict
with other ISA devices. Please refer to hardware installation
procedure in User's Manual in advance.
# insmod mxser
- to activate the moduler driver. You may run "lsmod" to check
+ to activate the modular driver. You may run "lsmod" to check
if "mxser.o" is activated.
2. Create special files by executing "msmknod".
# ./msmknod
Default major numbers for dial-in device and callout device are
- 174, 175. Msmknod will delete any special files occuping the same
+ 174, 175. Msmknod will delete any special files occupying the same
device naming.
3. Up to now, you may manually execute "insmod mxser" to activate
below.
a. # cd /moxa/mxser/driver
# vi mxser.c
- b. Find the array mxserBoardCAP[] as belows.
+ b. Find the array mxserBoardCAP[] as below.
static int mxserBoardCAP[]
= {0x00, 0x00, 0x00, 0x00};
f. cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz
g. Please make sure the boot kernel (vmlinuz) is in the
correct position. If you use 'lilo' utility, you should
- check /etc/lilo.conf 'image' item specifiedd the path
+ check /etc/lilo.conf 'image' item specified the path
which is the 'vmlinuz' path, or you will load wrong
(or old) boot kernel image (vmlinuz).
h. chmod 400 /vmlinuz
-----------------------------------------------------------------------------
6. Troubleshooting
- The boot time error mesages and solutions are stated as clearly as
+ The boot time error messages and solutions are stated as clearly as
possible. If all the possible solutions fail, please contact our technical
support team to get more help.
which device causes the situation,please check /proc/interrupts to find
free IRQ and simply change another free IRQ for Moxa board.
- Error msg: Board #: C1xx Series(CAP=xxx) interupt number invalid.
+ Error msg: Board #: C1xx Series(CAP=xxx) interrupt number invalid.
Solution:
Each port within the same multiport board shares the same IRQ. Please set
one IRQ (IRQ doesn't equal to zero) for one Moxa board.
There are two interfaces to /proc/mtrr: one is an ASCII interface
which allows you to read and write. The other is an ioctl()
interface. The ASCII interface is meant for administration. The
-ioctl() interface is meant for C programmes (i.e. the X server). The
+ioctl() interface is meant for C programs (i.e. the X server). The
interfaces are described below, with sample commands and C code.
===============================================================================
or using bash:
% echo "disable=2" >| /proc/mtrr
===============================================================================
-Reading MTRRs from a C programme using ioctl()'s:
+Reading MTRRs from a C program using ioctl()'s:
/* mtrr-show.c
- Source file for mtrr-show (example programme to show MTRRs using ioctl()'s)
+ Source file for mtrr-show (example program to show MTRRs using ioctl()'s)
Copyright (C) 1997-1998 Richard Gooch
*/
/*
- This programme will use an ioctl() on /proc/mtrr to show the current MTRR
+ This program will use an ioctl() on /proc/mtrr to show the current MTRR
settings. This is an alternative to reading /proc/mtrr.
http://home.adelphia.net/~siglercm/sb1000.html
http://linuxpower.cx/~cable/
- along with these utilties.
+ along with these utilities.
3.) The standard isapnp tools. These are necessary to configure your SB1000
card at boot time (or afterwards by hand) since it's a PnP card.
When you're ready with filling in the files in the comx[n] directory, you can
configure the corresponding network interface with the standard network
-configuration utilites. If you're unble to bring the interfaces up, look up
+configuration utilities. If you're unable to bring the interfaces up, look up
the various kernel log files on your system, and consult the messages for
a probable reason.
\r
insmod cs89x0.o io=0x200 irq=0xA media=aui\r
\r
-This exmaple loads the module and configures the adapter to use an IO port base\r
+This example loads the module and configures the adapter to use an IO port base\r
address of 200h, interrupt 10, and use the AUI media connection. The following\r
configuration options are available on the command line:\r
\r
irq \r
media type (no autodetect)\r
\r
-f) The following addtional parameters are CS89XX defaults (values\r
+f) The following additional parameters are CS89XX defaults (values\r
used with no EEPROM or command-line argument).\r
\r
* DMA Burst = enabled\r
the two numbers are the node address 1,2 = 1.2 For 2.2.xx kernels
and early 2.3.xx kernels, you must use a comma when specifying the
DECnet address like this. For more recent 2.3.xx kernels, you may
-use almost charecter except space, although a `.` would be the most
+use almost any character except space, although a `.` would be the most
obvious choice :-)
There used to be a third number specifying the node type. This option
-Wall -Wstrict-prototypes -O6 -c dmfe.c"
- B. The following steps teach you how to active DM9102 board:
+ B. The following steps teach you how to activate a DM9102 board:
1. Used the upper compiler command to compile dmfe.c
"ifconfig eth0 172.22.3.18"
^^^^^^^^^^^ Your IP address
- 4. Active the IP routing table. For some distributions, it is not
+ 4. Activate the IP routing table. For some distributions, it is not
necessary. You can type "route" to check.
"route add default eth0"
- 5. Well done. Your DM9102 adapter actived now.
+ 5. Well done. Your DM9102 adapter is now activated.
C. Object files description:
Documentation on setup and use of EtherTap.
Contact Jay Schulist <jschlst@turbolinux.com> if you
-have questions or need futher assistance.
+have questions or need further assistance.
Introduction
============
will be aborted after ~11 minutes of retries.
tcp_retries1 - INTEGER
- How many times to retry before deciding that somethig is wrong
+ How many times to retry before deciding that something is wrong
and it is necessary to report this suspection to network layer.
Minimal RFC value is 3, it is default, which corresponds
to ~3sec-8min depending on RTO.
(probably, after increasing installed memory),
if network conditions require more than default value,
and tune network services to linger and kill such states
- more aggressivley. Let me to remind again: each orphan eats
+ more aggressively. Let me to remind again: each orphan eats
up to ~64K of unswappable memory.
tcp_abort_on_overflow - BOOLEAN
If listening service is too slow to accept new connections,
reset them. Default state is FALSE. It means that if overflow
- occured due to a burst, connection will recover. Enable this
+ occurred due to a burst, connection will recover. Enable this
option _only_ if you are really sure that listening daemon
cannot be tuned to accept connections faster. Enabling this
option can harm clients of your server.
tcp_max_syn_backlog - INTEGER
Maximal number of remembered connection requests, which are
- still did not receive an acknowldgement from connecting client.
+ still did not receive an acknowledgement from connecting client.
Default value is 1024 for systems with more than 128Mb of memory,
and 128 for low memory machines. If server suffers of overload,
try to increase this number. Warning! If you make it greater
Text file for ipddp.c:
AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
-This text file writen by Jay Schulist <jschlst@turbolinux.com>
+This text file is written by Jay Schulist <jschlst@turbolinux.com>
Introduction
------------
-Pcbr:max_pcr=<xxx>
where:
xxx = the maximum peak cell rate, from 170 - 353207.
- This option may only be set on the trasmit machine.
+ This option may only be set on the transmit machine.
OUTSTANDING ISSUES
message_level: Controls level of messages created by the driver. Defaults to 0:
which only displays start-up and critical messages. Presently any non-zero
value will display all soft messages as well. NB This does not turn
-debuging messages on, that must be done by modified the source code.
+debugging messages on, that must be done by modified the source code.
Multi-card:
The driver will detect multiple cards and will work with shared interrupts,
each card is assigned the next token ring device, i.e. tr0 , tr1, tr2. The
driver should also happily reside in the system with other drivers. It has
-been tested with ibmtr.c running, and I personnally have had one Olicom PCI
+been tested with ibmtr.c running, and I personally have had one Olicom PCI
card and two IBM olympic cards (all on the same interrupt), all running
together.
by the driver and the source and destination addresses printed.
Also an entry will be added in /proc/net called olympic_tr. This
displays low level information about the configuration of the ring and
-the adapter. This feature has been designed for network adiministrators
+the adapter. This feature has been designed for network administrators
to assist in the diagnosis of network / ring problems.
6/8/99 Peter De Schrijver and Mike Phillips
There is no "borrowing" or "sharing" scheme. This is a simple
traffic limiter. We implement Van Jacobson and Sally Floyd's CBQ
-architecture into Linux 2.2. THis is the preferred solution. Shaper is
+architecture into Linux 2.2. This is the preferred solution. Shaper is
for simple or back compatible setups.
Alan
Silicon Integrated System Corp. is cooperating closely with core Linux
Kernel developers. The revisions of SiS 900 driver are distributed by
- the usuall channels for kernel tar files and patches. Those kernel tar
+ the usual channels for kernel tar files and patches. Those kernel tar
files for official kernel and patches for kernel pre-release can be
download at official kernel ftp site
<http://ftp.kernel.org/pub/linux/kernel/> and its mirrors. The 1.06
options sk98lin ...
For "...", use the same syntax as described below for the command
-line paramaters of insmod.
+line parameters of insmod.
You either have to reboot your computer or unload and reload
the driver to activate the new parameters.
The syntax of the driver parameters is:
this port is not "Sense". If autonegotiation is "On", all
three values are possible. If it is "Off", only "Full" and
"Half" are allowed.
- It is usefull if your link partner does not support all
+ It is useful if your link partner does not support all
possible combinations.
- Flow Control
Large frames (also called jumbo frames) are now supported by the
driver. This can result in a greatly improved throughput if
-transfering large amounts of data.
+transferring large amounts of data.
To enable large frames, set the MTU (maximum transfer unit)
of the interface to the value you wish (up to 9000). The command
for this is:
You can switch back to the standard ethernet frame size with:
ifconfig eth0 mtu 1500
-To make this setting persitent, add a script with the 'ifconfig'
+To make this setting persistent, add a script with the 'ifconfig'
line to the system startup sequence (named something like "S99sk98lin"
in /etc/rc.d/rc2.d).
***
This driver is under the GNU General Public License. Its Firmware image is
included as an initialized C-array and is licensed by SMC to the Linux
-users of this driver. However no waranty about its fitness is expressed or
+users of this driver. However no warranty about its fitness is expressed or
implied by SMC.
0x01 Turn on general debugging messages.
0x02 Turn on receive debugging messages.
0x04 Turn on transmit debugging messages.
- 0x08 Turn on list debugging messsages.
+ 0x08 Turn on list debugging messages.
2. You can append aui=1 to the end of the insmod line to cause
the adapter to use the AUI interface instead of the 10 Base T
http://www.linux-sna.org
Many thanks to Christoph Goos for his excellent work on this driver and
-SysKonnect for donating the adapters to Linux-SNA for the testing and maintaince
-of this device driver.
+SysKonnect for donating the adapters to Linux-SNA for the testing and
+maintenance of this device driver.
Important information to be noted:
1. Adapters can be slow to open (~20 secs) and close (~5 secs), please be
This driver is under the GNU General Public License. Its Firmware image is
included as an initialized C-array and is licensed by SysKonnect to the Linux
-users of this driver. However no waranty about its fitness is expressed or
+users of this driver. However no warranty about its fitness is expressed or
implied by SysKonnect.
Below find attached the setting for the SK NET TR 4/16 ISA adapters
0.9.4.3 (April 14, 2000):
* mod_timer fix (Hal Murray)
-* PNIC2 resusitation (Chris Smith)
+* PNIC2 resuscitation (Chris Smith)
0.9.4.2 (March 21, 2000):
* Fix 21041 CSR7, CSR13/14/15 handling
The driver was written by Donald Becker <becker@cesdis.gsfc.nasa.gov>
-Don is no longer the prime maintener of this version of the driver.
+Don is no longer the prime maintainer of this version of the driver.
Please report problems to one or more of:
Andrew Morton <andrewm@uow.edu.au>
options 3c59x debug=3 rx_copybreak=300
-If you are using the PCMCIA tools (cardmgr) then theoptions may be
+If you are using the PCMCIA tools (cardmgr) then the options may be
placed in /etc/pcmcia/config.opts:
module "3c59x" opts "debug=3 extra_reset=1"
max_interrupt_work=N
The driver's interrupt service routine can handle many receive and
- transmit packets in a single invokation. It does this in a loop.
+ transmit packets in a single invocation. It does this in a loop.
The value of max_interrupt_work governs how mnay times the interrupt
service routine will loop. The default value is 32 loops. If this
is exceeded the interrupt service routine gives up and generates a
2.0.8 Nov 02, 1999 - Fixed up the X25API code.
- Clear call bug fixed.i
- - Eanbled driver for multi-card
+ - Enabled driver for multi-card
operation.
2.0.7 Aug 26, 1999 - Merged X25API code into WANPIPE.
- - Fixed a memeory leak for X25API
+ - Fixed a memory leak for X25API
- Updated the X25API code for 2.2.X kernels.
- Improved NEM handling.
creating applications using BiSync
streaming.
-2.0.5 Aug 04, 1999 CHDLC initializatin bug fix.
+2.0.5 Aug 04, 1999 CHDLC initialization bug fix.
PPP interrupt driven driver:
Fix to the PPP line hangup problem.
New PPP firmware
Streaming HDLC API has been taken out.
Available as a patch.
-2.0.6 Aug 17, 1999 Increased debugging in statup scripts
- Fixed insallation bugs from 2.0.5
+2.0.6 Aug 17, 1999 Increased debugging in startup scripts
+ Fixed installation bugs from 2.0.5
Kernel patch works for both 2.2.10 and 2.2.11 kernels.
There is no functional difference between the two packages
2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE.
- o Fixed a memeory leak for X25API
+ o Fixed a memory leak for X25API
o Updated the X25API code for 2.2.X kernels.
o Improved NEM handling.
This is the driver for the ISA version of the first generation
of the Wavelan, now discontinued. The device is 2 Mb/s, composed of a
-Intel 82586 controler and a Lucent Modem, and is NOT 802.11 compliant.
+Intel 82586 controller and a Lucent Modem, and is NOT 802.11 compliant.
The driver has been tested with the following hardware :
o Wavelan ISA 915 MHz (full length ISA card)
o Wavelan ISA 915 MHz 2.0 (half length ISA card)
This is the driver for the PCMCIA version of the first
generation of the Wavelan, now discontinued. The device is 2 Mb/s,
-composed of a Intel 82593 controler (totally different from the 82586)
+composed of a Intel 82593 controller (totally different from the 82586)
and a Lucent Modem, and NOT 802.11 compatible.
The driver has been tested with the following hardware :
o Wavelan Pcmcia 915 MHz 2.0 (Pcmcia card + separate
'watchdog NMI interrupts'. (NMI: Non Maskable Interrupt - these get
executed even if the system is otherwise locked up hard) This can be
used to debug hard kernel lockups. By executing periodic NMI interrupts,
-the kernel can monitor wether any CPU has locked up, and print out
+the kernel can monitor whether any CPU has locked up, and print out
debugging messages if so. You can enable/disable the NMI watchdog at boot
time with the 'nmi_watchdog=1' boot parameter. Eg. the relevant
lilo.conf entry:
Although platform dependent, and certainly the case for embedded
8xx, traditionally memory is mapped at physical address zero,
- and I/O devices above phsical address 0x80000000. The lowest
+ and I/O devices above physical address 0x80000000. The lowest
and highest (above 0xf0000000) I/O addresses are traditionally
used for devices or registers we need to map during kernel
initialization and prior to KVM operation. For this reason,
We currently implement one partition per volume, which is the whole
volume, skipping the first blocks up to the volume label. These are
reserved for IPL records and IBM's volume label to assure
-accessability of the DASD from other OSs. In a later stage we will
+accessibility of the DASD from other OSs. In a later stage we will
provide support of partitions, maybe VTOC oriented or using a kind of
partition table in the label record.
-Low-level format (?CKD only)
For using an ECKD-DASD as a Linux harddisk you have to low-level
-format the tracks by issueing the BLKDASDFORMAT-ioctl on that
+format the tracks by issuing the BLKDASDFORMAT-ioctl on that
device. This will erase any data on that volume including IBM volume
labels, VTOCs etc. The ioctl may take a 'struct format_data *' or
'NULL' as an argument.
The halt_IO() function returns :
0 - successful completion or request successfuly initiated
--EBUSY - the device is currently performing a sysnchonous I/O
+-EBUSY - the device is currently performing a synchronous I/O
operation : do_IO() with flag DOIO_WAIT_FOR_INTERRUPT
or an error was encountered and the device is currently
be sensed
1. Support modem interface for 8738. (select in kernel configuration)
2. Enable S/PDIF-in to S/PDIF-out (S/PDIF loop).
3. Enable 4 channels analog duplicate mode on 3 jack or 4 jack
- configurateion.
+ configuration.
Be aware: C-Media Electronics Inc. is basically an IC design house,
master volume control.
Every chip that's detected as a ES1887 now has Full Duplex support. Made a
-little testprogram that showes that is works, haven't seen a real program that
+little testprogram that shows that is works, haven't seen a real program that
needs this however.
For ESS chips an additional parameter "esstype" can be specified. This controls
7) Turn on debug in drivers/sound/sound_config.h (DEB, DDB, MDB).
-8) If the system reports insuffcient DMA memory then you may want to
+8) If the system reports insufficient DMA memory then you may want to
load sound with the "dmabufs=1" option. Or in /etc/conf.modules add
preinstall sound dmabufs=1
When a sound card is first referenced and sound is modular the sound system
will ask for the sound devices to be loaded. Initially it requests that
-the driver for the sound system is loaded. It then wwill ask for
+the driver for the sound system is loaded. It then will ask for
sound-slot-0, where 0 is the first sound card. (sound-slot-1 the second and
so on). Thus you can do
As this is a PCI device, the module does not need to be informed of
any IO or IRQ resources it should use, it devines these from the
-system. Somtimes, on sucky PCs, the BIOS fails to allocated resources
+system. Sometimes, on sucky PCs, the BIOS fails to allocated resources
for the maestro. This will result in a message like:
maestro: PCI subsystem reports IRQ 0, this might not be correct.
from the kernel. Should this happen the sound chip most likely will
device. The PSS driver enables MSS and MPU401 modes of the card. SB
is not enabled since it doesn't work concurrently with MSS.
-If you build this driver as a module then the driver takes the folowing
+If you build this driver as a module then the driver takes the following
parameters
pss_io. The I/O base the PSS card is configured at (normally 0x220
Gregor Hoffleit Mozart support (initial version)
Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support
James Hightower Spotting a tiny but important bug in CS423x support.
- Denis Sablic OPTi 82C924 spesific enhancements (non PnP mode)
+ Denis Sablic OPTi 82C924 specific enhancements (non PnP mode)
Tim MacKenzie Full duplex support for OPTi 82C930.
Please look at lowlevel/README for more contributors.
There are also chips called OPL3-SA2, OPL3-SA3, ..., OPL3SA-N. They
are PnP chips and will not work with the OPL3-SA1 driver. You should
- use the standard MSS, MPU401 and OPL3 options with thses chips and to
+ use the standard MSS, MPU401 and OPL3 options with these chips and to
activate the card using isapnptools.
4Front Technologies SoftOSS
NOTE! ESS cards are not compatible with MSS/WSS so don't worry if MSS support
of OSS doesn't work with it.
-There are some ES1688/688 based sound cards and (particularily) motherboards
+There are some ES1688/688 based sound cards and (particularly) motherboards
which use software configurable I/O port relocation feature of the chip.
This ESS proprietary feature is supported only by OSS/Linux.
work.
ES1868 is a PnP chip which is (supposed to be) compatible with ESS1688
-brobably works with OSS/Free after initialization using isapnptools.
+probably works with OSS/Free after initialization using isapnptools.
Reveal cards
------------
The sound modules normally allocate DMA buffers during open() and
deallocate them during close(). Linux can often have problems allocating
DMA buffers for ISA cards on machines with more than 16MB RAM. This is
-because ISA DMA buffers must exist below the 16MB boundry and it is quite
+because ISA DMA buffers must exist below the 16MB boundary and it is quite
possible that we can't find a large enough free block in this region after
the machine has been running for any amount of time. The way to avoid this
problem is to allocate the DMA buffers during module load and deallocate
It can only play 22.05kHz / 8bit / Stereo samples, control external MIDI
port.
If you want to use your card as recent "16-bit" card, you should use
- Alsa or OSS/Linux driver. Ofcource you can write native PCI driver for
+ Alsa or OSS/Linux driver. Of course you can write native PCI driver for
your cards :)
boards.
There are two methods of configuring ISA, EISA and MCA boards into the drivers.
-If using the driver as a loadable module then the simplist method is to pass
+If using the driver as a loadable module then the simplest method is to pass
the driver configuration as module arguments. The other method is to modify
the driver source to add configuration lines for each board in use.
where:
- board? -- specifies the arbitary board number of this board,
+ board? -- specifies the arbitrary board number of this board,
can be in the range 0 to 3.
name -- textual name of this board. The board name is the comman
reaches this number, only the kernel can
allocate more memory.
freepages.low If the number of free pages gets below this
- point, the kernel starts swapping agressively.
+ point, the kernel starts swapping aggressively.
freepages.high The kernel tries to keep up to this amount of
memory free; if memory comes below this point,
the kernel gently starts swapping in the hopes
- that it never has to do real agressive swapping.
+ that it never has to do real aggressive swapping.
==============================================================
- swap cache
When your system is both deep in swap and high on cache,
-it probably means that a lot of the swaped data is being
+it probably means that a lot of the swapped data is being
cached, making for more efficient swapping than possible
with the 2.0 kernel.
On a low-memory, single CPU system you can safely set these
values to 0 so you don't waste the memory. On SMP systems it
is used so that the system can do fast pagetable allocations
-without having to aquire the kernel memory lock.
+without having to acquire the kernel memory lock.
For large systems, the settings are probably OK. For normal
systems they won't hurt a bit. For small systems (<16MB ram)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Well, un'R'aw is very handy when your X server or a svgalib program crashes.
-sa'K' (Secure Access Key) is usefull when you want to be sure there are no
+sa'K' (Secure Access Key) is useful when you want to be sure there are no
trojan program is running at console and which could grab your password
when you would try to login. It will kill all programs on given console
and thus letting you make sure that the login prompt you see is actually
the one from init, not some trojan program.
IMPORTANT:In its true form it is not a true SAK like the one in :IMPORTANT
IMPORTATN:c2 compliant systems, and it should be mistook as such. :IMPORTANT
- It seems other find it usefull as (System Attention Key) which is
+ It seems other find it useful as (System Attention Key) which is
useful when you want to exit a program that will not let you switch consoles.
(For example, X or a svgalib program.)
- USAR Systems provided us with one of their excellent USB
Evaluation Kits. It allows us to test the Linux-USB driver
- for compilance with the latest USB specification. USAR
+ for compliance with the latest USB specification. USAR
Systems recognized the importance of an up-to-date open
Operating System and supports this project with
Hardware. Thanks!.
Linux users.
- Many thanks to ing büro h doran [http://www.ibhdoran.com]!
- It was almost imposible to get a PC backplate USB connector
+ It was almost impossible to get a PC backplate USB connector
for the motherboard here at Europe (mine, home-made, was
- quite lowsy :). Now I know where to adquire nice USB stuff!
+ quite lousy :). Now I know where to acquire nice USB stuff!
- Genius Germany donated a USB mouse to test the mouse boot
protocol. They've also donated a F-23 digital joystick and a
documentation for the UUSBD. Go for it!
- Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
- introductory documents (compiting with Alberto's :).
+ introductory documents (competing with Alberto's :).
- Christian Groessler <cpg@aladdin.de>, for it's help on those
itchy bits ... :)
- Rasca Gmelch <thron@gmx.de> has revived the raw driver and
pointed bugs, as well as started the uusbd-utils package.
- - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
+ - Peter Dettori <dettori@ozy.dec.com> is uncovering bugs like
crazy, as well as making cool suggestions, great :)
- All the Free Software and Linux community, the FSF & the GNU
- Big thanks to Richard Stallman for creating Emacs!
- The people at the linux-usb mailing list, for reading so
- many messages :) Ok, no more kidding; for all your advices!
+ many messages :) Ok, no more kidding; for all your advises!
- All the people at the USB Implementors Forum for their
help and assistance.
- URBs can be linked. After completing one URB, the next one can be
automatically submitted. This is especially useful for ISO transfers:
You only have read/write the data from/to the buffers in the completion
-handler, the continous streaming itself is transparently done by the
+handler, the continuous streaming itself is transparently done by the
URB-machinery.
1.2. The URB structure
Usually, (to reduce restart time) the completion handler is called
AFTER the URB re-submission. You can get the other way by setting
-USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for
+USB_URB_EARLY_COMPLETE in transfer_flags. This is implicit for
INT transfers.
1.5. How to submit an URB?
with the ASAP flag result in a seamless ISO streaming. Exception: The
execution cannot be scheduled later than 900 frames from the 'now'-time.
The same applies to INT transfers, but here the seamless continuation is
-independent of the transfer flags (implicitely ASAP).
+independent of the transfer flags (implicitly ASAP).
1.6. How to cancel an already running URB?
audio synchronisation/adaptive transfer rates). You can also use the length
0 to omit one or more frames (striping).
-As can be concluded from above, the UHCI-driver does not care for continous
+As can be concluded from above, the UHCI-driver does not care for continuous
data in case of short packet ISO reads! There's no fixup_isoc() like in the
old driver. There may be a common routine to do this in the future, but this
has nothing to do with the UHCI-driver!
For scheduling you can choose your own start frame or ASAP. As written above,
queuing more than one ISO frame with ASAP to the same device&endpoint result
-in seamless ISO streaming. For continous streaming you have to use URB
+in seamless ISO streaming. For continuous streaming you have to use URB
linking.
1.9. How to start interrupt (INT) transfers?
3.1.3 usbkbd.c
~~~~~~~~~~~~~~
- Much like usbmouse.c, this module talks to keyboards with a simpplified
+ Much like usbmouse.c, this module talks to keyboards with a simplified
HIDBP protocol. It's smaller, but doesn't support any extra special keys.
Use hid.c instead if there isn't any special reason to use this.
3.2 Event handlers
~~~~~~~~~~~~~~~~~~
- Event handlers distrubite the events from the devices to userland and
+ Event handlers distribute the events from the devices to userland and
kernel, as needed.
3.2.1 keybdev.c
~~~~~~~~~~~~~
Evdev is the generic input event interface. It passes the events generated
in the kernel straight to the program, with timestamps. The API is still
-evolving, but should be useable now. It's described in section 5.
+evolving, but should be usable now. It's described in section 5.
This should be the way for GPM and X to get keyboard and mouse mouse
events. It allows for multihead in X without any specific multihead kernel
You can test the joystick emulation with the 'jstest' utility, available
in the joystick package (see Documentation/joystick.txt).
- You can test the event devics with the 'evtest' utitily available on the
+ You can test the event devics with the 'evtest' utility available on the
input driver homepage (see the URL above).
5. Event interface
};
'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+Type is for example EV_REL for relative movement, REL_KEY for a keypress or
release. More types are defined in include/linux/input.h.
'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
The OHCI HCD layer is a simple but nearly complete implementation of what the
USB people would call a HCD for the OHCI.
- (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
+ (ISO coming soon, Bulk, INT u. CTRL transfers enabled)
It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers.
- Endpoint Descriptor (ED) handling more static approach
(EDs should be allocated in parallel to the SET CONFIGURATION command and they live
- as long as the function (device) is alive or another configuration is choosen.
+ as long as the function (device) is alive or another configuration is chosen.
In the HCD layer the EDs has to be allocated manually either by calling a subroutine
or by sending a USB root hub vendor specific command to the virtual root hub.
At the alternate linux usb stack EDs will be added (allocated) at their first use.
- ED will be unlinked from the HC chains if they are not bussy.
+ ED will be unlinked from the HC chains if they are not busy.
files: ohci-hcd.c ohci-hcd.h
routines: (do not use for drivers, use the top layer alternate usb commands instead)
DEFAULT: 5
DESC: This is the number of times the driver will try to sync and detect the
internal i2c bus (which connects the OV511 and sensor). If you are
- getting intermittant detection failures ("Failed to read sensor ID...")
+ getting intermittent detection failures ("Failed to read sensor ID...")
you should increase this by a modest amount. If setting it to 20 or so
doesn't fix things, look elsewhere for the cause of the problem.
S: SerialNumber=ssss
| |__Serial Number of this device as read from the device,
| except that it is a generated string for USB host controllers
-| (virtual root hubs), and represent's the host controller's
+| (virtual root hubs), and represents the host controller's
| unique identification in the system (currently I/O or
| memory-mapped base address).
|__String info tag
MESSAGES
-On occassion the message 'usb_control/bulk_msg: timeout' or something
+On occasions the message 'usb_control/bulk_msg: timeout' or something
similar will appear in '/var/adm/messages' or on the console or both,
depending on how your system is configured. This is a side effect
that scanners are sometimes very slow at warming up and/or
-initialiazing. In most cases, however, only several of these messages
+initializing. In most cases, however, only several of these messages
should appear and is generally considered to be normal. If you see
a message of the type 'excessive NAK's received' then this should
be considered abnormal and generally indicates that the USB system is
days (and nights) on the 16th and 17th of October 1999, now known as the
great USB-October-Revolution started by GA, DF, and TS ;-)
-Since the concept is in no way UHCI dependant, we hope that it will also be
+Since the concept is in no way UHCI dependent, we hope that it will also be
transfered to the OHCI-driver, so both drivers share a common API.
1.2. Advantages and disadvantages
1.4. What's really working?
-As said above, CTRL und BULK already work fine even with the wrappers,
+As said above, CTRL and BULK already work fine even with the wrappers,
so legacy code wouldn't notice the change.
Regarding to Thomas, ISO transfers now run stable with USB audio.
INT transfers (e.g. mouse driver) work fine, too.
affected, no atomic memory operation is required. The three QHs in the
common chain are never equipped with TDs!
-For ISO or INT, the TD for each frame is simply inserted into the apropriate
+For ISO or INT, the TD for each frame is simply inserted into the appropriate
ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
among the 1024 frames similar to the old UHCI driver.
Current status:
The device's firmware is downloaded on connection, the new firmware
- runs properly and all four ports are successfuly recognized and connected.
+ runs properly and all four ports are successfully recognized and connected.
Data can be sent and received through the device on all ports.
Hardware flow control needs to be implemented.
The c-qcam is IEEE1284 compatible, so if you are using the proc file
system (CONFIG_PROC_FS), the parallel printer support
-(CONFIG_PRINTER), the IEEE 1284 sytem,(CONFIG_PRINTER_READBACK), you
+(CONFIG_PRINTER), the IEEE 1284 system,(CONFIG_PRINTER_READBACK), you
should be able to read some identification from your quickcam with
modprobe -v parport
device opens
- complete control over camera via proc-interface (_all_ camera settings are
supported), there is also a python-gtk application available for this [3]
-- works under SMP (but the driver is completly serialized and synchronous)
+- works under SMP (but the driver is completely serialized and synchronous)
so you get no benefit from SMP, but at least it does not crash your box
- might work for non-Intel architecture, let us know about this
The camera can act in two modes, streaming or grabbing. Right now a
polling grab-scheme is used. Maybe interrupt driven streaming will be
-used for a ansychronous mmap interface in the next major release of the
+used for a asynchronous mmap interface in the next major release of the
driver. This might give a better frame rate.
---------------------------------------------------------------------------
--------------------
The RadioTrack card is an ISA 8-bit FM radio card. The radio frequency (RF)
input is simply an antenna lead, and the output is a power audio signal
-available through a miniature phono plug. Its RF frequencies of operation are
+available through a miniature phone plug. Its RF frequencies of operation are
more or less limited from 87.0 to 109.0 MHz (the commercial FM broadcast
band). Although the registers can be programmed to request frequencies beyond
these limits, experiments did not give promising results. The variable
to memory is done in the so-called snapshot mode. In this mode
the Zoran stops after capturing a frame worth of data and wait
till the application set GRAB bit to indicate readiness for the
-next frame. After detecting a set bit, the chip neetly waits
+next frame. After detecting a set bit, the chip neatly waits
till the start of a frame, captures it and it goes back to off.
Smart ppl will notice the problem here. Its the waiting on the
_next_ frame each time we set the GRAB bit... Oh well, 12,5 fps
key components of the kernel need on memory on that node.
Currently, all the numa support is to provide efficient handling
-of widely discontiguous physical memory, so architectures which
+of widely discontinuous physical memory, so architectures which
are not NUMA but can have huge holes in the physical address space
can use the same code. All this code is bracketed by CONFIG_DISCONTIGMEM.
S: Maintained
FILE LOCKING (flock() and fcntl()/lockf())
-P: Andy Walker
-M: andy@lysaker.kvaerner.no
+P: Matthew Wilcox
+M: willy@thepuffingroup.com
L: linux-kernel@vger.rutgers.edu
S: Maintained
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test5
+EXTRAVERSION = -test6
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
DRIVERS-m :=
DRIVERS- :=
-DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o
DRIVERS-$(CONFIG_AGP) += drivers/char/agp/agp.o
+DRIVERS-$(CONFIG_DRM) += drivers/char/drm/drm.o
DRIVERS-$(CONFIG_NUBUS) += drivers/nubus/nubus.a
DRIVERS-$(CONFIG_ISDN) += drivers/isdn/isdn.a
DRIVERS-$(CONFIG_NET_FC) += drivers/net/fc/fc.a
# use '-fno-strict-aliasing', but only if the compiler can take it
CFLAGS += $(shell if $(CC) -fno-strict-aliasing -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-strict-aliasing"; fi)
+# likewise for -fno-delete-null-pointer-checks
+CFLAGS += $(shell if $(CC) -fno-delete-null-pointer-checks -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-fno-delete-null-pointer-checks"; fi)
export CPPFLAGS CFLAGS AFLAGS
MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \
mkdir -p $$MODLIB; \
rm -f $$MODLIB/build; \
- ln -s $TOPDIR $$MODLIB/build; \
+ ln -s $$TOPDIR $$MODLIB/build; \
cd modules; \
MODULES=""; \
inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \
#include <linux/config.h>
#include <asm/system.h>
+#include <asm/cache.h>
#define SIGCHLD 20
cmovne $26,0,$19 /* $19 = 0 => non-restartable */
ldl $3,TASK_PROCESSOR($8)
lda $4,softirq_state
- sll $3,5,$3
+ sll $3,L1_CACHE_SHIFT,$3
addq $3,$4,$4
ldq $4,0($4)
sll $4,32,$3
endif
ifdef CONFIG_MK7
-CFLAGS += $(shell if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686"; fi) -malign-functions=4 -fschedule-insns2 -mwide-multiply -fexpensive-optimizations
+CFLAGS += $(shell if $(CC) -march=athlon -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=athlon"; else if $(CC) -march=i686 -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-march=i686 -malign-functions=4"; fi fi)
endif
ifdef CONFIG_MCRUSOE
if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n");
#endif
output_data = (char *)0x100000; /* Points to 1M */
+ free_mem_end_ptr = (long)real_mode;
}
struct moveparams {
comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
+dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_VT
endmenu
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
CONFIG_DRM=y
CONFIG_DRM_TDFX=y
# CONFIG_DRM_GAMMA is not set
# CONFIG_DRM_R128 is not set
# CONFIG_DRM_I810 is not set
# CONFIG_DRM_MGA is not set
-# CONFIG_AGP is not set
CONFIG_PCMCIA_SERIAL=y
#
return 0;
}
+/* our specific f_op->release() method needs no locking */
static int microcode_release(struct inode *inode, struct file *file)
{
- lock_kernel();
clear_bit(MICROCODE_IS_OPEN, µcode_status);
- unlock_kernel();
return 0;
}
CFLAGS := $(CFLAGS) -mcpu=r3000 -mips1
endif
ifdef CONFIG_CPU_R6000
-CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2
+CFLAGS := $(CFLAGS) -mcpu=r6000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R4300
-CFLAGS := $(CFLAGS) -mcpu=r4300 -mips2
+CFLAGS := $(CFLAGS) -mcpu=r4300 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R4X00
-CFLAGS := $(CFLAGS) -mcpu=r4600 -mips2
+CFLAGS := $(CFLAGS) -mcpu=r4600 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R5000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2
+CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_NEVADA
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -mmad
+CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap -mmad
endif
ifdef CONFIG_CPU_R8000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2
+CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
endif
ifdef CONFIG_CPU_R10000
-CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2
+CFLAGS := $(CFLAGS) -mcpu=r8000 -mips2 -Wa,--trap
endif
#
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
- bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
- bool ' Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
mainmenu_option next_comment
comment 'Machine selection'
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
endmenu
mainmenu_option next_comment
- comment 'CPU selection'
-
- choice 'CPU type' \
- "R3000 CONFIG_CPU_R3000 \
- R6000 CONFIG_CPU_R6000 \
- R4300 CONFIG_CPU_R4300 \
- R4x00 CONFIG_CPU_R4X00 \
- R5000 CONFIG_CPU_R5000 \
- R56x0 CONFIG_CPU_NEVADA \
- R8000 CONFIG_CPU_R8000 \
- R10000 CONFIG_CPU_R10000" R4x00
-
- bool 'Override CPU Options' CONFIG_CPU_ADVANCED
-
- if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then
- bool ' ll/sc Instructions available' CONFIG_CPU_HAS_LLSC
- bool ' Writeback Buffer available' CONFIG_CPU_HAS_WB
- else
- if [ "$CONFIG_CPU_R3000" = "y" ]; then
- if [ "$CONFIG_DECSTATION" = "y" ]; then
- define_bool CONFIG_CPU_HAS_LLSC n
- define_bool CONFIG_CPU_HAS_WB y
- else
- define_bool CONFIG_CPU_HAS_LLSC n
- define_bool CONFIG_CPU_HAS_WB n
- fi
- else
- define_bool CONFIG_CPU_HAS_LLSC y
- define_bool CONFIG_CPU_HAS_WB n
- fi
- fi
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
+ bool ' Kernel module loader' CONFIG_KMOD
+fi
endmenu
mainmenu_option next_comment
-comment 'General setup'
+comment 'CPU selection'
+
+choice 'CPU type' \
+ "R3000 CONFIG_CPU_R3000 \
+ R6000 CONFIG_CPU_R6000 \
+ R4300 CONFIG_CPU_R4300 \
+ R4x00 CONFIG_CPU_R4X00 \
+ R5000 CONFIG_CPU_R5000 \
+ R56x0 CONFIG_CPU_NEVADA \
+ R8000 CONFIG_CPU_R8000 \
+ R10000 CONFIG_CPU_R10000" R4x00
+
+bool 'Override CPU Options' CONFIG_CPU_ADVANCED
+
+if [ "$CONFIG_CPU_ADVANCED" = "y" ]; then
+ bool ' ll/sc Instructions available' CONFIG_CPU_HAS_LLSC
+ bool ' Writeback Buffer available' CONFIG_CPU_HAS_WB
+else
+ if [ "$CONFIG_CPU_R3000" = "y" ]; then
+ if [ "$CONFIG_DECSTATION" = "y" ]; then
+ define_bool CONFIG_CPU_HAS_LLSC n
+ define_bool CONFIG_CPU_HAS_WB y
+ else
+ define_bool CONFIG_CPU_HAS_LLSC n
+ define_bool CONFIG_CPU_HAS_WB n
+ fi
+ else
+ define_bool CONFIG_CPU_HAS_LLSC y
+ define_bool CONFIG_CPU_HAS_WB n
+ fi
+fi
+endmenu
- if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" ]; then
- define_bool CONFIG_CPU_LITTLE_ENDIAN y
- else
- bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
- fi
+mainmenu_option next_comment
+comment 'General setup'
+if [ "$CONFIG_DECSTATION" = "y" -o "$CONFIG_DDB5074" = "y" ]; then
+ define_bool CONFIG_CPU_LITTLE_ENDIAN y
+else
+ bool 'Generate little endian code' CONFIG_CPU_LITTLE_ENDIAN
+fi
- if [ "$CONFIG_PROC_FS" = "y" ]; then
- define_bool CONFIG_KCORE_ELF y
- fi
- define_bool CONFIG_ELF_KERNEL y
+if [ "$CONFIG_PROC_FS" = "y" ]; then
+ define_bool CONFIG_KCORE_ELF y
+fi
+define_bool CONFIG_ELF_KERNEL y
- if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
- bool 'Include IRIX binary compatibility' CONFIG_BINFMT_IRIX
- bool 'Include forward keyboard' CONFIG_FORWARD_KEYBOARD
- fi
+if [ "$CONFIG_CPU_LITTLE_ENDIAN" = "n" ]; then
+ bool 'Include IRIX binary compatibility' CONFIG_BINFMT_IRIX
+ bool 'Include forward keyboard' CONFIG_FORWARD_KEYBOARD
+fi
- define_bool CONFIG_BINFMT_AOUT n
- define_bool CONFIG_BINFMT_ELF y
- tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+define_bool CONFIG_BINFMT_AOUT n
+define_bool CONFIG_BINFMT_ELF y
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
- bool 'Networking support' CONFIG_NET
+bool 'Networking support' CONFIG_NET
- if [ "$CONFIG_PCI" = "y" ]; then
- source drivers/pci/Config.in
- fi
+if [ "$CONFIG_PCI" = "y" ]; then
+ source drivers/pci/Config.in
+fi
- bool 'System V IPC' CONFIG_SYSVIPC
- bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
- bool 'Sysctl support' CONFIG_SYSCTL
+bool 'System V IPC' CONFIG_SYSVIPC
+bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+bool 'Sysctl support' CONFIG_SYSCTL
- source drivers/parport/Config.in
+source drivers/parport/Config.in
- if [ "$CONFIG_DECSTATION" = "y" ]; then
- bool 'TURBOchannel support' CONFIG_TC
-# if [ "$CONFIG_TC" = "y" ]; then
-# bool ' Access.Bus support' CONFIG_ACCESSBUS
-# fi
- fi
+if [ "$CONFIG_DECSTATION" = "y" ]; then
+ bool 'TURBOchannel support' CONFIG_TC
+# if [ "$CONFIG_TC" = "y" ]; then
+# bool ' Access.Bus support' CONFIG_ACCESSBUS
+# fi
+fi
endmenu
if [ "$CONFIG_ISA" = "y" ]; then
if [ "$CONFIG_DECSTATION" != "y" -a \
"$CONFIG_SGI_IP22" != "y" ]; then
- source drivers/telephony/Config.in
+ source drivers/telephony/Config.in
fi
if [ "$CONFIG_SGI_IP22" != "y" -a \
"$CONFIG_DECSTATION" != "y" ]; then
- mainmenu_option next_comment
- comment 'ATA/IDE/MFM/RLL support'
+ mainmenu_option next_comment
+ comment 'ATA/IDE/MFM/RLL support'
- tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
+ tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
- if [ "$CONFIG_IDE" != "n" ]; then
+ if [ "$CONFIG_IDE" != "n" ]; then
source drivers/ide/Config.in
- else
+ else
define_bool CONFIG_BLK_DEV_IDE_MODES n
define_bool CONFIG_BLK_DEV_HD n
- fi
- endmenu
+ fi
+ endmenu
fi
mainmenu_option next_comment
if [ "$CONFIG_DECSTATION" != "y" -a \
"$CONFIG_SGI_IP22" != "y" ]; then
- source drivers/i2o/Config.in
+ source drivers/i2o/Config.in
fi
if [ "$CONFIG_NET" = "y" ]; then
if [ "$CONFIG_SGI_NEWPORT_CONSOLE" != "y" ]; then
define_bool CONFIG_DUMMY_CONSOLE y
else
- define_bool CONFIG_FONT_8x16 y
+ define_bool CONFIG_FONT_8x16 y
fi
bool 'SGI PROM Console Support' CONFIG_SGI_PROM_CONSOLE
fi
# CONFIG_ISA is not set
# CONFIG_PCI is not set
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
#
# CPU selection
#
# Parallel port support
#
# CONFIG_PARPORT is not set
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
# CONFIG_PCMCIA is not set
#
CONFIG_PCI=y
# CONFIG_ISA is not set
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
#
# CPU selection
#
# Parallel port support
#
# CONFIG_PARPORT is not set
-CONFIG_MODULES=y
-CONFIG_MODVERSIONS=y
-CONFIG_KMOD=y
# CONFIG_PCMCIA is not set
#
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
# CONFIG_AGP is not set
#
#
# Native Language Support
#
+CONFIG_NLS_DEFAULT="iso8859-1"
CONFIG_NLS_CODEPAGE_437=m
CONFIG_NLS_CODEPAGE_737=m
CONFIG_NLS_CODEPAGE_775=m
CONFIG_NLS_CODEPAGE_866=m
CONFIG_NLS_CODEPAGE_869=m
CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_950=m
CONFIG_NLS_ISO8859_1=m
CONFIG_NLS_ISO8859_2=m
CONFIG_NLS_ISO8859_3=m
# CONFIG_NLS_ISO8859_14 is not set
# CONFIG_NLS_ISO8859_15 is not set
CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_UTF8=m
#
# Sound
# CONFIG_ISA is not set
# CONFIG_PCI is not set
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
#
# CPU selection
#
# Parallel port support
#
# CONFIG_PARPORT is not set
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
CONFIG_TC=y
# CONFIG_PCMCIA is not set
# CONFIG_ISA is not set
# CONFIG_PCI is not set
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
#
# CPU selection
#
# Parallel port support
#
# CONFIG_PARPORT is not set
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
# CONFIG_PCMCIA is not set
#
# CONFIG_ISA is not set
# CONFIG_PCI is not set
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
#
# CPU selection
#
# Parallel port support
#
# CONFIG_PARPORT is not set
-# CONFIG_MODULES is not set
# CONFIG_PCMCIA is not set
#
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
# CONFIG_AGP is not set
#
CONFIG_ISA=y
CONFIG_PC_KEYB=y
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
#
# CPU selection
#
# Parallel port support
#
# CONFIG_PARPORT is not set
-CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-CONFIG_KMOD=y
#
# Plug and Play configuration
# CONFIG_WATCHDOG is not set
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
+CONFIG_RTC=y
#
# Video For Linux
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
# CONFIG_AGP is not set
#
-/* $Id: scall_o32.S,v 1.10 2000/02/23 00:41:00 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1997, 1998 by Ralf Baechle
+ * Copyright (C) 1997, 1998, 1999, 2000 by Ralf Baechle
*/
#include <asm/asm.h>
#include <linux/errno.h>
#include <asm/unistd.h>
/* This duplicates the definition from <linux/sched.h> */
-#define PF_TRACESYS 0x00000020 /* tracing system calls */
+#define PT_TRACESYS 0x00000002 /* tracing system calls */
/* This duplicates the definition from <asm/signal.h> */
#define SIGILL 4 /* Illegal instruction (ANSI). */
stack_done:
sw a3, PT_R26(sp) # save for syscall restart
- lw t0, TASK_FLAGS($28) # syscall tracing enabled?
- andi t0, PF_TRACESYS
+ lw t0, TASK_PTRACE($28) # syscall tracing enabled?
+ andi t0, PT_TRACESYS
bnez t0, trace_a_syscall
jalr t2 # Do The Real Thing (TM)
-/* $Id: andes.c,v 1.10 2000/02/13 20:52:05 harald Exp $
- *
+/*
* andes.c: MMU and cache operations for the R10000 (ANDES).
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* with a lot of changes to make this thing work for R3000s
* Copyright (C) 1998, 2000 Harald Koerfgen
* Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
- *
- * $Id: r2300.c,v 1.16 2000/03/13 10:33:05 raiko Exp $
*/
#include <linux/init.h>
#include <linux/kernel.h>
static void r3k_flush_cache_mm(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
{
struct vm_area_struct *vma;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
flush_cache_all();
} else {
unsigned long flags, physpage;
save_and_cli(flags);
- while(start < end) {
- if((physpage = get_phys_page(start, mm)))
+ while (start < end) {
+ if ((physpage = get_phys_page(start, mm)))
r3k_flush_icache_range(physpage, PAGE_SIZE);
start += PAGE_SIZE;
{
struct mm_struct *mm = vma->vm_mm;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
if (vma->vm_flags & VM_EXEC) {
unsigned long physpage;
- if((physpage = get_phys_page(page, vma->vm_mm)))
+ if ((physpage = get_phys_page(page, vma->vm_mm)))
r3k_flush_icache_range(physpage, PAGE_SIZE);
}
void flush_tlb_mm(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
unsigned long flags;
#ifdef DEBUG_TLB
pte_t *ptep;
int idx, pid;
- pid = (get_entryhi() & 0xfc0);
+ /*
+ * Handle debugger faulting in for debugee.
+ */
+ if (current->active_mm != vma->vm_mm)
+ return;
+
+ pid = get_entryhi() & 0xfc0;
#ifdef DEBUG_TLB
if((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) {
-/* $Id: r4xx0.c,v 1.29 2000/02/24 00:12:40 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
* r4xx0.c: R4000 processor variant specific MMU/Cache routines.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
- * Copyright (C) 1997, 1998 Ralf Baechle ralf@gnu.org
+ * Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org
*
* To do:
*
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s16d16i16();
} else {
pgd_t *pgd;
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s32d16i16();
} else {
pgd_t *pgd;
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
#endif
vma = find_vma(mm, start);
if(vma) {
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s64d16i16();
} else {
pgd_t *pgd;
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s128d16i16();
} else {
pgd_t *pgd;
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s32d32i32();
} else {
pgd_t *pgd;
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s64d32i32();
} else {
pgd_t *pgd;
struct vm_area_struct *vma;
unsigned long flags;
- if(mm->context == 0)
+ if (mm->context == 0)
return;
start &= PAGE_MASK;
printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
#endif
vma = find_vma(mm, start);
- if(vma) {
- if(mm->context != current->mm->context) {
+ if (vma) {
+ if (mm->context != current->active_mm->context) {
r4k_flush_cache_all_s128d32i32();
} else {
pgd_t *pgd;
unsigned long start,
unsigned long end)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
unsigned long flags;
#ifdef DEBUG_CACHE
unsigned long start,
unsigned long end)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
unsigned long flags;
#ifdef DEBUG_CACHE
*/
static void r4k_flush_cache_mm_s16d16i16(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_s32d16i16(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_s64d16i16(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_s128d16i16(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_s32d32i32(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_s64d32i32(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_s128d32i32(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_d16i16(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
static void r4k_flush_cache_mm_d32i32(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
#ifdef DEBUG_CACHE
printk("cmm[%d]", (int)mm->context);
#endif
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
*/
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
/* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
*/
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
/* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
*/
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/*
* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/*
* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/*
* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
/* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm->context != current->mm->context) {
+ if (mm->context != current->active_mm->context) {
/* Do indexed flush, too much work to get the (possible)
* tlb refills to work correctly.
*/
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
/* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_VALID))
+ if (!(pte_val(*ptep) & _PAGE_VALID))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if(mm == current->mm) {
+ if (mm == current->active_mm) {
blast_dcache16_page(page);
if(text)
blast_icache16_page(page);
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
* If the page isn't marked valid, the page cannot possibly be
* in the cache.
*/
- if(!(pte_val(*ptep) & _PAGE_PRESENT))
+ if (!(pte_val(*ptep) & _PAGE_PRESENT))
goto out;
text = (vma->vm_flags & VM_EXEC);
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if((mm == current->mm) && (pte_val(*ptep) & _PAGE_VALID)) {
+ if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
blast_dcache32_page(page);
if(text)
blast_icache32_page(page);
* If ownes no valid ASID yet, cannot possibly have gotten
* this page into the cache.
*/
- if(mm->context == 0)
+ if (mm->context == 0)
return;
#ifdef DEBUG_CACHE
* for every cache flush operation. So we do indexed flushes
* in that case, which doesn't overly flush the cache too much.
*/
- if((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
+ if ((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
blast_dcache32_page(page);
if(text)
blast_icache32_page(page);
void flush_tlb_mm(struct mm_struct *mm)
{
- if(mm->context != 0) {
+ if (mm->context != 0) {
unsigned long flags;
#ifdef DEBUG_TLB
#endif
save_and_cli(flags);
get_new_mmu_context(mm, asid_cache);
- if(mm == current->mm)
+ if (mm == current->active_mm)
set_entryhi(mm->context & 0xff);
restore_flags(flags);
}
set_entryhi(oldpid);
} else {
get_new_mmu_context(mm, asid_cache);
- if(mm == current->mm)
+ if (mm == current->active_mm)
set_entryhi(mm->context & 0xff);
}
restore_flags(flags);
void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
{
- if(vma->vm_mm->context != 0) {
+ if (vma->vm_mm->context != 0) {
unsigned long flags;
int oldpid, newpid, idx;
pte_t *ptep;
int idx, pid;
+ /*
+ * Handle debugger faulting in for debugee.
+ */
+ if (current->active_mm != vma->vm_mm)
+ return;
+
pid = get_entryhi() & 0xff;
#ifdef DEBUG_TLB
#include <asm/stackframe.h>
#include <asm/system.h>
#include <asm/cpu.h>
+#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
#include <asm/mc146818rtc.h>
char arcs_cmdline[CL_SIZE] = {0, };
#include <asm/stackframe.h>
#include <asm/system.h>
#include <asm/cpu.h>
+#include <linux/sched.h>
#include <linux/bootmem.h>
#include <asm/addrspace.h>
+#include <asm/bootinfo.h>
#include <asm/mc146818rtc.h>
#include <asm/orion.h>
*/
struct sgi_ioc_timers *p;
volatile unsigned char *tcwp, *tc2p;
- unsigned long r4k_ticks[3];
+ unsigned long r4k_ticks[3] = { 0, 0, 0 };
unsigned long r4k_next;
/* Figure out the r4k offset, the algorithm is very simple
tc2p = &p->tcnt2;
printk("Calibrating system timer... ");
- dosample(tcwp, tc2p); /* First sample. */
- dosample(tcwp, tc2p); /* Eat one. */
- r4k_ticks[0] = dosample(tcwp, tc2p); /* Second sample. */
- dosample(tcwp, tc2p); /* Eat another. */
- r4k_ticks[1] += dosample (tcwp, tc2p); /* Third sample. */
+ dosample(tcwp, tc2p); /* Prime cache. */
+ dosample(tcwp, tc2p); /* Prime cache. */
+ /* Zero is NOT an option. */
+ while (!r4k_ticks[0])
+ r4k_ticks[0] = dosample (tcwp, tc2p);
+ while (!r4k_ticks[1])
+ r4k_ticks[1] = dosample (tcwp, tc2p);
if (r4k_ticks[0] != r4k_ticks[1]) {
printk ("warning: timer counts differ, retrying...");
- dosample (tcwp, tc2p);
r4k_ticks[2] = dosample (tcwp, tc2p);
if (r4k_ticks[2] == r4k_ticks[0]
|| r4k_ticks[2] == r4k_ticks[1])
offset("#define TASK_FLAGS ", struct task_struct, flags);
offset("#define TASK_SIGPENDING ", struct task_struct, sigpending);
offset("#define TASK_NEED_RESCHED ", struct task_struct, need_resched);
+ offset("#define TASK_PTRACE ", struct task_struct, ptrace);
offset("#define TASK_COUNTER ", struct task_struct, counter);
offset("#define TASK_NICE ", struct task_struct, nice);
offset("#define TASK_MM ", struct task_struct, mm);
-# $Id: Makefile,v 1.5 2000/01/21 22:34:03 ralf Exp $
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
# machines may also. Since BFD is incredibly buggy with respect to
# crossformat linking we rely on the elf2ecoff tool for format conversion.
#
-CFLAGS += -mabi=64 -G 0 -mno-abicalls -fno-pic -pipe
+CFLAGS += -mabi=64 -G 0 -mno-abicalls -fno-pic -Wa,--trap -pipe
LINKFLAGS += -G 0 -static # -N
MODFLAGS += -mlong-calls
bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
endmenu
-mainmenu_option next_comment
-comment 'Loadable module support'
-bool 'Enable loadable module support' CONFIG_MODULES
-if [ "$CONFIG_MODULES" = "y" ]; then
- bool ' Set version information on all module symbols' CONFIG_MODVERSIONS
- bool ' Kernel module loader' CONFIG_KMOD
-fi
-endmenu
-
mainmenu_option next_comment
comment 'Machine selection'
bool 'Support for SGI IP22' CONFIG_SGI_IP22
endmenu
+mainmenu_option next_comment
+comment 'Loadable module support'
+bool 'Enable loadable module support' CONFIG_MODULES
+if [ "$CONFIG_MODULES" = "y" ]; then
+ bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS
+ bool 'Kernel module loader' CONFIG_KMOD
+fi
+
source drivers/pci/Config.in
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
# File systems
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
# File systems
#
# CONFIG_FTAPE is not set
# CONFIG_DRM is not set
-# CONFIG_DRM_TDFX is not set
+# CONFIG_AGP is not set
#
# File systems
-/* $Id: binfmt_elf32.c,v 1.1 1999/11/24 06:56:13 ralf Exp $
- *
+/*
* Support for 32-bit Linux/MIPS ELF binaries.
*
* Copyright (C) 1999 Ralf Baechle
typedef double elf_fpreg_t;
typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
-#define elf_check_arch(x) ((x)->e_machine == EM_MIPS || (x)->e_machine == EM_MIPS_RS4_BE)
+#define elf_check_arch(x) \
+ ((x)->e_machine == EM_MIPS || (x)->e_machine == EM_MIPS_RS4_BE)
#define TASK32_SIZE 0x80000000UL
#undef ELF_ET_DYN_BASE
#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/filter.h>
+#include <linux/shm.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
#include <asm/uaccess.h>
#include <asm/mman.h>
+#include <asm/ipc.h>
#define A(__x) ((unsigned long)(__x))
nargs(unsigned int arg, char **ap)
{
char *ptr;
- int n;
+ int n, ret;
n = 0;
do {
/* egcs is stupid */
if (!access_ok(VERIFY_READ, arg, sizeof (unsigned int)))
return -EFAULT;
- __get_user((long)ptr,(int *)A(arg));
- if (ap)
- *ap++ = ptr;
+ if (IS_ERR(ret = __get_user((long)ptr,(int *)A(arg))))
+ return ret;
+ if (ap) /* no access_ok needed, we allocated */
+ if (IS_ERR(ret = __put_user(ptr, ap++)))
+ return ret;
arg += sizeof(unsigned int);
n++;
} while (ptr);
char * filename;
na = nargs(argv, NULL);
+ if (IS_ERR(na))
+ return(na);
ne = nargs(envp, NULL);
+ if (IS_ERR(ne))
+ return(ne);
len = (na + ne + 2) * sizeof(*av);
/*
* kmalloc won't work because the `sys_exec' code will attempt
up(¤t->mm->mmap_sem);
if (IS_ERR(av))
- return((long) av);
+ return (long) av;
ae = av + na + 1;
- av[na] = (char *)0;
- ae[ne] = (char *)0;
- (void)nargs(argv, av);
- (void)nargs(envp, ae);
+ if (IS_ERR(r = __put_user(0, (av + na))))
+ goto out;
+ if (IS_ERR(r = __put_user(0, (ae + ne))))
+ goto out;
+ if (IS_ERR(r = nargs(argv, av)))
+ goto out;
+ if (IS_ERR(r = nargs(envp, ae)))
+ goto out;
filename = getname((char *) (long)regs.regs[4]);
r = PTR_ERR(filename);
if (IS_ERR(filename))
- return(r);
+ goto out;
r = do_execve(filename, av, ae, ®s);
putname(filename);
if (IS_ERR(r))
+out:
sys_munmap((unsigned long)av, len);
return(r);
}
return sys_fcntl(fd, cmd, (unsigned long)arg);
}
}
+
+struct msgbuf32 { s32 mtype; char mtext[1]; };
+
+struct ipc_perm32
+{
+ key_t key;
+ __kernel_uid_t32 uid;
+ __kernel_gid_t32 gid;
+ __kernel_uid_t32 cuid;
+ __kernel_gid_t32 cgid;
+ __kernel_mode_t32 mode;
+ unsigned short seq;
+};
+
+struct semid_ds32 {
+ struct ipc_perm32 sem_perm; /* permissions .. see ipc.h */
+ __kernel_time_t32 sem_otime; /* last semop time */
+ __kernel_time_t32 sem_ctime; /* last change time */
+ u32 sem_base; /* ptr to first semaphore in array */
+ u32 sem_pending; /* pending operations to be processed */
+ u32 sem_pending_last; /* last pending operation */
+ u32 undo; /* undo requests on this array */
+ unsigned short sem_nsems; /* no. of semaphores in array */
+};
+
+struct msqid_ds32
+{
+ struct ipc_perm32 msg_perm;
+ u32 msg_first;
+ u32 msg_last;
+ __kernel_time_t32 msg_stime;
+ __kernel_time_t32 msg_rtime;
+ __kernel_time_t32 msg_ctime;
+ u32 wwait;
+ u32 rwait;
+ unsigned short msg_cbytes;
+ unsigned short msg_qnum;
+ unsigned short msg_qbytes;
+ __kernel_ipc_pid_t32 msg_lspid;
+ __kernel_ipc_pid_t32 msg_lrpid;
+};
+
+struct shmid_ds32 {
+ struct ipc_perm32 shm_perm;
+ int shm_segsz;
+ __kernel_time_t32 shm_atime;
+ __kernel_time_t32 shm_dtime;
+ __kernel_time_t32 shm_ctime;
+ __kernel_ipc_pid_t32 shm_cpid;
+ __kernel_ipc_pid_t32 shm_lpid;
+ unsigned short shm_nattch;
+};
+
+#define IPCOP_MASK(__x) (1UL << (__x))
+
+static int
+do_sys32_semctl(int first, int second, int third, void *uptr)
+{
+ union semun fourth;
+ u32 pad;
+ int err, err2;
+ struct semid64_ds s;
+ struct semid_ds32 *usp;
+ mm_segment_t old_fs;
+
+ if (!uptr)
+ return -EINVAL;
+ err = -EFAULT;
+ if (get_user (pad, (u32 *)uptr))
+ return err;
+ if(third == SETVAL)
+ fourth.val = (int)pad;
+ else
+ fourth.__pad = (void *)A(pad);
+ switch (third) {
+
+ case IPC_INFO:
+ case IPC_RMID:
+ case IPC_SET:
+ case SEM_INFO:
+ case GETVAL:
+ case GETPID:
+ case GETNCNT:
+ case GETZCNT:
+ case GETALL:
+ case SETVAL:
+ case SETALL:
+ err = sys_semctl (first, second, third, fourth);
+ break;
+
+ case IPC_STAT:
+ case SEM_STAT:
+ usp = (struct semid_ds32 *)A(pad);
+ fourth.__pad = &s;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_semctl (first, second, third, fourth);
+ set_fs (old_fs);
+ err2 = put_user(s.sem_perm.key, &usp->sem_perm.key);
+ err2 |= __put_user(s.sem_perm.uid, &usp->sem_perm.uid);
+ err2 |= __put_user(s.sem_perm.gid, &usp->sem_perm.gid);
+ err2 |= __put_user(s.sem_perm.cuid,
+ &usp->sem_perm.cuid);
+ err2 |= __put_user (s.sem_perm.cgid,
+ &usp->sem_perm.cgid);
+ err2 |= __put_user (s.sem_perm.mode,
+ &usp->sem_perm.mode);
+ err2 |= __put_user (s.sem_perm.seq, &usp->sem_perm.seq);
+ err2 |= __put_user (s.sem_otime, &usp->sem_otime);
+ err2 |= __put_user (s.sem_ctime, &usp->sem_ctime);
+ err2 |= __put_user (s.sem_nsems, &usp->sem_nsems);
+ if (err2)
+ err = -EFAULT;
+ break;
+
+ }
+
+ return err;
+}
+
+static int
+do_sys32_msgsnd (int first, int second, int third, void *uptr)
+{
+ struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf)
+ + 4, GFP_USER);
+ struct msgbuf32 *up = (struct msgbuf32 *)uptr;
+ mm_segment_t old_fs;
+ int err;
+
+ if (!p)
+ return -ENOMEM;
+ err = get_user (p->mtype, &up->mtype);
+ err |= __copy_from_user (p->mtext, &up->mtext, second);
+ if (err)
+ goto out;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgsnd (first, p, second, third);
+ set_fs (old_fs);
+out:
+ kfree (p);
+ return err;
+}
+
+static int
+do_sys32_msgrcv (int first, int second, int msgtyp, int third,
+ int version, void *uptr)
+{
+ struct msgbuf32 *up;
+ struct msgbuf *p;
+ mm_segment_t old_fs;
+ int err;
+
+ if (!version) {
+ struct ipc_kludge *uipck = (struct ipc_kludge *)uptr;
+ struct ipc_kludge ipck;
+
+ err = -EINVAL;
+ if (!uptr)
+ goto out;
+ err = -EFAULT;
+ if (copy_from_user (&ipck, uipck, sizeof (struct ipc_kludge)))
+ goto out;
+ uptr = (void *)A(ipck.msgp);
+ msgtyp = ipck.msgtyp;
+ }
+ err = -ENOMEM;
+ p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+ if (!p)
+ goto out;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+ set_fs (old_fs);
+ if (err < 0)
+ goto free_then_out;
+ up = (struct msgbuf32 *)uptr;
+ if (put_user (p->mtype, &up->mtype) ||
+ __copy_to_user (&up->mtext, p->mtext, err))
+ err = -EFAULT;
+free_then_out:
+ kfree (p);
+out:
+ return err;
+}
+
+static int
+do_sys32_msgctl (int first, int second, void *uptr)
+{
+ int err = -EINVAL, err2;
+ struct msqid_ds m;
+ struct msqid64_ds m64;
+ struct msqid_ds32 *up = (struct msqid_ds32 *)uptr;
+ mm_segment_t old_fs;
+
+ switch (second) {
+
+ case IPC_INFO:
+ case IPC_RMID:
+ case MSG_INFO:
+ err = sys_msgctl (first, second, (struct msqid_ds *)uptr);
+ break;
+
+ case IPC_SET:
+ err = get_user (m.msg_perm.uid, &up->msg_perm.uid);
+ err |= __get_user (m.msg_perm.gid, &up->msg_perm.gid);
+ err |= __get_user (m.msg_perm.mode, &up->msg_perm.mode);
+ err |= __get_user (m.msg_qbytes, &up->msg_qbytes);
+ if (err)
+ break;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgctl (first, second, &m);
+ set_fs (old_fs);
+ break;
+
+ case IPC_STAT:
+ case MSG_STAT:
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_msgctl (first, second, (void *) &m64);
+ set_fs (old_fs);
+ err2 = put_user (m64.msg_perm.key, &up->msg_perm.key);
+ err2 |= __put_user(m64.msg_perm.uid, &up->msg_perm.uid);
+ err2 |= __put_user(m64.msg_perm.gid, &up->msg_perm.gid);
+ err2 |= __put_user(m64.msg_perm.cuid, &up->msg_perm.cuid);
+ err2 |= __put_user(m64.msg_perm.cgid, &up->msg_perm.cgid);
+ err2 |= __put_user(m64.msg_perm.mode, &up->msg_perm.mode);
+ err2 |= __put_user(m64.msg_perm.seq, &up->msg_perm.seq);
+ err2 |= __put_user(m64.msg_stime, &up->msg_stime);
+ err2 |= __put_user(m64.msg_rtime, &up->msg_rtime);
+ err2 |= __put_user(m64.msg_ctime, &up->msg_ctime);
+ err2 |= __put_user(m64.msg_cbytes, &up->msg_cbytes);
+ err2 |= __put_user(m64.msg_qnum, &up->msg_qnum);
+ err2 |= __put_user(m64.msg_qbytes, &up->msg_qbytes);
+ err2 |= __put_user(m64.msg_lspid, &up->msg_lspid);
+ err2 |= __put_user(m64.msg_lrpid, &up->msg_lrpid);
+ if (err2)
+ err = -EFAULT;
+ break;
+
+ }
+
+ return err;
+}
+
+static int
+do_sys32_shmat (int first, int second, int third, int version, void *uptr)
+{
+ unsigned long raddr;
+ u32 *uaddr = (u32 *)A((u32)third);
+ int err = -EINVAL;
+
+ if (version == 1)
+ return err;
+ if (version == 1)
+ return err;
+ err = sys_shmat (first, uptr, second, &raddr);
+ if (err)
+ return err;
+ err = put_user (raddr, uaddr);
+ return err;
+}
+
+static int
+do_sys32_shmctl (int first, int second, void *uptr)
+{
+ int err = -EFAULT, err2;
+ struct shmid_ds s;
+ struct shmid64_ds s64;
+ struct shmid_ds32 *up = (struct shmid_ds32 *)uptr;
+ mm_segment_t old_fs;
+ struct shm_info32 {
+ int used_ids;
+ u32 shm_tot, shm_rss, shm_swp;
+ u32 swap_attempts, swap_successes;
+ } *uip = (struct shm_info32 *)uptr;
+ struct shm_info si;
+
+ switch (second) {
+
+ case IPC_INFO:
+ case IPC_RMID:
+ case SHM_LOCK:
+ case SHM_UNLOCK:
+ err = sys_shmctl (first, second, (struct shmid_ds *)uptr);
+ break;
+ case IPC_SET:
+ err = get_user (s.shm_perm.uid, &up->shm_perm.uid);
+ err |= __get_user (s.shm_perm.gid, &up->shm_perm.gid);
+ err |= __get_user (s.shm_perm.mode, &up->shm_perm.mode);
+ if (err)
+ break;
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_shmctl (first, second, &s);
+ set_fs (old_fs);
+ break;
+
+ case IPC_STAT:
+ case SHM_STAT:
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_shmctl (first, second, (void *) &s64);
+ set_fs (old_fs);
+ if (err < 0)
+ break;
+ err2 = put_user (s64.shm_perm.key, &up->shm_perm.key);
+ err2 |= __put_user (s64.shm_perm.uid, &up->shm_perm.uid);
+ err2 |= __put_user (s64.shm_perm.gid, &up->shm_perm.gid);
+ err2 |= __put_user (s64.shm_perm.cuid,
+ &up->shm_perm.cuid);
+ err2 |= __put_user (s64.shm_perm.cgid,
+ &up->shm_perm.cgid);
+ err2 |= __put_user (s64.shm_perm.mode,
+ &up->shm_perm.mode);
+ err2 |= __put_user (s64.shm_perm.seq, &up->shm_perm.seq);
+ err2 |= __put_user (s64.shm_atime, &up->shm_atime);
+ err2 |= __put_user (s64.shm_dtime, &up->shm_dtime);
+ err2 |= __put_user (s64.shm_ctime, &up->shm_ctime);
+ err2 |= __put_user (s64.shm_segsz, &up->shm_segsz);
+ err2 |= __put_user (s64.shm_nattch, &up->shm_nattch);
+ err2 |= __put_user (s64.shm_cpid, &up->shm_cpid);
+ err2 |= __put_user (s64.shm_lpid, &up->shm_lpid);
+ if (err2)
+ err = -EFAULT;
+ break;
+
+ case SHM_INFO:
+ old_fs = get_fs ();
+ set_fs (KERNEL_DS);
+ err = sys_shmctl (first, second, (void *)&si);
+ set_fs (old_fs);
+ if (err < 0)
+ break;
+ err2 = put_user (si.used_ids, &uip->used_ids);
+ err2 |= __put_user (si.shm_tot, &uip->shm_tot);
+ err2 |= __put_user (si.shm_rss, &uip->shm_rss);
+ err2 |= __put_user (si.shm_swp, &uip->shm_swp);
+ err2 |= __put_user (si.swap_attempts,
+ &uip->swap_attempts);
+ err2 |= __put_user (si.swap_successes,
+ &uip->swap_successes);
+ if (err2)
+ err = -EFAULT;
+ break;
+
+ }
+ return err;
+}
+
+asmlinkage long
+sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+{
+ int version, err;
+
+ version = call >> 16; /* hack for backward compatibility */
+ call &= 0xffff;
+
+ switch (call) {
+
+ case SEMOP:
+ /* struct sembuf is the same on 32 and 64bit :)) */
+ err = sys_semop (first, (struct sembuf *)A(ptr),
+ second);
+ break;
+ case SEMGET:
+ err = sys_semget (first, second, third);
+ break;
+ case SEMCTL:
+ err = do_sys32_semctl (first, second, third,
+ (void *)A(ptr));
+ break;
+
+ case MSGSND:
+ err = do_sys32_msgsnd (first, second, third,
+ (void *)A(ptr));
+ break;
+ case MSGRCV:
+ err = do_sys32_msgrcv (first, second, fifth, third,
+ version, (void *)A(ptr));
+ break;
+ case MSGGET:
+ err = sys_msgget ((key_t) first, second);
+ break;
+ case MSGCTL:
+ err = do_sys32_msgctl (first, second, (void *)A(ptr));
+ break;
+
+ case SHMAT:
+ err = do_sys32_shmat (first, second, third,
+ version, (void *)A(ptr));
+ break;
+ case SHMDT:
+ err = sys_shmdt ((char *)A(ptr));
+ break;
+ case SHMGET:
+ err = sys_shmget (first, second, third);
+ break;
+ case SHMCTL:
+ err = do_sys32_shmctl (first, second, (void *)A(ptr));
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
* Functions to control caches.
*/
EXPORT_SYMBOL(_flush_page_to_ram);
-EXPORT_SYMBOL(_flush_cache_all);
+EXPORT_SYMBOL(_flush_cache_l1);
#ifndef CONFIG_COHERENT_IO
EXPORT_SYMBOL(_dma_cache_wback_inv);
EXPORT_SYMBOL(_dma_cache_inv);
-/* $Id: scall_64.S,v 1.7 2000/02/23 00:41:00 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996, 1997, 1998, 1999 by Ralf Baechle
- * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
#include <linux/config.h>
#include <asm/asm.h>
#include <asm/unistd.h>
/* This duplicates the definition from <linux/sched.h> */
-#define PF_TRACESYS 0x00000020 /* tracing system calls */
+#define PT_TRACESYS 0x00000002 /* tracing system calls */
/* This duplicates the definition from <asm/signal.h> */
#define SIGILL 4 /* Illegal instruction (ANSI). */
sd a3, PT_R26(sp) # save a3 for syscall restarting
- ld t0, TASK_FLAGS($28) # syscall tracing enabled?
- andi t0, PF_TRACESYS
+ ld t0, TASK_PTRACE($28) # syscall tracing enabled?
+ andi t0, PT_TRACESYS
bnez t0, trace_a_syscall
jalr t2 # Do The Real Thing (TM)
#include <asm/unistd.h>
/* This duplicates the definition from <linux/sched.h> */
-#define PF_TRACESYS 0x00000020 /* tracing system calls */
+#define PT_TRACESYS 0x00000002 /* tracing system calls */
/* This duplicates the definition from <asm/signal.h> */
#define SIGILL 4 /* Illegal instruction (ANSI). */
bgez t0, stackargs
stack_done:
- ld t0, TASK_FLAGS($28) # syscall tracing enabled?
- andi t0, PF_TRACESYS
+ ld t0, TASK_PTRACE($28) # syscall tracing enabled?
+ andi t0, PT_TRACESYS
bnez t0, trace_a_syscall
jalr t2 # Do The Real Thing (TM)
sys sys32_wait4 4
sys sys_swapoff 1 /* 4115 */
sys sys_sysinfo 1
- sys sys_ipc 6
+ sys sys32_ipc 6
sys sys_fsync 1
sys sys32_sigreturn 0
sys sys_clone 0 /* 4120 */
extern void allowboot(void);
init_new_context(current, &init_mm);
- global_irq_holder = 0;
current->processor = 0;
init_idle();
smp_tune_scheduling();
return 0;
case FLUSH_CACHE:
- flush_cache_all();
+ flush_cache_l1();
return 0;
case MIPS_RDNVRAM:
-/* $Id: andes.c,v 1.7 2000/03/13 22:43:25 kanoj Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com)
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/sgialib.h>
#include <asm/mmu_context.h>
+static int scache_lsz64;
+
/* CP0 hazard avoidance. I think we can drop this for the R10000. */
#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
"nop; nop; nop; nop; nop; nop;\n\t" \
".set reorder\n\t")
-/* R10000 has no Create_Dirty type cacheops. */
+/*
+ * This version has been tuned on an Origin. For other machines the arguments
+ * of the pref instructin may have to be tuned differently.
+ */
static void andes_clear_page(void * page)
{
__asm__ __volatile__(
".set\tnoreorder\n\t"
".set\tnoat\n\t"
"daddiu\t$1,%0,%2\n"
- "1:\tsd\t$0,(%0)\n\t"
+ "1:\tpref 7,512(%0)\n\t"
+ "sd\t$0,(%0)\n\t"
"sd\t$0,8(%0)\n\t"
"sd\t$0,16(%0)\n\t"
"sd\t$0,24(%0)\n\t"
:"$1", "memory");
}
+/* R10000 has no Create_Dirty type cacheops. */
static void andes_copy_page(void * to, void * from)
{
- unsigned long dummy1, dummy2, reg1, reg2;
+ unsigned long dummy1, dummy2, reg1, reg2, reg3, reg4;
__asm__ __volatile__(
".set\tnoreorder\n\t"
".set\tnoat\n\t"
- "daddiu\t$1,%0,%6\n"
- "1:\tld\t%2,(%1)\n\t"
+ "daddiu\t$1,%0,%8\n"
+ "1:\tpref\t0,2*128(%1)\n\t"
+ "pref\t1,2*128(%0)\n\t"
+ "ld\t%2,(%1)\n\t"
"ld\t%3,8(%1)\n\t"
+ "ld\t%4,16(%1)\n\t"
+ "ld\t%5,24(%1)\n\t"
"sd\t%2,(%0)\n\t"
"sd\t%3,8(%0)\n\t"
- "ld\t%2,16(%1)\n\t"
- "ld\t%3,24(%1)\n\t"
- "sd\t%2,16(%0)\n\t"
- "sd\t%3,24(%0)\n\t"
+ "sd\t%4,16(%0)\n\t"
+ "sd\t%5,24(%0)\n\t"
"daddiu\t%0,64\n\t"
"daddiu\t%1,64\n\t"
"ld\t%2,-32(%1)\n\t"
"ld\t%3,-24(%1)\n\t"
+ "ld\t%4,-16(%1)\n\t"
+ "ld\t%5,-8(%1)\n\t"
"sd\t%2,-32(%0)\n\t"
"sd\t%3,-24(%0)\n\t"
- "ld\t%2,-16(%1)\n\t"
- "ld\t%3,-8(%1)\n\t"
- "sd\t%2,-16(%0)\n\t"
+ "sd\t%4,-16(%0)\n\t"
"bne\t$1,%0,1b\n\t"
- " sd\t%3,-8(%0)\n\t"
+ " sd\t%5,-8(%0)\n\t"
".set\tat\n\t"
".set\treorder"
- :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2)
+ :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2),
+ "=&r" (reg3), "=&r" (reg4)
:"0" (to), "1" (from), "I" (PAGE_SIZE));
}
/* Cache operations. These are only used with the virtual memory system,
not for non-coherent I/O so it's ok to ignore the secondary caches. */
static void
-andes_flush_cache_all(void)
+andes_flush_cache_l1(void)
{
blast_dcache32(); blast_icache64();
}
+/*
+ * This is only used during initialization time. vmalloc() also calls
+ * this, but that will be changed pretty soon.
+ */
static void
-andes_flush_cache_mm(struct mm_struct *mm)
+andes_flush_cache_l2(void)
{
- if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
-#ifdef DEBUG_CACHE
- printk("cmm[%d]", (int)mm->context);
-#endif
- andes_flush_cache_all();
+ switch (sc_lsize()) {
+ case 64:
+ blast_scache64();
+ break;
+ case 128:
+ blast_scache128();
+ break;
+ default:
+ printk("Unknown L2 line size\n");
+ while(1);
}
}
-static void
-andes_flush_cache_range(struct mm_struct *mm, unsigned long start,
- unsigned long end)
+void
+andes_flush_icache_page(unsigned long page)
{
- if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
- unsigned long flags;
-
-#ifdef DEBUG_CACHE
- printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
-#endif
- save_and_cli(flags);
- blast_dcache32(); blast_icache64();
- restore_flags(flags);
- }
-}
-
-static void
-andes_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long flags;
- pgd_t *pgdp;
- pmd_t *pmdp;
- pte_t *ptep;
- int text;
-
- /*
- * If ownes no valid ASID yet, cannot possibly have gotten
- * this page into the cache.
- */
- if (CPU_CONTEXT(smp_processor_id(), mm) == 0)
- return;
-
-#ifdef DEBUG_CACHE
- printk("cpage[%d,%08lx]", (int)mm->context, page);
-#endif
- save_and_cli(flags);
- page &= PAGE_MASK;
- pgdp = pgd_offset(mm, page);
- pmdp = pmd_offset(pgdp, page);
- ptep = pte_offset(pmdp, page);
-
- /*
- * If the page isn't marked valid, the page cannot possibly be
- * in the cache.
- */
- if(!(pte_val(*ptep) & _PAGE_PRESENT))
- goto out;
-
- text = (vma->vm_flags & VM_EXEC);
- /*
- * Doing flushes for another ASID than the current one is
- * too difficult since stupid R4k caches do a TLB translation
- * for every cache flush operation. So we do indexed flushes
- * in that case, which doesn't overly flush the cache too much.
- */
- if ((mm == current->mm) && (pte_val(*ptep) & _PAGE_VALID)) {
- blast_dcache32_page(page);
- if(text)
- blast_icache64_page(page);
- } else {
- /*
- * Do indexed flush, too much work to get the (possible)
- * tlb refills to work correctly.
- */
- page = (CKSEG0 + (page & (dcache_size - 1)));
- blast_dcache32_page_indexed(page);
- if(text)
- blast_icache64_page_indexed(page);
- }
-out:
- restore_flags(flags);
-}
-
-/* Hoo hum... will this ever be called for an address that is not in CKSEG0
- and not cacheable? */
-static void
-andes_flush_page_to_ram(struct page * page)
-{
- unsigned long addr = page_address(page) & PAGE_MASK;
-
- if ((addr >= K0BASE_NONCOH && addr < (0xb0UL << 56))
- || (addr >= KSEG0 && addr < KSEG1)
- || (addr >= KSEG2)) {
-#ifdef DEBUG_CACHE
- printk("cram[%08lx]", addr);
-#endif
- blast_dcache32_page(addr);
- }
+ if (scache_lsz64)
+ blast_scache64_page(page);
+ else
+ blast_scache128_page(page);
}
static void
pte_t *ptep;
int idx, pid;
+ /*
+ * Handle debugger faulting in for debugee.
+ */
+ if (current->active_mm != vma->vm_mm)
+ return;
+
__save_and_cli(flags);
pid = get_entryhi() & 0xff;
_clear_page = andes_clear_page;
_copy_page = andes_copy_page;
- _flush_cache_all = andes_flush_cache_all;
- _flush_cache_mm = andes_flush_cache_mm;
- _flush_cache_range = andes_flush_cache_range;
- _flush_cache_page = andes_flush_cache_page;
+ _flush_cache_l1 = andes_flush_cache_l1;
+ _flush_cache_l2 = andes_flush_cache_l2;
_flush_cache_sigtramp = andes_flush_cache_sigtramp;
- _flush_page_to_ram = andes_flush_page_to_ram;
_flush_tlb_all = andes_flush_tlb_all;
_flush_tlb_mm = andes_flush_tlb_mm;
_flush_tlb_range = andes_flush_tlb_range;
_flush_tlb_page = andes_flush_tlb_page;
+
+ switch (sc_lsize()) {
+ case 64:
+ scache_lsz64 = 1;
+ break;
+ case 128:
+ scache_lsz64 = 0;
+ break;
+ default:
+ printk("Unknown L2 line size\n");
+ while(1);
+ }
update_mmu_cache = andes_update_mmu_cache;
_show_regs = andes_show_regs;
_user_mode = andes_user_mode;
- flush_cache_all();
+ flush_cache_l1();
/*
* You should never change this register:
asmlinkage int sys_cacheflush(void *addr, int bytes, int cache)
{
/* XXX Just get it working for now... */
- flush_cache_all();
+ flush_cache_l1();
return 0;
}
void (*_copy_page)(void * to, void * from);
/* Cache operations. */
-void (*_flush_cache_all)(void);
void (*_flush_cache_mm)(struct mm_struct *mm);
void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
unsigned long end);
void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
-void (*_flush_cache_sigtramp)(unsigned long addr);
void (*_flush_page_to_ram)(struct page * page);
+/* MIPS specific cache operations */
+void (*_flush_cache_sigtramp)(unsigned long addr);
+void (*_flush_cache_l2)(void);
+void (*_flush_cache_l1)(void);
+
+
/* DMA cache operations. */
void (*_dma_cache_wback_inv)(unsigned long start, unsigned long size);
void (*_dma_cache_wback)(unsigned long start, unsigned long size);
unsigned int flags;
if (size >= dcache_size) {
- flush_cache_all();
+ flush_cache_l1();
} else {
/* Workaround for R4600 bug. See comment above. */
__save_and_cli(flags);
unsigned long end, a;
if (size >= scache_size) {
- flush_cache_all();
+ flush_cache_l1();
return;
}
unsigned int flags;
if (size >= dcache_size) {
- flush_cache_all();
+ flush_cache_l1();
} else {
/* Workaround for R4600 bug. See comment above. */
__save_and_cli(flags);
unsigned long end, a;
if (size >= scache_size) {
- flush_cache_all();
+ flush_cache_l1();
return;
}
}
}
+static void
+r4k_flush_cache_l2(void)
+{
+}
+
#ifdef DEBUG_TLBUPDATE
static unsigned long ehi_debug[NTLB_ENTRIES];
static unsigned long el0_debug[NTLB_ENTRIES];
pte_t *ptep;
int idx, pid;
+ /*
+ * Handle debugger faulting in for debugee.
+ */
+ if (current->active_mm != vma->vm_mm)
+ return;
+
__save_and_cli(flags);
pid = (get_entryhi() & 0xff);
case 16:
_clear_page = r4k_clear_page_d16;
_copy_page = r4k_copy_page_d16;
- _flush_cache_all = r4k_flush_cache_all_d16i16;
+ _flush_cache_l1 = r4k_flush_cache_all_d16i16;
_flush_cache_mm = r4k_flush_cache_mm_d16i16;
_flush_cache_range = r4k_flush_cache_range_d16i16;
_flush_cache_page = r4k_flush_cache_page_d16i16;
_clear_page = r4k_clear_page_d32;
_copy_page = r4k_copy_page_d32;
}
- _flush_cache_all = r4k_flush_cache_all_d32i32;
+ _flush_cache_l1 = r4k_flush_cache_all_d32i32;
_flush_cache_mm = r4k_flush_cache_mm_d32i32;
_flush_cache_range = r4k_flush_cache_range_d32i32;
_flush_cache_page = r4k_flush_cache_page_d32i32;
case 16:
switch(dc_lsize) {
case 16:
- _flush_cache_all = r4k_flush_cache_all_s16d16i16;
+ _flush_cache_l1 = r4k_flush_cache_all_s16d16i16;
_flush_cache_mm = r4k_flush_cache_mm_s16d16i16;
_flush_cache_range = r4k_flush_cache_range_s16d16i16;
_flush_cache_page = r4k_flush_cache_page_s16d16i16;
case 32:
switch(dc_lsize) {
case 16:
- _flush_cache_all = r4k_flush_cache_all_s32d16i16;
+ _flush_cache_l1 = r4k_flush_cache_all_s32d16i16;
_flush_cache_mm = r4k_flush_cache_mm_s32d16i16;
_flush_cache_range = r4k_flush_cache_range_s32d16i16;
_flush_cache_page = r4k_flush_cache_page_s32d16i16;
_flush_page_to_ram = r4k_flush_page_to_ram_s32d16i16;
break;
case 32:
- _flush_cache_all = r4k_flush_cache_all_s32d32i32;
+ _flush_cache_l1 = r4k_flush_cache_all_s32d32i32;
_flush_cache_mm = r4k_flush_cache_mm_s32d32i32;
_flush_cache_range = r4k_flush_cache_range_s32d32i32;
_flush_cache_page = r4k_flush_cache_page_s32d32i32;
case 64:
switch(dc_lsize) {
case 16:
- _flush_cache_all = r4k_flush_cache_all_s64d16i16;
+ _flush_cache_l1 = r4k_flush_cache_all_s64d16i16;
_flush_cache_mm = r4k_flush_cache_mm_s64d16i16;
_flush_cache_range = r4k_flush_cache_range_s64d16i16;
_flush_cache_page = r4k_flush_cache_page_s64d16i16;
_flush_page_to_ram = r4k_flush_page_to_ram_s64d16i16;
break;
case 32:
- _flush_cache_all = r4k_flush_cache_all_s64d32i32;
+ _flush_cache_l1 = r4k_flush_cache_all_s64d32i32;
_flush_cache_mm = r4k_flush_cache_mm_s64d32i32;
_flush_cache_range = r4k_flush_cache_range_s64d32i32;
_flush_cache_page = r4k_flush_cache_page_s64d32i32;
case 128:
switch(dc_lsize) {
case 16:
- _flush_cache_all = r4k_flush_cache_all_s128d16i16;
+ _flush_cache_l1 = r4k_flush_cache_all_s128d16i16;
_flush_cache_mm = r4k_flush_cache_mm_s128d16i16;
_flush_cache_range = r4k_flush_cache_range_s128d16i16;
_flush_cache_page = r4k_flush_cache_page_s128d16i16;
_flush_page_to_ram = r4k_flush_page_to_ram_s128d16i16;
break;
case 32:
- _flush_cache_all = r4k_flush_cache_all_s128d32i32;
+ _flush_cache_l1 = r4k_flush_cache_all_s128d32i32;
_flush_cache_mm = r4k_flush_cache_mm_s128d32i32;
_flush_cache_range = r4k_flush_cache_range_s128d32i32;
_flush_cache_page = r4k_flush_cache_page_s128d32i32;
_flush_tlb_mm = r4k_flush_tlb_mm;
_flush_tlb_range = r4k_flush_tlb_range;
_flush_tlb_page = r4k_flush_tlb_page;
+ _flush_cache_l2 = r4k_flush_cache_l2;
update_mmu_cache = r4k_update_mmu_cache;
_show_regs = r4k_show_regs;
_user_mode = r4k_user_mode;
- flush_cache_all();
+ flush_cache_l1();
/*
* You should never change this register:
memcpy((void *)(KSEG0 + 0x100), (void *) KSEG0, 0x80);
memcpy((void *)(KSEG0 + 0x180), &except_vec3_generic,
0x100);
- flush_cache_all();
+ flush_cache_l1();
+ flush_cache_l2();
}
#endif
}
init_mfhi_war();
#endif
_flush_tlb_all();
- flush_cache_all();
+ flush_cache_l1();
+ flush_cache_l2();
start_secondary();
}
return num_pages;
}
-/*
- * HACK ALERT - Things do not work if this is not here. Maybe this is
- * acting as a pseudocacheflush operation. The write pattern seems to
- * be important, writing a 0 does not help.
- */
-void setup_test(cnodeid_t node, pfn_t start, pfn_t end)
-{
- unsigned long *ptr = __va(start << PAGE_SHIFT);
- unsigned long size = 4 * 1024 * 1024; /* 4M L2 caches */
-
- while (size) {
- size -= sizeof(unsigned long);
- *ptr = (0xdeadbeefbabeb000UL|node);
- /* *ptr = 0; */
- ptr++;
- }
-}
-
/*
* Currently, the intranode memory hole support assumes that each slot
* contains at least 32 MBytes of memory. We assume all bootmem data
/* Foll line hack for non discontigmem; remove once discontigmem
* becomes the default. */
max_low_pfn = (slot_lastpfn - slot_firstpfn);
- if (node != 0)
- setup_test(node, slot_freepfn, slot_lastpfn);
+
/*
* Allocate the node data structure on the node first.
*/
offset("#define TASK_FLAGS ", struct task_struct, flags);
offset("#define TASK_SIGPENDING ", struct task_struct, sigpending);
offset("#define TASK_NEED_RESCHED ", struct task_struct, need_resched);
+ offset("#define TASK_PTRACE ", struct task_struct, ptrace);
offset("#define TASK_COUNTER ", struct task_struct, counter);
offset("#define TASK_NICE ", struct task_struct, nice);
offset("#define TASK_MM ", struct task_struct, mm);
SUB_DIRS :=
MOD_SUB_DIRS := $(SUB_DIRS)
-ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick pcmcia rio
+ALL_SUB_DIRS := $(SUB_DIRS) ftape joystick pcmcia rio drm agp
#
# This file contains the font map for the default (hardware) font
endif
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
-
obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o
-ifeq ($(CONFIG_ATARI_DSP56K),y)
-S = y
-else
- ifeq ($(CONFIG_ATARI_DSP56K),m)
- SM = y
- endif
-endif
-
obj-$(CONFIG_ROCKETPORT) += rocket.o
obj-$(CONFIG_MOXA_SMARTIO) += mxser.o
obj-$(CONFIG_MOXA_INTELLIO) += moxa.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_SPECIALIX) += specialix.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
-
-# After much ado, we found that an object can safely be declared as
-# both a module and into the kernel. Below that is filtered out.
-# So this should simply provide the wanted functionality!
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o
endif
obj-$(CONFIG_BUSMOUSE) += busmouse.o
-ifeq ($(CONFIG_BUSMOUSE),y)
-M = y
-else
- ifeq ($(CONFIG_BUSMOUSE),m)
- MM = m
- endif
-endif
-
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_INTEL_RNG) += i810_rng.o
-#
-# for external dependencies in arm/config.in and video/config.in
-#
-ifeq ($(CONFIG_BUS_I2C),y)
- L_I2C=y
-else
- ifeq ($(CONFIG_BUS_I2C),m)
- L_I2C=m
- endif
-endif
-
+obj-$(CONFIG_BUS_I2C) += i2c-old.o
obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o \
- tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o
-ifeq ($(CONFIG_VIDEO_BT848),y)
-L_TUNERS=y
-else
- ifeq ($(CONFIG_VIDEO_BT848),m)
- L_TUNERS=m
- endif
-endif
+ tda7432.o tda8425.o tda985x.o tda9875.o tea6300.o tea6420.o tuner.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
-obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
-ifeq ($(CONFIG_VIDEO_ZR36120),y)
-L_I2C=y
-L_TUNERS=y
-L_DECODERS=y
-else
- ifeq ($(CONFIG_VIDEO_ZR36120),m)
- L_I2C=m
- L_TUNERS=m
- L_DECODERS=m
- endif
-endif
-
-obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
-ifeq ($(CONFIG_I2C_PARPORT),y)
-L_I2C = y
-else
- ifeq ($(CONFIG_I2C_PARPORT),m)
- L_I2C = m
- endif
-endif
-
-obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
-ifeq ($(CONFIG_VIDEO_SAA5249),y)
-L_I2C=y
-else
- ifeq ($(CONFIG_VIDEO_SAA5249),m)
- L_I2C=m
- endif
-endif
-
+obj-$(CONFIG_VIDEO_ZR36120) += zoran.o i2c-old.o tuner.o saa7110.o saa7111.o saa7185.o
+obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o i2c-old.o
+obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o i2c-old.o
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_ZORAN) += buz.o
-ifeq ($(CONFIG_VIDEO_ZORAN),y)
-L_I2C=y
-L_DECODERS=y
-else
- ifeq ($(CONFIG_VIDEO_ZORAN),m)
- L_I2C=m
- L_DECODERS=m
- endif
-endif
-
+obj-$(CONFIG_VIDEO_ZORAN) += buz.o i2c-old.o saa7110.o saa7111.o saa7185.o
obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
obj-$(CONFIG_H8) += h8.o
obj-$(CONFIG_PPDEV) += ppdev.o
-
-# set when a framegrabber supports external tuners
-obj-$(L_TUNERS) += tuner.o
-
-# set when a framegrabber supports external decoders
-obj-$(L_DECODERS) += saa7110.o saa7111.o saa7185.o
-
-# set when a framegrabber implements i2c support
-obj-$(L_I2C) += i2c-old.o
-
obj-$(CONFIG_DZ) += dz.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
ifeq ($(CONFIG_DRM),y)
SUB_DIRS += drm
- ALL_SUB_DIRS += drm
MOD_SUB_DIRS += drm
+else
+ ifeq ($(CONFIG_DRM),m)
+ MOD_SUB_DIRS += drm
+ endif
endif
ifeq ($(CONFIG_PCMCIA),y)
ifeq ($(CONFIG_AGP), y)
SUB_DIRS += agp
- ALL_SUB_DIRS += agp
MOD_SUB_DIRS += agp
else
ifeq ($(CONFIG_AGP), m)
- ALL_SUB_DIRS += agp
MOD_SUB_DIRS += agp
endif
endif
#define __NO_VERSION__
#include "drmP.h"
+#include <linux/module.h>
drm_agp_func_t drm_agp = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
down(&dev->struct_sem);
for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
- if (pt->priv->authenticated)
- continue;
if (pt->magic == magic) {
retval = pt->priv;
break;
-
+#include <linux/config.h>
#include "drmP.h"
/* Misc. support (init.c) */
*/
#define __NO_VERSION__
+#include <linux/config.h>
#include "drmP.h"
typedef struct drm_mem_stats {
*/
#define __NO_VERSION__
+#include <linux/config.h>
#include "drmP.h"
#include "r128_drv.h"
#include "linux/un.h"
spin_unlock(&dev->count_lock);
}
- unlock_kernel();
-
return retcode;
}
atomic_read(&dev->ioctl_count),
dev->blocked);
spin_unlock(&dev->count_lock);
+ unlock_kernel();
return -EBUSY;
}
spin_unlock(&dev->count_lock);
+ unlock_kernel();
return tdfx_takedown(dev);
}
spin_unlock(&dev->count_lock);
nr -= num;
if (nr == 0)
break;
- current->state = TASK_RUNNING;
get_user(c, b);
- current->state = TASK_INTERRUPTIBLE;
if (opost(c, tty) < 0)
break;
b++; nr--;
if (tty->driver.flush_chars)
tty->driver.flush_chars(tty);
} else {
- current->state = TASK_RUNNING;
c = tty->driver.write(tty, 1, b, nr);
- current->state = TASK_INTERRUPTIBLE;
if (c < 0) {
retval = c;
goto break_out;
dep_tristate 'I2C bit-banging interfaces' CONFIG_I2C_ALGOBIT $CONFIG_I2C
if [ "$CONFIG_I2C_ALGOBIT" != "n" ]; then
- dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT
+ dep_tristate ' Philips style parallel port adapter' CONFIG_I2C_PHILIPSPAR $CONFIG_I2C_ALGOBIT $CONFIG_PARPORT
dep_tristate ' ELV adapter' CONFIG_I2C_ELV $CONFIG_I2C_ALGOBIT
dep_tristate ' Velleman K9000 adapter' CONFIG_I2C_VELLEMAN $CONFIG_I2C_ALGOBIT
fi
(hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
(hwif->pci_dev->device == PCI_DEVICE_ID_PROMISE_20267)) {
hwif->resetproc = &pdc202xx_reset;
- hwif->tri_proc = &pdc202xx_tristate;
}
#ifdef CONFIG_BLK_DEV_IDEDMA
MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i");
MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i");
+#endif
void __exit ace_module_cleanup(void)
{
root_dev = next;
}
}
-#endif
int __init ace_module_init(void)
*/
#include <linux/module.h>
-
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/types.h>
static void ioc3_timeout(struct net_device *dev);
static inline unsigned int ioc3_hash(const unsigned char *addr);
static void ioc3_stop(struct net_device *dev);
-static void ioc3_clean_tx_ring(struct ioc3_private *ip);
-static void ioc3_clean_rx_ring(struct ioc3_private *ip);
static void ioc3_init(struct net_device *dev);
static const char ioc3_str[] = "IOC3 Ethernet";
ip->stats.rx_packets++; /* Statistics */
ip->stats.rx_bytes += len;
-
} else {
/* The frame is invalid and the skb never
reached the network layer so we can just
((unsigned long) rxb & TO_PHYS_MASK);
rxb->w0 = 0; /* Clear valid flag */
n_entry = (n_entry + 1) & 511; /* Update erpir */
- ioc3->erpir = (n_entry << 3) | ERPIR_ARM;
/* Now go on to the next ring entry. */
rx_entry = (rx_entry + 1) & 511;
rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
w0 = rxb->w0;
}
+ ioc3->erpir = (n_entry << 3) | ERPIR_ARM;
ip->rx_pi = n_entry;
ip->rx_ci = rx_entry;
}
ioc3_error(struct net_device *dev, struct ioc3_private *ip,
struct ioc3 *ioc3, u32 eisr)
{
- if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR)) {
- if (eisr & EISR_RXMEMERR) {
- printk(KERN_ERR "%s: RX PCI error.\n", dev->name);
- }
- if (eisr & EISR_TXMEMERR) {
- printk(KERN_ERR "%s: TX PCI error.\n", dev->name);
- }
+ if (eisr & EISR_RXOFLO) {
+ printk(KERN_ERR "%s: RX overflow.\n", dev->name);
+ }
+ if (eisr & EISR_RXBUFOFLO) {
+ printk(KERN_ERR "%s: RX buffer overflow.\n", dev->name);
+ }
+ if (eisr & EISR_RXMEMERR) {
+ printk(KERN_ERR "%s: RX PCI error.\n", dev->name);
+ }
+ if (eisr & EISR_RXPARERR) {
+ printk(KERN_ERR "%s: RX SSRAM parity error.\n", dev->name);
+ }
+ if (eisr & EISR_TXBUFUFLO) {
+ printk(KERN_ERR "%s: TX buffer underflow.\n", dev->name);
+ }
+ if (eisr & EISR_TXMEMERR) {
+ printk(KERN_ERR "%s: TX PCI error.\n", dev->name);
}
ioc3_stop(dev);
- ioc3_clean_tx_ring(dev->priv);
ioc3_init(dev);
dev->trans_start = jiffies;
struct net_device *dev = (struct net_device *)_dev;
struct ioc3_private *ip = dev->priv;
struct ioc3 *ioc3 = ip->regs;
- const u32 enabled = EISR_RXTIMERINT | EISR_TXEXPLICIT |
- EISR_RXMEMERR | EISR_TXMEMERR;
+ const u32 enabled = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
+ EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
+ EISR_TXEXPLICIT | EISR_TXMEMERR;
u32 eisr;
eisr = ioc3->eisr & enabled;
ioc3->eisr = eisr;
ioc3->eisr; /* Flush */
+ if (eisr & (EISR_RXOFLO | EISR_RXBUFOFLO | EISR_RXMEMERR |
+ EISR_RXPARERR | EISR_TXBUFUFLO | EISR_TXMEMERR))
+ ioc3_error(dev, ip, ioc3, eisr);
if (eisr & EISR_RXTIMERINT)
ioc3_rx(dev, ip, ioc3);
if (eisr & EISR_TXEXPLICIT)
ioc3_tx(dev, ip, ioc3);
- if (eisr & (EISR_RXMEMERR | EISR_TXMEMERR))
- ioc3_error(dev, ip, ioc3, eisr);
+
eisr = ioc3->eisr & enabled;
}
}
/* Autonegotiate 100mbit and fullduplex. */
mii_write(ioc3, phy, 0, mii0 | 0x3100);
- spin_unlock_irq(&ip->ioc3_lock);
- mdelay(1000); /* XXX Yikes XXX */
- spin_lock_irq(&ip->ioc3_lock);
-
- mii_status = mii_read(ioc3, phy, 1);
spin_unlock_irq(&ip->ioc3_lock);
return 0;
}
+static inline void
+ioc3_clean_rx_ring(struct ioc3_private *ip)
+{
+ struct sk_buff *skb;
+ int i;
+
+ for (i = ip->rx_ci; i & 15; i++) {
+ ip->rx_skbs[ip->rx_pi] = ip->rx_skbs[ip->rx_ci];
+ ip->rxr[ip->rx_pi++] = ip->rxr[ip->rx_ci++];
+ }
+ ip->rx_pi &= 511;
+ ip->rx_ci &= 511;
+
+ for (i = ip->rx_ci; i != ip->rx_pi; i = (i+1) & 511) {
+ struct ioc3_erxbuf *rxb;
+ skb = ip->rx_skbs[i];
+ rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
+ rxb->w0 = 0;
+ }
+}
+
+static inline void
+ioc3_clean_tx_ring(struct ioc3_private *ip)
+{
+ struct sk_buff *skb;
+ int i;
+
+ for (i=0; i < 128; i++) {
+ skb = ip->tx_skbs[i];
+ if (skb) {
+ ip->tx_skbs[i] = NULL;
+ dev_kfree_skb_any(skb);
+ }
+ ip->txr[i].cmd = 0;
+ }
+ ip->tx_pi = 0;
+ ip->tx_ci = 0;
+}
+
+static void
+ioc3_free_rings(struct ioc3_private *ip)
+{
+ struct sk_buff *skb;
+ int rx_entry, n_entry;
+
+ ioc3_clean_tx_ring(ip);
+ ip->txr = NULL;
+ free_pages((unsigned long)ip->txr, 2);
+
+ n_entry = ip->rx_ci;
+ rx_entry = ip->rx_pi;
+
+ while (n_entry != rx_entry) {
+ skb = ip->rx_skbs[n_entry];
+ if (skb)
+ dev_kfree_skb_any(skb);
+
+ n_entry = (n_entry + 1) & 511;
+ }
+ free_page((unsigned long)ip->rxr);
+ ip->rxr = NULL;
+}
+
static void
ioc3_alloc_rings(struct net_device *dev, struct ioc3_private *ip,
struct ioc3 *ioc3)
ioc3_alloc_rings(dev, ip, ioc3);
- ioc3_clean_tx_ring(ip);
ioc3_clean_rx_ring(ip);
+ ioc3_clean_tx_ring(ip);
/* Now the rx ring base, consume & produce registers. */
ring = (0xa5UL << 56) | ((unsigned long)ip->rxr & TO_PHYS_MASK);
ioc3->etcir; /* Flush */
}
-static void
-ioc3_clean_tx_ring(struct ioc3_private *ip)
-{
- struct sk_buff *skb;
- int i;
-
- for (i=0; i < 128; i++) {
- skb = ip->tx_skbs[i];
- if (skb) {
- ip->tx_skbs[i] = NULL;
- dev_kfree_skb_any(skb);
- }
- ip->txr[i].cmd = 0;
- }
-}
-
-static void
-ioc3_clean_rx_ring(struct ioc3_private *ip)
-{
- struct sk_buff *skb;
- int i;
-
- for (i = 0; i < RX_BUFFS; i++) {
- struct ioc3_erxbuf *rxb;
- skb = ip->rx_skbs[i];
- rxb = (struct ioc3_erxbuf *) (skb->data - RX_OFFSET);
-
- rxb->w0 = 0;
- }
-}
-
-static void
-ioc3_free_rings(struct ioc3_private *ip)
-{
- struct sk_buff *skb;
- int rx_entry, n_entry;
-
- ioc3_clean_tx_ring(ip);
- free_pages((unsigned long)ip->txr, 2);
- ip->txr = NULL;
-
- n_entry = ip->rx_ci;
- rx_entry = ip->rx_pi;
-
- while (n_entry != rx_entry) {
- skb = ip->rx_skbs[n_entry];
- if (skb)
- dev_kfree_skb_any(skb);
-
- n_entry = (n_entry + 1) & 511;
- }
- free_page((unsigned long)ip->rxr);
- ip->rxr = NULL;
-}
-
static inline void
ioc3_ssram_disc(struct ioc3_private *ip)
{
ioc3->emar_h = (dev->dev_addr[5] << 8) | dev->dev_addr[4];
ioc3->emar_l = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) |
(dev->dev_addr[1] << 8) | dev->dev_addr[0];
- ioc3->ehar_h = ioc3->ehar_l = 0;
+ ioc3->ehar_h = ip->ehar_h;
+ ioc3->ehar_l = ip->ehar_l;
ioc3->ersr = 42; /* XXX should be random */
- //ioc3->erpir = ERPIR_ARM;
ioc3_init_rings(dev, ip, ioc3);
ip->emcr |= ((RX_OFFSET / 2) << EMCR_RXOFF_SHIFT) | EMCR_TXDMAEN |
- EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN;
+ EMCR_TXEN | EMCR_RXDMAEN | EMCR_RXEN;
ioc3->emcr = ip->emcr;
- ioc3->eier = EISR_RXTIMERINT | EISR_TXEXPLICIT | /* Interrupts ... */
- EISR_RXMEMERR | EISR_TXMEMERR;
+ ioc3->eier = EISR_RXTIMERINT | EISR_RXOFLO | EISR_RXBUFOFLO |
+ EISR_RXMEMERR | EISR_RXPARERR | EISR_TXBUFUFLO |
+ EISR_TXEXPLICIT | EISR_TXMEMERR;
ioc3->eier;
}
struct ioc3 *ioc3 = ip->regs;
ioc3->emcr = 0; /* Shutup */
- ip->emcr = 0;
ioc3->eier = 0; /* Disable interrupts */
ioc3->eier; /* Flush */
}
static int
ioc3_open(struct net_device *dev)
{
+ struct ioc3_private *ip;
+
if (request_irq(dev->irq, ioc3_interrupt, 0, ioc3_str, dev)) {
printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
return -EAGAIN;
}
- ((struct ioc3_private *)dev->priv)->ehar_h = 0;
- ((struct ioc3_private *)dev->priv)->ehar_l = 0;
+ ip = (struct ioc3_private *) dev->priv;
+
+ ip->ehar_h = 0;
+ ip->ehar_l = 0;
ioc3_init(dev);
netif_start_queue(dev);
printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
ioc3_stop(dev);
- ioc3_clean_tx_ring(dev->priv);
ioc3_init(dev);
dev->trans_start = jiffies;
if (!(*addr & 1))
continue;
- ehar |= (1 << ioc3_hash(addr));
+ ehar |= (1UL << ioc3_hash(addr));
}
ip->ehar_h = ehar >> 32;
ip->ehar_l = ehar & 0xffffffff;
pci_write_config_word(dev, 0xc0, legsup);
}
+/*
+ * VIA VT82C598 has its device ID settable and many BIOSes
+ * set it to the ID of VT82C597 for backward compatibility.
+ * We need to switch it off to be able to recognize the real
+ * type of the chip.
+ */
+static void __init quirk_vt82c598_id(struct pci_dev *dev)
+{
+ pci_write_config_byte(dev, 0xfc, 0);
+ pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
+}
+
/*
* The main table of quirks.
*/
/*
* Its not totally clear which chipsets are the problematic ones
* We know 82C586 and 82C596 variants are affected.
- *
*/
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci },
{ PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci },
+ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi },
{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi },
General Public License. Originally written by Martin Kolinek, December 1995.
Officially maintained by Michael Lang since January 1999.
- Version 3.1e
+ Version 3.2
- Last update: 20 February 1999
+ Last update: 29 July 2000
Authors of this Driver
- Klaus Kudielka (multiple SCSI-host management/detection, adaption to
Linux Kernel 2.1.x, module support)
- Michael Lang (assigning original pun,lun mapping, dynamical ldn
- assignment, this file, patch, official driver maintenance)
+ assignment, this file, patch, official driver maintenance
+ and subsequent pains related with the driver :-))
Table of Contents
-----------------
5.3 Bugreports
5.4 Support WWW-page
6 References
- 7 Trademarks
+ 7 Credits to
+ 7.1 People
+ 7.2 Sponsors & Supporters
+ 8 Trademarks
+ 9 Disclaimer
* * *
quite outdated. The history of the driver development is also kept inside
here. Multiple historical developments have been summarized to shorten the
textsize a bit. At the end of this file you can find a small manual for
- this driver and hints to get it running even on your machine (hopefully).
+ this driver and hints to get it running on your machine.
2 Driver Description
--------------------
Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the
Microchannel. In a next step, a free interrupt is chosen and the main
interrupt handler is connected to it to handle answers of the SCSI-
- subsystem(s). In a further step, it is checked, wether there was a forced
- detection of the adapter via the kernel commandline, where the I/O port
- and the SCSI-subsystem id can be specified. The next step checks if there
- is an integrated SCSI-subsystem installed. This register area is fixed
- through all IBM PS/2 MCA-machines and appears as something like a virtual
- slot 10 of the MCA-bus. If POS-register 2 is not 0xff, there must be a SCSI-
+ subsystem(s). If the F/W SCSI-adapter is forced by the BIOS to use IRQ11
+ instead of IRQ14, IRQ11 is used for the IBM SCSI-2 F/W adapter. In a
+ further step it is checked, if the adapter gets detected by force from
+ the kernel commandline, where the I/O port and the SCSI-subsystem id can
+ be specified. The next step checks if there is an integrated SCSI-subsystem
+ installed. This register area is fixed through all IBM PS/2 MCA-machines
+ and appears as something like a virtual slot 10 of the MCA-bus. On most
+ PS/2 machines, the POS registers of slot 10 are set to 0xff or 0x00 if not
+ integrated SCSI-controller is available. But on certain PS/2s, like model
+ 9595, this slot 10 is used to store other information which at earlier
+ stage confused the driver and resulted in the detection of some ghost-SCSI.
+ If POS-register 2 and 3 are not 0x00 and not 0xff, but all other POS
+ registers are either 0xff or 0x00, there must be an integrated SCSI-
subsystem present and it will be registered as IBM Integrated SCSI-
Subsystem. The next step checks, if there is a slot-adapter installed on
the MCA-bus. To get this, the first two POS-registers, that represent the
adapter ID are checked. If they fit to one of the ids, stored in the
- adapter list, a SCSI-subsystem is assumed to be found and will be
+ adapter list, a SCSI-subsystem is assumed to be found in a slot and will be
registered. This check is done through all possible MCA-bus slots to allow
more than one SCSI-adapter to be present in the PS/2-system and this is
already the first point of problems. Looking into the technical reference
manual for the IBM PS/2 common interfaces, the POS2 register must have
- different interpretation of its single bits. While one can assume, that the
- integrated subsystem has a fix I/O-address at 0x3540 - 0x3547, further
- installed IBM SCSI-adapters must use a different I/O-address. This is
- expressed by bit 1 to 3 of POS2 (multiplied by 8 + 0x3540). Bits 2 and 3
- are reserved for the integrated subsystem, but not for the adapters! The
- following list shows, how the bits of POS2 and POS3 should be interpreted.
+ different interpretation of its single bits to avoid overlapping I/O
+ regions. While one can assume, that the integrated subsystem has a fix
+ I/O-address at 0x3540 - 0x3547, further installed IBM SCSI-adapters must
+ use a different I/O-address. This is expressed by bit 1 to 3 of POS2
+ (multiplied by 8 + 0x3540). Bits 2 and 3 are reserved for the integrated
+ subsystem, but not for the adapters! The following list shows, how the
+ bits of POS2 and POS3 should be interpreted.
The POS2-register of all PS/2 models' integrated SCSI-subsystems has the
following interpretation of bits:
Bit 3 - 2 : Reserved
Bit 1 : 8k NVRAM Disabled
Bit 0 : Chip Enable (EN-Signal)
- The POS3-register is interpreted as follows (for ALL IBM SCSI-subsys.):
+ The POS3-register is interpreted as follows (for most IBM SCSI-subsys.):
Bit 7 - 5 : SCSI ID
Bit 4 - 0 : Reserved = 0
- (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
- Interfaces (1991)").
- In short words, this means, that IBM PS/2 machines only support 1 single
- subsystem by default. But (additional) slot-adapters must have another
- configuration on pos2 in order to be enabled to use more than one IBM SCSI-
- subsystem, e.g. for a network server. From tests with the IBM SCSI Adapter
- w/cache, the POS2-register for slot adapters should be interpreted in the
- following way:
- Bit 7 - 4 : Chip Revision ID (Release)
- Bit 3 - 1 : port offset factor ( * 8 + 0x3540 )
- Bit 0 : Chip Enable (EN-Signal)
+ The slot-adapters have different interpretation of these bits. The IBM SCSI
+ adapter (w/Cache) and the IBM SCSI-2 F/W adapter use the following
+ interpretation of the POS2 register:
+ Bit 7 - 4 : ROM Segment Address Select
+ Bit 3 - 1 : Adapter I/O Address Select (*8+0x3540)
+ Bit 0 : Adapter Enable (EN-Signal)
+ and for the POS3 register:
+ Bit 7 - 5 : SCSI ID
+ Bit 4 : Fairness Enable (SCSI ID3 f. F/W)
+ Bit 3 - 0 : Arbitration Level
+ The most modern product of the series is the IBM SCSI-2 F/W adapter, it
+ allows dual-bus SCSI and SCSI-wide addressing, which means, PUNs may be
+ between 0 and 15. Here, Bit 4 is the high-order bit of the 4-bit wide
+ adapter PUN expression. In short words, this means, that IBM PS/2 machines
+ can only support 1 single integrated subsystem by default. Additional
+ slot-adapters get ports assigned by the automatic configuration tool.
One day I found a patch in ibmmca_detect(), forcing the I/O-address to be
0x3540 for integrated SCSI-subsystems, there was a remark placed, that on
number or pun, also called the scsi id, this is the number you select
with hardware jumpers), and each physical unit can have up to 8
"logical units" (each identified by logical unit number, or lun,
- between 0 and 7).
+ between 0 and 7). The IBM SCSI-2 F/W adapter offers this on up to two
+ busses and provides support for 30 logical devices at the same time, where
+ in wide-addressing mode you can have 16 puns with 32 luns on each device.
+ This section dexribes you the handling of devices on non-F/W adapters.
+ Just imagine, that you can have 16 * 32 = 512 devices on a F/W adapter
+ which means a lot of possible devices for such a small machine.
Typically the adapter has pun=7, so puns of other physical units
- are between 0 and 6. Almost all physical units have only one
- logical unit, with lun=0. A CD-ROM jukebox would be an example of
- a physical unit with more than one logical unit.
+ are between 0 and 6(15). On a wide-adapter a pun higher than 7 is
+ possible, but is normally not used. Almost all physical units have only
+ one logical unit, with lun=0. A CD-ROM jukebox would be an example of a
+ physical unit with more than one logical unit.
The embedded microprocessor of the IBM SCSI-subsystem hides the complex
two-dimensional (pun,lun) organization from the operating system.
checks, on its own, all 56 possible (pun,lun) combinations, and the first
15 devices found are assigned into a one-dimensional array of so-called
"logical devices", identified by "logical device numbers" or ldn. The last
- ldn=15 is reserved for the subsystem itself.
+ ldn=15 is reserved for the subsystem itself. Wide adapters may have
+ to check up to 15 * 8 = 120 pun/lun combinations.
2.3 SCSI-Device Recognition and dynamical ldn Assignment
--------------------------------------------------------
numbers are also hidden. The two possibilities to get around this problem
is to offer fake pun/lun combinations to the operating system or to
delete the whole mapping of the adapter and to reassign the ldns, using
- the immediate assign command of the SCSI-subsystem. At the beginning of the
- development of this driver, the following approach was used:
+ the immediate assign command of the SCSI-subsystem for probing through
+ all possible pun/lun combinations. a ldn is a "logical device number"
+ which is used by IBM SCSI-subsystems to access some valid SCSI-device.
+ At the beginning of the development of this driver, the following approach
+ was used:
+
First, the driver checked the ldn's (0 to 6) to find out which ldn's
have devices assigned. This was done by the functions check_devices() and
device_exists(). The interrupt handler has a special paragraph of code
and later, realizes the device recognition in the following way:
The physical SCSI-devices on the SCSI-bus are probed via immediate_assign-
and device_inquiry-commands, that is all implemented in a completely new
- made check_devices() subroutine. This delivers a exact map of the physical
+ made check_devices() subroutine. This delivers an exact map of the physical
SCSI-world that is now stored in the get_scsi[][]-array. This means,
that the once hidden pun,lun assignment is now known to this driver.
It no longer believes in default-settings of the subsystem and maps all
can be different from the old, faked puns. Therefore, Linux will eventually
change /dev/sdXXX assignments and prompt you for corrupted superblock
repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
- You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file
+ You have to reboot (CTRL-D) with an old kernel and set the /etc/fstab-file
entries right. After that, the system should come up as errorfree as before.
If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
in a Linux session booted on old kernel and run lilo before reboot. Check
----------------------------------
The following IBM SCSI-subsystems are supported by this driver:
- - IBM Fast SCSI-2 Adapter
+ - IBM Fast/Wide SCSI-2 Adapter
- IBM 7568 Industrial Computer SCSI Adapter w/cache
- IBM Expansion Unit SCSI Controller
- IBM SCSI Adapter w/Cache
- IBM SCSI Adapter
- IBM Integrated SCSI Controller
+ - All clones, 100% compatible with the chipset and subsystem command
+ system of IBM SCSI-adapters (forced detection)
2.14 Linux Kernel Versions
--------------------------
The IBM SCSI-subsystem low level driver is prepared to be used with
- all versions of Linux between 2.0.x and 2.2.x. The compatibility checks
+ all versions of Linux between 2.0.x and 2.4.x. The compatibility checks
are fully implemented up from version 3.1e of the driver. This means, that
you just need the latest ibmmca.h and ibmmca.c file and copy it in the
linux/drivers/scsi directory. The code is automatically adapted during
addition more flexibility.
- Michael Lang
+ Apr 23, 2000 (v3.2pre1)
+ 1) During a very long time, I collected a huge amount of bugreports from
+ various people, trying really quite different things on their SCSI-
+ PS/2s. Today, all these bugreports are taken into account and should be
+ mostly solved. The major topics were:
+ - Driver crashes during boottime by no obvious reason.
+ - Driver panics while the midlevel-SCSI-driver is trying to inquire
+ the SCSI-device properties, even though hardware is in perfect state.
+ - Displayed info for the various slot-cards is interpreted wrong.
+ The main reasons for the crashes were two:
+ 1) The commands to check for device information like INQUIRY,
+ TEST_UNIT_READY, REQUEST_SENSE and MODE_SENSE cause the devices
+ to deliver information of up to 255 bytes. Midlevel drivers offer
+ 1024 bytes of space for the answer, but the IBM-SCSI-adapters do
+ not accept this, as they stick quite near to ANSI-SCSI and report
+ a COMMAND_ERROR message which causes the driver to panic. The main
+ problem was located around the INQUIRY command. Now, for all the
+ mentioned commands, the buffersize, sent to the adapter is at
+ maximum 255 which seems to be a quite reasonable solution.
+ TEST_UNIT_READY gets a buffersize of 0 to make sure, that no
+ data is transferred in order to avoid any possible command failure.
+ 2) On unsuccessful TEST_UNIT_READY, the midlevel-driver has to send
+ a REQUEST_SENSE in order to see, where the problem is located. This
+ REQUEST_SENSE may have various length in its answer-buffer. IBM
+ SCSI-subsystems report a command failure, if the returned buffersize
+ is different from the sent buffersize, but this can be supressed by
+ a special bit, which is now done and problems seem to be solved.
+ 2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on
+ 2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes.
+ 3) Commandline-parameters are recognized again, even under Kernel 2.3.x or
+ higher.
+ - Michael Lang
+
+ April 27, 2000 (v3.2pre2)
+ 1) Bypassed commands get read by the adapter by one cycle instead of two.
+ This increases SCSI-performance.
+ 2) Synchronous datatransfer is provided for sure to be 5 MHz on older
+ SCSI and 10 MHz on internal F/W SCSI-adapter.
+ 3) New commandline parameters allow to force the adapter to slow down while
+ in synchronous transfer. Could be helpful for very old devices.
+ - Michael Lang
+
+ June 2, 2000 (v3.2pre5)
+ 1) Added Jim Shorney's contribution to make the activity indicator
+ flashing in addition to the LED-alphanumeric display-panel on
+ models 95A. To be enabled to choose this feature freely, a new
+ commandline parameter is added, called 'activity'.
+ 2) Added the READ_CONTROL bit for test_unit_ready SCSI-command.
+ 3) Added some suppress_exception bits to read_device_capacity and
+ all device_inquiry occurences in the driver code.
+ 4) Complaints about the various KERNEL_VERSION implementations are
+ taken into account. Every local_LinuxKernelVersion occurence is
+ now replaced by KERNEL_VERSION, defined in linux/version.h.
+ Corresponding changes were applied to ibmmca.h, too. This was a
+ contribution to all kernel-parts by Philipp Hahn.
+ - Michael Lang
+
+ July 17, 2000 (v3.2pre8)
+ A long period of collecting bugreports from all corners of the world
+ now lead to the following corrections to the code:
+ 1) SCSI-2 F/W support crashed with a COMMAND ERROR. The reason for this
+ was, that it is possible to disbale Fast-SCSI for the external bus.
+ The feature-control command, where this crash appeared regularly tried
+ to set the maximum speed of 10MHz synchronous transfer speed and that
+ reports a COMMAND ERROR, if external bus Fast-SCSI is disabled. Now,
+ the feature-command probes down from maximum speed until the adapter
+ stops to complain, which is at the same time the maximum possible
+ speed selected in the reference program. So, F/W external can run at
+ 5 MHz (slow-) or 10 MHz (fast-SCSI). During feature probing, the
+ COMMAND ERROR message is used to detect if the adapter does not complain.
+ 2) Up to now, only combined busmode is supported, if you use external
+ SCSI-devices, attached to the F/W-controller. If dual bus is selected,
+ only the internal SCSI-devices get accessed by Linux. For most
+ applications, this should do fine.
+ 3) Wide-SCSI-addressing (16-Bit) is now possible for the internal F/W
+ bus on the F/W adapter. If F/W adapter is detected, the driver
+ automatically uses the extended PUN/LUN <-> LDN mapping tables, which
+ are now new from 3.2pre8. This allows PUNs between 0 and 15 and should
+ provide more fun with the F/W adapter.
+ 4) Several machines use the SCSI: POS registers for internal/undocumented
+ storage of system relevant info. This confused the driver, mainly on
+ models 9595, as it expected no onboard SCSI only, if all POS in
+ the integrated SCSI-area are set to 0x00 or 0xff. Now, the mechanism
+ to check for integrated SCSI is much more restrictive and these problems
+ should be history.
+ - Michael Lang
+
+ July 18, 2000 (v3.2pre9)
+ This develop rather quickly at the moment. Two major things were still
+ missing in 3.2pre8:
+ 1) The adapter PUN for F/W adapters has 4-bits, while all other adapters
+ have 3-bits. This is now taken into account for F/W.
+ 2) When you select CONFIG_IBMMCA_SCSI_ORDER_STANDARD, you should
+ normally get the inverse probing order of your devices on the SCSI-bus.
+ The ANSI device order gets scrambled in version 3.2pre8!! Now, a new
+ and tested algorithm inverts the device-order on the SCSI-bus and
+ automatically avoids accidental access to whatever SCSI PUN the adapter
+ is set and works with SCSI- and Wide-SCSI-addressing.
+ - Michael Lang
+
+ July 23, 2000 (v3.2pre10 unpublished)
+ 1) LED panel display supports wide-addressing in ibmmca=display mode.
+ 2) Adapter-information and autoadaption to address-space is done.
+ 3) Auto-probing for maximum synchronous SCSI transfer rate is working.
+ 4) Optimization to some embedded function calls is applied.
+ 5) Added some comment for the user to wait for SCSI-devices beeing probed.
+ 6) Finished version 3.2 for Kernel 2.4.0. It least, I thought it is but...
+ - Michael Lang
+
+ July 26, 2000 (v3.2pre11)
+ 1) I passed a horrible weekend getting mad with NMIs on kernel 2.2.14 and
+ a model 9595. Asking around in the community, nobody except of me has
+ seen such errors. Weired, but I am trying to recompile everything on
+ the model 9595. Maybe, as I use a specially modified gcc, that could
+ cause problems. But, it was not the reason. The true background was,
+ that the kernel was compiled for i386 and the 9595 has a 486DX-2.
+ Normally, no troubles should appear, but for this special machine,
+ only the right processor support is working fine!
+ 2) Previous problems with synchronous speed, slowing down from one adapter
+ to the next during probing are corrected. Now, local variables store
+ the synchronous bitmask for every single adapter found on the MCA bus.
+ 3) LED alphanumeric panel support for XX95 systems is now showing some
+ alive rotator during boottime. This makes sense, when no monitor is
+ connected to the system. You can get rid of all display activity, if
+ you do not use any parameter or just ibmmcascsi=activity, for the
+ harddrive activity LED, existant on all PS/2, except models 8595-XXX.
+ If no monitor is available, please use ibmmcascsi=display, which works
+ fine together with the linuxinfo utility for the LED-panel.
+ - Michael Lang
+
+ July 29, 2000 (v3.2)
+ 1) Submission of this driver for kernel 2.4test-XX and 2.2.17.
+ - Michael Lang
+
4 To do
-------
+ - IBM SCSI-2 F/W external SCSI bus support in seperate mode.
- It seems that the handling of bad disks is really bad -
non-existent, in fact.
- More testing of the full driver-controlled dynamical ldn
- (re)mapping for up to 56 SCSI-devices.
- - Support more of the SCSI-command set.
- - Support some of the caching abilities, particularly Read Prefetch.
- This fetches data into the cache, which later gets hit by the
- regular Read Data. (<--- This is coming soon!!!!)
- - Abort and Reset functions still slightly buggy or better say,
- it is the new episode, called SCREAM III.
+ (re)mapping for up to 56 SCSI-devices. I guess, it won't work
+ at the moment, but nobody ever really tried it.
+ - Abort and Reset functions still slightly buggy.
5 Users' Manual
---------------
where '-' stays dark, 'D' shows the SCSI-device id
and 'A' shows the SCSI hostindex, beeing currently
- accessed.
+ accessed. During boottime, this will give the message
+
+ SCSIini*
+
+ on the LED-panel, where the * represents a rotator,
+ showing the activity during the probing phase of the
+ driver which can take up to two minutes per SCSI-adapter.
adisplay This works like display, but gives more optical overview
of the activities on the SCSI-bus. The display will have
the following output:
hostindex. If display nor adisplay is set, the internal
PS/2 harddisk LED is used for media-activities. So, if
you really do not have a system with a LED-display, you
- should not set display or adisplay.
+ should not set display or adisplay. Keep in mind, that
+ display and adisplay can only be used alternatively. It
+ is not recommended to use this option, if you have some
+ wide-addressed devices e.g. at the SCSI-2 F/W adapter in
+ your system. In addition, the usage of the display for
+ other tasks in parallel, like the linuxinfo-utility makes
+ no sense with this option.
+ activity This enables the PS/2 harddisk LED activity indicator.
+ Most PS/2 have no alphanumeric LED display, but some
+ indicator. So you should use this parameter to activate it.
+ If you own model 9595 (Server95), you can have both, the
+ LED panel and the activity indicator in parallel. However,
+ some PS/2s, like the 8595 do not have any harddisk LED
+ activity indicator, which means, that you must use the
+ alphanumeric LED display if you want to monitor SCSI-
+ activity.
bypass This commandline parameter forces the driver never to use
SCSI-subsystems' integrated SCSI-command set. Except of
the immediate assign, which is of vital importance for
this flag will slow-down SCSI-accesses slightly, as the
software generated commands are always slower than the
hardware. Non-harddisk devices always get read/write-
- commands in bypass mode.
+ commands in bypass mode. On the most recent releases of
+ the Linux IBM-SCSI-driver, the bypass command should be
+ no longer a necessary thing, if you are sure about your
+ SCSI-hardware!
normal This is the parameter, introduced on the 2.0.x development
rail by ZP Gu. This parameter defines the SCSI-device
scan order in the new industry standard. This means, that
pun=6 gets sda and a harddisk at pun=0 gets sdb. If you
like to have the same SCSI-device order, as in DOS, OS-9
or OS/2, just use this parameter.
+ fast SCSI-I/O in synchronous mode is done at 5 MHz for IBM-
+ SCSI-devices. SCSI-2 Fast/Wide Adapter/A external bus
+ should then run at 10 MHz if Fast-SCSI is enabled,
+ and at 5 MHz if Fast-SCSI is disabled on the external
+ bus. This is the default setting when nothing is
+ specified here.
+ medium Synchronous rate is at 50% approximately, which means
+ 2.5 MHz for IBM SCSI-adapters and 5.0 MHz for F/W ext.
+ SCSI-bus (when Fast-SCSI speed enabled on external bus).
+ slow The slowest possible synchronous transfer rate is set.
+ This means 1.82 MHz for IBM SCSI-adapters and 2.0 MHz
+ for F/W external bus at Fast-SCSI speed on the external
+ bus.
A further option is that you can force the SCSI-driver to accept a SCSI-
subsystem at a certain I/O-address with a predefined adapter PUN. This
ibmmcascsi=adisplay,bypass
This will use the advanced display mode for the model 95 LED display and
- every SCSI-command passed to a attached device will get bypassed in order
+ every SCSI-command passed to an attached device will get bypassed in order
not to use any of the subsystem built-in commands.
ibmmcascsi=display,0x3558,7
with OS/2 and DOS, you have to activate this flag in the kernel
configuration or you should set 'ansi' as parameter for the kernel.
The parameter 'normal' sets the new industry standard, starting
- from pun 0, scaning up to pun 6. This allows you to change your
+ from pun 0, scanning up to pun 6. This allows you to change your
opinion still after having already compiled the kernel.
- Q: Why can I not find the IBM MCA SCSI support in the config menue?
+ Q: Why I cannot find the IBM MCA SCSI support in the config menue?
A: You have to activate MCA bus support, first.
Q: Where can I find the latest info about this driver?
A: See the file MAINTAINERS for the current WWW-address, which offers
A: Just force it to be recognized by kernel parameters. See section 5.1.
Q: The driver screws up, if it starts to probe SCSI-devices, is there
some way out of it?
- A: This is based on some problems with the driver. In such cases, send
- e-mail to the maintainer. If you are owner of a model with the serial
- number 95XX, just send as subject NOTIFY 95XX PROBLEM and the
- maintainer immediately knows about your problem. But please:
- Check your hardware and only if it works fine with other operating
- systems, send E-Mail to me to notify the troubles. See the homepage
- for how to send bug-reports or please read the next Q/A, here:
+ A: Yes, that was some recognition problem of the correct SCSI-adapter
+ and its I/O base addresses. Upgrade your driver to the latest release
+ and it should be fine again.
Q: I get a message: panic IBM MCA SCSI: command error .... , what can
I do against this?
A: Previously, I followed the way by ignoring command errors by using
ibmmcascsi=forgiveall. Are there other possibilities to prevent
such panics?
A: No, get just the latest release of the driver and it should work
- better and better with increasing version number. Forget this
- ibmmcascsi=forgiveall, as also ignorecmd are obsolete.
+ better and better with increasing version number. Forget about this
+ ibmmcascsi=forgiveall, as also ignorecmd are obsolete.!
Q: Linux panics or stops without any comment, but it is probable, that my
harddisk(s) have bad blocks.
A: Sorry, the bad-block handling is still a feeble point of this driver,
Astonishingly, reset works in most cases quite ok, but the harddisks
won't run in synchonous mode anymore after a reset, until you reboot.
Q: Why does my XXX w/Cache adapter not use read-prefetch?
- A: w/Cache technical manuals are incoming here, so if I understood the
- command of read-prefetch, it should be an easy thing to get harddisks
- read in read-prefetch with w/Cache controllers. Some weeks or months,
- still ahead and a lot of work still to do, sigh ...
+ A: Ok, that is not completely possible. If a cache is present, the
+ adapter tries to use it internally. Explicitly, one can use the cache
+ with a read prefetch command, maybe in future, but this requires
+ some major overhead of SCSI-commands that risks the performance to
+ go down more than it gets improved. Tests with that are running.
+ Q: I have a IBM SCSI-2 Fast/Wide adapter, it boots in some way and hangs.
+ A: Yes, that is understood, as for sure, your SCSI-2 Fast/Wide adapter
+ was in such a case recognized as integrated SCSI-adapter or something
+ else, but not as the correct adapter. As the I/O-ports get assigned
+ wrongly by that reason, the system should crash in most cases. You
+ should upgrade to the latest release of the SCSI-driver. The
+ recommended version is 3.2 or later. Here, the F/W support is in
+ a stable and reliable condition. Wide-addressing is in addition
+ supported.
+ Q: I get a Ooops message and something like "killing interrupt".
+ A: The reason for this is that the IBM SCSI-subsystem only sends a
+ termination status back, if some error appeared. In former releases
+ of the driver, it was not checked, if the termination status block
+ is NULL. From version 3.2, it is taken care of this.
+ Q: I have a F/W adapter and the driver sees my internal SCSI-devices,
+ but ignores the external ones.
+ A: Select combined busmode in the config-program and check for that
+ no SCSI-id on the external devices appears on internal devices.
+ Reboot afterwards. Dual busmode is supported, but works only for the
+ internal bus, yet. External bus is still ignored. Take care for your
+ SCSI-ids. If combined bus-mode is activated, on some adapters,
+ the wide-addressing is not possible, so devices with ids between 8
+ and 15 get ignored by the driver & adapter!
+ Q: I have a 9595 and I get a NMI during heavy SCSI I/O e.g. during fsck.
+ A COMMAND ERROR is reported and characters on the screen are missing.
+ Warm reboot is not possible. Things look like quite weired.
+ A: Check the processor type of your 9595. If you have an 80486 or 486DX-2
+ processor complex on your mainboard and you compiled a kernel that
+ supports 80386 processors, it is possible, that the kernel cannot
+ keep track of the PS/2 interrupt handling and stops on an NMI. Just
+ compile a kernel for the correct processor type of your PS/2 and
+ everything should be fine. This is necessary even if one assumes,
+ that some 80486 system should be downward compatible to 80386
+ software.
5.3 Bugreports
--------------
Zubkoff, as Linus is burried in E-Mail and Leonard is supervising all
SCSI-drivers and won't have the time left to look inside every single
driver to fix a bug and especially DO NOT send modified code to Linus
- Torvalds, which has not been checked here!!! Recently, I got a lot of
+ Torvalds or Alan J. Cox which has not been checked here!!! They are both
+ quite burried in E-mail (as me, sometimes, too) and one should first check
+ for problems on my local teststand. Recently, I got a lot of
bugreports for errors in the ibmmca.c code, which I could not imagine, but
a look inside some Linux-distribution showed me quite often some modified
code, which did no longer work on most other machines than the one of the
http://www.uni-mainz.de/~langm000/linux.html
Here you can find info about the background of this driver, patches,
- news and a bugreport form.
+ troubleshooting support, news and a bugreport form. Please check that
+ WWW-page regularly for latest hints.
+
+ For the bugreport, please fill out the formular on the corresponding
+ WWW-page. Read the dedicated instructions and write as much as you
+ know about your problem. If you do not like such formulars, please send
+ some e-mail directly, but at least with the same information as required by
+ the formular.
+
+ If you have extensive bugreports, including Ooops messages and
+ screen-shots, please feel free to send it directly to the address
+ of the maintainer, too. The current address of the maintainer is:
+
+ Michael Lang <langa2@kph.uni-mainz.de>
6 References
------------
- The source of information is "Update for the PS/2 Hardware
- Interface Technical Reference, Common Interfaces", September 1991,
- part number 04G3281, available in the U.S. for $21.75 at
- 1-800-IBM-PCTB, elsewhere call your local friendly IBM
- representative. E.g. in Germany, "Hallo IBM" works really great.
- In addition to SCSI subsystem, this update contains fairly detailed
- (at hardware register level) sections on diskette controller,
- keyboard controller, serial port controller, VGA, and XGA.
+ IBM Corp., "Update for the PS/2 Hardware Interface Technical Reference,
+ Common Interfaces", Armonk, September 1991, PN 04G3281,
+ (available in the U.S. for $21.75 at 1-800-IBM-PCTB or in Germany for
+ around 40,-DM at "Hallo IBM").
- Additional information from "Personal System/2 Micro Channel SCSI
- Adapter with Cache Technical Reference", March 1990, PN 68X2365,
- probably available from the same source (or possibly found buried
- in officemates desk).
+ IBM Corp., "Personal System/2 Micro Channel SCSI
+ Adapter with Cache Technical Reference", Armonk, March 1990, PN 68X2365.
+
+ IBM Corp., "Personal System/2 Micro Channel SCSI
+ Adapter Technical Reference", Armonk, March 1990, PN 68X2397.
+
+ IBM Corp., "SCSI-2 Fast/Wide Adapter/A Technical Reference - Dual Bus",
+ Armonk, March 1994, PN 83G7545.
Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme *
Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988
- 7 Trademarks
+ 7 Credits to
+ ------------
+ 7.1 People
+ ----------
+ Klaus Grimm
+ who already a long time ago gave me the old code from the
+ SCSI-driver in order to get it running for some old machine
+ in our institute.
+ Martin Kolinek
+ who wrote the first release of the IBM SCSI-subsystem driver.
+ Chris Beauregard
+ who for a long time maintained MCA-Linux and the SCSI-driver
+ in the beginning. Chris, wherever you are: Cheers to you!
+ Klaus Kudielka
+ with whom in the 2.1.x times, I had a quite fruitful
+ cooperation to get the driver running as a module and to get
+ it running with multiple SCSI-adapters.
+ David Weinehall
+ for his excellent maintenance of the MCA-stuff and the quite
+ detailed bug reports and ideas for this driver (and his
+ patience ;-)).
+ Alan J. Cox
+ for his bugreports and his bold activities in cross-checking
+ the driver-code with his teststand.
+
+ 7.2 Sponsors & Supporters
+ -------------------------
+ "Hallo IBM",
+ IBM-Deutschland GmbH
+ the service of IBM-Deutschland for customers. Their E-Mail
+ service is unbeatable. Whatever old stuff I asked for, I
+ always got some helpful answers.
+ Karl-Otto Reimers,
+ IBM Klub - Sparte IBM Geschichte, Sindelfingen
+ for sending me a copy of the w/Cache manual from the
+ IBM-Deutschland archives.
+ Harald Staiger
+ for his extensive hardware donations which allows me today
+ still to test the driver in various constellations.
+ Erich Fritscher
+ for his very kind sponsoring.
+ Louis Ohland,
+ Charles Lasitter
+ for support by shipping me an IBM SCSI-2 Fast/Wide manual.
+ In addition, the contribution of various hardware is quite
+ decessive and will make it possible to add FWSR (RAID)
+ adapter support to the driver in the near future! So,
+ complaints about no RAID support won't remain forever.
+ Yes, folks, that is no joke, RAID support is going to rise!
+ Erik Weber
+ for the great deal we made about a model 9595 and the nice
+ surrounding equipment and the cool trip to Mannheim
+ second-hand computer market.
+ Anthony Hogbin
+ for his direct shipment of a SCSI F/W adapter, which allowed
+ me immediately on the first stage to try it on model 8557
+ together with onboard SCSI adapter and some SCSI w/Cache.
+ Andreas Hotz
+ for his support by memory and an IBM SCSI-adapter. Collecting
+ all this together now allows me to try really things with
+ the driver at maximum load and variety on various models in
+ a very quick and efficient way.
+ Peter Jennewein
+ for his model 30, which serves me as part of my teststand
+ and his cool remark about how you make an ordinary diskette
+ drive working and how to connect it to an IBM-diskette port.
+ Johannes Gutenberg-University, Mainz &
+ Institut fuer Kernphysik, MAMI
+ for the offered space, the link, placed on the central
+ homepage and the space to store and offer the driver and
+ related material and the free working times, which allow
+ me to answer all your e-mail.
+
+ 8 Trademarks
------------
IBM, PS/2, OS/2, Microchannel are registered trademarks of International
- Business Machines Corp.
+ Business Machines Corporation
MS-DOS is a registered trademark of Microsoft Corporation
- OS-9 is a registered trademark of Microware Systems
+ Microware, OS-9 are registered trademarks of Microware Systems
+
+ 9 Disclaimer
+ ------------
+ Beside the GNU public license and the dependant disclaimers and disclaimers
+ concerning the Linux-kernel in special, this SCSI-driver comes without any
+ warranty. Its functionality is tested as good as possible on certain
+ machines and combinations of computer hardware, which does not exclude,
+ that dataloss or severe damage of hardware is possible while using this
+ part of software on some arbitrary computer hardware or in combination
+ with other software packages. It is highly recommended to make backup
+ copies of your data before using this software.
+
+ This driver supports hardware, produced by International Business Machines
+ Corporation (IBM).
------
Michael Lang
* See the file README.ibmmca for a detailed description of this driver,
* the commandline arguments and the history of its development.
* See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
- * updates and info.
+ * updates, info and ADF-files for adapters supported by this driver.
*/
/******************* HEADER FILE INCLUDES ************************************/
#endif
/* choose adaption for Kernellevel */
-#define local_LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,65)
+#define OLDKERN
+#else
+#undef OLDKERN
+#endif
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/stat.h>
#include <linux/mca.h>
#include <asm/system.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,17)
#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#include <asm/spinlock.h>
+#endif
#include <asm/io.h>
+#include <linux/init.h>
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
/******************* LOCAL DEFINES *******************************************/
+/* milliseconds of delay for timing out reset. */
#ifndef mdelay
#define mdelay(a) udelay((a) * 1000)
#endif
/*--------------------------------------------------------------------*/
/* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "3.1e"
+#define IBMMCA_SCSI_DRIVER_VERSION "3.2"
/*--------------------------------------------------------------------*/
/* driver debugging - #undef all for normal operation */
/* if defined: count interrupts and ignore this special one: */
-#undef IM_DEBUG_TIMEOUT 50
+#undef IM_DEBUG_TIMEOUT 50
#define TIMEOUT_PUN 0
#define TIMEOUT_LUN 0
/* verbose interrupt: */
-#undef IM_DEBUG_INT
+#undef IM_DEBUG_INT
/* verbose queuecommand: */
-#undef IM_DEBUG_CMD
+#undef IM_DEBUG_CMD
/* verbose queucommand for specific SCSI-device type: */
-#undef IM_DEBUG_CMD_SPEC_DEV
+#undef IM_DEBUG_CMD_SPEC_DEV
/* verbose device probing */
-#undef IM_DEBUG_PROBE
+#define IM_DEBUG_PROBE
/* device type that shall be displayed on syslog (only during debugging): */
#define IM_DEBUG_CMD_DEVICE TYPE_TAPE
/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
#define IM_SCB_CMD_COMPLETED 0x10
#define IM_SCB_CMD_COMPLETED_WITH_RETRIES 0x50
+#define IM_LOOP_SCATTER_BUFFER_FULL 0x60
#define IM_ADAPTER_HW_FAILURE 0x70
#define IM_IMMEDIATE_CMD_COMPLETED 0xa0
#define IM_CMD_COMPLETED_WITH_FAILURE 0xc0
unsigned short length; /*block length, on SCSI device */
}
blk;
- unsigned char scsi_command[12]; /*other scsi command */
+ unsigned char scsi_command[12]; /*other scsi command */
}
u2;
};
unsigned long byte_length;
};
+/*structure returned by a get_pos_info command: */
+struct im_pos_info
+ {
+ unsigned short pos_id; /* adapter id */
+ unsigned char pos_3a; /* pos 3 (if pos 6 = 0) */
+ unsigned char pos_2; /* pos 2 */
+ unsigned char int_level; /* interrupt level IRQ 11 or 14 */
+ unsigned char pos_4a; /* pos 4 (if pos 6 = 0) */
+ unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */
+ unsigned char num_luns; /* number of supported luns per device */
+ unsigned char num_puns; /* number of supported puns */
+ unsigned char pacing_factor; /* pacing factor */
+ unsigned char num_ldns; /* number of ldns available */
+ unsigned char eoi_off; /* time EOI and interrupt inactive */
+ unsigned char max_busy; /* time between reset and busy on */
+ unsigned short cache_stat; /* ldn cachestat. Bit=1 = not cached */
+ unsigned short retry_stat; /* retry status of ldns. Bit=1=disabled */
+ unsigned char pos_4b; /* pos 4 (if pos 6 = 1) */
+ unsigned char pos_3b; /* pos 3 (if pos 6 = 1) */
+ unsigned char pos_6; /* pos 6 */
+ unsigned char pos_5; /* pos 5 */
+ unsigned short max_overlap; /* maximum overlapping requests */
+ unsigned short num_bus; /* number of SCSI-busses */
+ };
+
/*values for SCB command word */
#define IM_NO_SYNCHRONOUS 0x0040 /*flag for any command */
#define IM_NO_DISCONNECT 0x0080 /*flag for any command */
#define IM_REQUEST_SENSE_CMD 0x1c08
#define IM_READ_CAPACITY_CMD 0x1c09
#define IM_DEVICE_INQUIRY_CMD 0x1c0b
+#define IM_READ_LOGICAL_CMD 0x1c2a
#define IM_OTHER_SCSI_CMD_CMD 0x241f
/* unused, but supported, SCB commands */
#define IM_RETRY_ENABLE 0x2000
#define IM_POINTER_TO_LIST 0x1000
#define IM_SUPRESS_EXCEPTION_SHORT 0x0400
+#define IM_BYPASS_BUFFER 0x0200
#define IM_CHAIN_ON_NO_ERROR 0x0001
/*TSB (Termination Status Block) structure */
};
/*subsystem uses interrupt request level 14 */
-#define IM_IRQ 14
+#define IM_IRQ 14
+/*SCSI-2 F/W may evade to interrupt 11 */
+#define IM_IRQ_FW 11
/*--------------------------------------------------------------------*/
/*
The model 95 doesn't have a standard activity light. Instead it
- has a row of LEDs on the front. We use the last one as the activity
- indicator if we think we're on a model 95. I suspect the model id
- check will be either too narrow or too general, and some machines
- won't have an activity indicator. Oh well...
+ has a row of alphanumerial LEDs on the front. We use the last one
+ as the activity indicator if we think we're on a model 95. I suspect
+ the model id check will be either too narrow or too general, and some
+ machines won't have an activity indicator. Oh well...
The regular PS/2 disk led is turned on/off by bits 6,7 of system
control port.
#define MOD95_LED_PORT 0x108
/* system-control-register of PS/2s with diskindicator */
#define PS2_SYS_CTR 0x92
+/* activity displaying methods */
+#define LED_DISP 1
+#define LED_ADISP 2
+#define LED_ACTIVITY 4
+
+#define CMD_FAIL 255
/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED
displays. ldn is no longer displayed here, because the ldn mapping is now
interest, debugging or just for having fun. The left number gives the
host-adapter number and the right shows the accessed SCSI-ID. */
-/* use_display is set by the ibmmcascsi=display command line arg */
-static int use_display = 0;
-/* use_adisplay is set by ibmmcascsi=adisplay, which offers a higher
- * level of displayed luxus on PS/2 95 (really fancy! :-))) */
-static int use_adisplay = 0;
-
+/* display_mode is set by the ibmmcascsi= command line arg */
+static int display_mode = 0;
+/* set default adapter timeout */
+static unsigned int adapter_timeout = 45;
+/* for probing on feature-command: */
+static unsigned int global_command_error_excuse = 0;
+/* global setting by command line for adapter_speed */
+static int global_adapter_speed = 0; /* full speed by default */
+
+/* Panel / LED on, do it right for F/W addressin, too. adisplay will
+ * just ignore ids>7, as the panel has only 7 digits available */
#define PS2_DISK_LED_ON(ad,id) {\
- if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \
- outb((char)(ad+48), MOD95_LED_PORT+1); } \
- else if( use_adisplay ) { if (id<7) outb((char)(id+48), \
- MOD95_LED_PORT+1+id); outb((char)(ad+48), MOD95_LED_PORT); } \
- else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
+ if (display_mode & LED_DISP) { \
+ if (id>9) \
+ outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); \
+ else \
+ outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } \
+ else if (display_mode & LED_ADISP) { \
+ if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \
+ outb((char)(ad+48), MOD95_LED_PORT); } \
+ if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
+ outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
}
-
+/* Panel / LED off */
/* bug fixed, Dec 15, 1997, where | was replaced by & here */
#define PS2_DISK_LED_OFF() {\
- if( use_display ) { outb( ' ', MOD95_LED_PORT ); \
- outb(' ', MOD95_LED_PORT+1); } \
- if ( use_adisplay ) { outb(' ',MOD95_LED_PORT ); \
- outb(' ',MOD95_LED_PORT+1); outb(' ',MOD95_LED_PORT+2); \
- outb(' ',MOD95_LED_PORT+3); outb(' ',MOD95_LED_PORT+4); \
- outb(' ',MOD95_LED_PORT+5); outb(' ',MOD95_LED_PORT+6); \
- outb(' ',MOD95_LED_PORT+7); } \
- else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
+ if (display_mode & LED_DISP) \
+ outw(0x2020, MOD95_LED_PORT ); \
+ else if (display_mode & LED_ADISP) { \
+ outl(0x20202020,MOD95_LED_PORT); \
+ outl(0x20202020,MOD95_LED_PORT+4); } \
+ if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
+ outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
}
/*--------------------------------------------------------------------*/
char *description;
};
+/* types of different supported hardware that goes to hostdata special */
+#define IBM_SCSI2_FW 0
+#define IBM_7568_WCACHE 1
+#define IBM_EXP_UNIT 2
+#define IBM_SCSI_WCACHE 3
+#define IBM_SCSI 4
+
+/* other special flags for hostdata structure */
+#define FORCED_DETECTION 100
+#define INTEGRATED_SCSI 101
+
/* List of possible IBM-SCSI-adapters */
struct subsys_list_struct subsys_list[] =
{
- {0x8efc, "IBM Fast SCSI-2 Adapter"}, /* special = 0 */
- {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"}, /* special = 1 */
+ {0x8efc, "IBM SCSI-2 F/W Adapter"}, /* special = 0 */
+ {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */
{0x8ef8, "IBM Expansion Unit SCSI Controller"},/* special = 2 */
{0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */
{0x8efe, "IBM SCSI Adapter"}, /* special = 4 */
+};
+
+/*for /proc filesystem, only valid in older kernel releases */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27)
+struct proc_dir_entry proc_scsi_ibmmca =
+{
+ PROC_SCSI_IBMMCA, 6, "ibmmca",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2,
+ 0, 0, 0, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL
};
+#endif
/* Max number of logical devices (can be up from 0 to 14). 15 is the address
of the adapter itself. */
struct im_tsb tsb; /* SCSI command complete status block structure */
struct im_sge sge[16]; /* scatter gather list structure */
unsigned char buf[256]; /* SCSI command return data buffer */
- Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */
-
+ Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */
int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
for interpretation of the possible values */
int block_length;/* blocksize of a particular logical SCSI-device */
+ int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */
+ int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */
};
/* statistics of the driver during operations (for proc_info) */
int ldn_write_access[MAX_LOG_DEV+1]; /* total write-access on a ldn */
int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */
int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */
+ int scbs; /* short SCBs queued */
+ int long_scbs; /* long SCBs queued */
int total_accesses; /* total accesses on all ldns */
int total_interrupts; /* total interrupts (should be
same as total_accesses) */
struct ibmmca_hostdata
{
/* array of logical devices: */
- struct logical_device _ld[MAX_LOG_DEV+1];
+ struct logical_device _ld[MAX_LOG_DEV+1];
/* array to convert (pun, lun) into logical device number: */
- unsigned char _get_ldn[8][8];
+ unsigned char _get_ldn[16][8];
/*array that contains the information about the physical SCSI-devices
attached to this host adapter: */
- unsigned char _get_scsi[8][8];
+ unsigned char _get_scsi[16][8];
/* used only when checking logical devices: */
int _local_checking_phase_flag;
/* report received interrupt: */
int _last_scsi_command[MAX_LOG_DEV+1];
/* identifier of the last SCSI-command type */
int _last_scsi_type[MAX_LOG_DEV+1];
- /* Counter that points on the next reassignable ldn for dynamical
- remapping. The default value is 7, that is the first reassignable
+ /* last blockcount */
+ int _last_scsi_blockcount[MAX_LOG_DEV+1];
+ /* last locgical block address */
+ unsigned long _last_scsi_logical_block[MAX_LOG_DEV+1];
+ /* Counter that points on the next reassignable ldn for dynamical
+ remapping. The default value is 7, that is the first reassignable
number in the list at boottime: */
int _next_ldn;
/* Statistics-structure for this IBM-SCSI-host: */
struct Driver_Statistics _IBM_DS;
- /* This hostadapters pos-registers pos2 and pos3 */
- unsigned _pos2, _pos3;
+ /* This hostadapters pos-registers pos2 until pos6 */
+ unsigned _pos2, _pos3, _pos4, _pos5, _pos6;
/* assign a special variable, that contains dedicated info about the
adaptertype */
int _special;
+ /* connector size on the MCA bus */
+ int _connector_size;
+ /* synchronous SCSI transfer rate bitpattern */
+ int _adapter_speed;
};
/* macros to access host data structure */
#define subsystem_pun(hi) (hosts[(hi)]->this_id)
+#define subsystem_maxid(hi) (hosts[(hi)]->max_id)
#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
+#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)
+#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)
+#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
+#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)
+#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)
#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos2)
#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos3)
+#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos4)
+#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos5)
+#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos6)
-/* Define a arbitrary number as subsystem-marker-type. This number is, as
+/* Define a arbitrary number as subsystem-marker-type. This number is, as
described in the ANSI-SCSI-standard, not occupied by other device-types. */
#define TYPE_IBM_SCSI_ADAPTER 0x2F
#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4
#define IM_RESET_FINISHED_OK_NO_INT 5
-/* special flags for hostdata structure */
-#define FORCED_DETECTION 100
-#define INTEGRATED_SCSI 101
-
/* define undefined SCSI-command */
#define NO_SCSI 0xffff
static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };
+/* fill module-parameters only, when this define is present.
+ (that is kernel version 2.1.x) */
+#if defined(MODULE)
+static char *boot_options = NULL;
+#include <linux/module.h>
+MODULE_PARM(boot_options, "s");
+MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
+MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
+MODULE_PARM(display, "1i");
+MODULE_PARM(adisplay, "1i");
+MODULE_PARM(bypass, "1i");
+MODULE_PARM(normal, "1i");
+MODULE_PARM(ansi, "1i");
+#endif
/*counter of concurrent disk read/writes, to turn on/off disk led */
static int disk_rw_in_progress = 0;
/* spinlock handling to avoid command clash while in operation */
+#ifndef OLDKERN
spinlock_t info_lock = SPIN_LOCK_UNLOCKED;
spinlock_t proc_lock = SPIN_LOCK_UNLOCKED;
spinlock_t abort_lock = SPIN_LOCK_UNLOCKED;
spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
spinlock_t issue_lock = SPIN_LOCK_UNLOCKED;
spinlock_t intr_lock = SPIN_LOCK_UNLOCKED;
+#endif
/* host information */
static int found = 0;
-static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL };
-static unsigned int pos[8]; /* whole pos register-line */
+static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL };
+static unsigned int pos[8]; /* whole pos register-line for diagnosis */
/* Taking into account the additions, made by ZP Gu.
* This selects now the preset value from the configfile and
* offers the 'normal' commandline option to be accepted */
/******************* FUNCTIONS IN FORWARD DECLARATION ************************/
static void interrupt_handler (int, void *, struct pt_regs *);
+#ifndef OLDKERN
static void do_interrupt_handler (int, void *, struct pt_regs *);
+#endif
static void issue_cmd (int, unsigned long, unsigned char);
static void internal_done (Scsi_Cmnd * cmd);
-static void check_devices (int);
-static int immediate_assign(int, unsigned int, unsigned int, unsigned int,
+static void check_devices (int, int);
+static int immediate_assign(int, unsigned int, unsigned int, unsigned int,
unsigned int);
+static int immediate_feature(int, unsigned int, unsigned int);
#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
static int immediate_reset(int, unsigned int);
#endif
static int device_inquiry(int, int);
static int read_capacity(int, int);
+static int get_pos_info(int);
static char *ti_p(int);
static char *ti_l(int);
+static char *ibmrate(unsigned int, int);
+static int probe_display(int);
+static int probe_bus_mode(int);
static int device_exists (int, int, int *, int *);
static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *,
- int, int, char *);
-
+ int, int, int, char *);
/* local functions needed for proc_info */
static int ldn_access_load(int, int);
static int ldn_access_total_read_write(int);
static int bypass_controller = 0; /* bypass integrated SCSI-cmd set flag */
+
/*--------------------------------------------------------------------*/
/******************* LOCAL FUNCTIONS IMPLEMENTATION *************************/
+#ifndef OLDKERN
/* newer Kernels need the spinlock interrupt handler */
static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
{
spin_lock_irqsave(&io_request_lock, flags);
interrupt_handler(irq, dev_id, regs);
spin_unlock_irqrestore(&io_request_lock, flags);
- return;
+ return;
}
+#endif
static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
{
unsigned int intr_reg;
unsigned int cmd_result;
unsigned int ldn;
- static unsigned long flags;
+ unsigned long flags;
Scsi_Cmnd *cmd;
- int errorflag;
- int interror;
-
- host_index=0; /* make sure, host_index is 0, else this won't work and
- never dare to ask, what happens, if an interrupt-handler
- does not work :-((( .... */
+ int lastSCSI;
+
+ host_index = 0; /* make sure, host_index is 0 */
/* search for one adapter-response on shared interrupt */
while (hosts[host_index]
&& !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST))
host_index++;
-
+
/* return if some other device on this IRQ caused the interrupt */
if (!hosts[host_index]) return;
reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
return;
}
-
- /*get command result and logical device */
- intr_reg = inb (IM_INTR_REG(host_index));
- cmd_result = intr_reg & 0xf0;
- ldn = intr_reg & 0x0f;
-
+
/*must wait for attention reg not busy, then send EOI to subsystem */
- while (1)
+ while (1)
{
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&intr_lock, flags);
- if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+#endif
+ /* if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) */
+ if ((inb(IM_STAT_REG(host_index)) & 0xf) == (IM_CMD_REG_EMPTY | IM_INTR_REQUEST))
break;
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&intr_lock, flags);
+#endif
}
- outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+ /*get command result and logical device */
+ intr_reg = (unsigned char)(inb (IM_INTR_REG(host_index)));
+ cmd_result = intr_reg & 0xf0;
+ ldn = intr_reg & 0x0f;
+
/* get the last_scsi_command here */
- interror = last_scsi_command(host_index)[ldn];
- spin_unlock_irqrestore(&intr_lock, flags);
- errorflag = 0; /* no errors by default */
+ lastSCSI = last_scsi_command(host_index)[ldn];
+
/*these should never happen (hw fails, or a local programming bug) */
- if (cmd_result == IM_ADAPTER_HW_FAILURE)
- {
- printk("\n");
- printk("IBM MCA SCSI: ERROR - subsystem hardware failure!\n");
- printk(" Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
- last_scsi_command(host_index)[ldn],ldn,host_index);
- errorflag = 1;
- }
- if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR)
- {
- printk("\n");
- printk("IBM MCA SCSI: ERROR - software sequencing error!\n");
- printk(" Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
- last_scsi_command(host_index)[ldn],ldn,host_index);
- errorflag = 1;
- }
- if (cmd_result == IM_CMD_ERROR)
- {
- printk("\n");
- printk("IBM MCA SCSI: ERROR - command error!\n");
- printk(" Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
- last_scsi_command(host_index)[ldn],ldn,host_index);
- errorflag = 1;
+ if (!global_command_error_excuse)
+ {
+ switch (cmd_result)
+ { /* Prevent from Ooopsing on error to show the real reason */
+ case IM_ADAPTER_HW_FAILURE:
+ case IM_SOFTWARE_SEQUENCING_ERROR:
+ case IM_CMD_ERROR:
+ printk("\nIBM MCA SCSI: Fatal Subsystem ERROR!\n");
+ printk(" Last cmd=0x%x, ena=%x, len=",lastSCSI,
+ ld(host_index)[ldn].scb.enable);
+ if (ld(host_index)[ldn].cmd)
+ printk("%ld/%ld",(long)(ld(host_index)[ldn].cmd->request_bufflen),
+ (long)(ld(host_index)[ldn].scb.sys_buf_length));
+ else
+ printk("none");
+ printk(", ");
+ if (ld(host_index)[ldn].cmd)
+ printk("Blocksize=%d",ld(host_index)[ldn].scb.u2.blk.length);
+ else
+ printk("Blocksize=none");
+ printk(", host=0x%x, ldn=0x%x\n",host_index, ldn);
+ if (ld(host_index)[ldn].cmd)
+ {
+ printk("Blockcount=%d/%d\n",last_scsi_blockcount(host_index)[ldn],
+ ld(host_index)[ldn].scb.u2.blk.count);
+ printk("Logical block=%lx/%lx\n",last_scsi_logical_block(host_index)[ldn],
+ ld(host_index)[ldn].scb.u1.log_blk_adr);
+ }
+ printk("Reason given: %s\n",
+ (cmd_result==IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" :
+ (cmd_result==IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" :
+ (cmd_result==IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
+ /* if errors appear, enter this section to give detailed info */
+ printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
+ printk(" Command Type................: %x\n",
+ last_scsi_type(host_index)[ldn]);
+ printk(" Attention Register..........: %x\n",
+ inb (IM_ATTN_REG(host_index)));
+ printk(" Basic Control Register......: %x\n",
+ inb (IM_CTR_REG(host_index)));
+ printk(" Interrupt Status Register...: %x\n",
+ intr_reg);
+ printk(" Basic Status Register.......: %x\n",
+ inb (IM_STAT_REG(host_index)));
+ if ((last_scsi_type(host_index)[ldn]==IM_SCB)||
+ (last_scsi_type(host_index)[ldn]==IM_LONG_SCB))
+ {
+ printk(" SCB-Command.................: %x\n",
+ ld(host_index)[ldn].scb.command);
+ printk(" SCB-Enable..................: %x\n",
+ ld(host_index)[ldn].scb.enable);
+ printk(" SCB-logical block address...: %lx\n",
+ ld(host_index)[ldn].scb.u1.log_blk_adr);
+ printk(" SCB-system buffer address...: %lx\n",
+ ld(host_index)[ldn].scb.sys_buf_adr);
+ printk(" SCB-system buffer length....: %lx\n",
+ ld(host_index)[ldn].scb.sys_buf_length);
+ printk(" SCB-tsb address.............: %lx\n",
+ ld(host_index)[ldn].scb.tsb_adr);
+ printk(" SCB-Chain address...........: %lx\n",
+ ld(host_index)[ldn].scb.scb_chain_adr);
+ printk(" SCB-block count.............: %x\n",
+ ld(host_index)[ldn].scb.u2.blk.count);
+ printk(" SCB-block length............: %x\n",
+ ld(host_index)[ldn].scb.u2.blk.length);
+ }
+ printk(" Send this report to the maintainer.\n");
+ panic("IBM MCA SCSI: Fatal errormessage from the subsystem (0x%X,0x%X)!\n",
+ lastSCSI,cmd_result);
+ break;
+ }
}
- if (errorflag)
- { /* if errors appear, enter this section to give detailed info */
- printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
- printk(" Command Type................: %x\n",
- last_scsi_type(host_index)[ldn]);
- printk(" Attention Register..........: %x\n",
- inb (IM_ATTN_REG(host_index)));
- printk(" Basic Control Register......: %x\n",
- inb (IM_CTR_REG(host_index)));
- printk(" Interrupt Status Register...: %x\n",
- intr_reg);
- printk(" Basic Status Register.......: %x\n",
- inb (IM_STAT_REG(host_index)));
- if ((last_scsi_type(host_index)[ldn]==IM_SCB)||
- (last_scsi_type(host_index)[ldn]==IM_LONG_SCB))
+ else
+ { /* The command error handling is made silent, but we tell the
+ * calling function, that there is a reported error from the
+ * adapter. */
+ switch (cmd_result)
{
- printk(" SCB End Status Word.........: %x\n",
- ld(host_index)[ldn].tsb.end_status);
- printk(" Command Status..............: %x\n",
- ld(host_index)[ldn].tsb.cmd_status);
- printk(" Device Status...............: %x\n",
- ld(host_index)[ldn].tsb.dev_status);
- printk(" Command Error...............: %x\n",
- ld(host_index)[ldn].tsb.cmd_error);
- printk(" Device Error................: %x\n",
- ld(host_index)[ldn].tsb.dev_error);
- printk(" Last SCB Address (LSW)......: %x\n",
- ld(host_index)[ldn].tsb.low_of_last_scb_adr);
- printk(" Last SCB Address (MSW)......: %x\n",
- ld(host_index)[ldn].tsb.high_of_last_scb_adr);
+ case IM_ADAPTER_HW_FAILURE:
+ case IM_SOFTWARE_SEQUENCING_ERROR:
+ case IM_CMD_ERROR:
+ global_command_error_excuse = CMD_FAIL;
+ break;
+ default:
+ global_command_error_excuse = 0;
+ break;
}
- printk(" Send report to the maintainer.\n");
- panic("IBM MCA SCSI: Fatal errormessage from the subsystem!\n");
- }
-
+ }
+
/* if no panic appeared, increase the interrupt-counter */
IBM_DS(host_index).total_interrupts++;
-
+
/*only for local checking phase */
if (local_checking_phase_flag(host_index))
{
got_interrupt(host_index) = 1;
reset_status(host_index) = IM_RESET_FINISHED_OK;
last_scsi_command(host_index)[ldn] = NO_SCSI;
+
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
return;
- }
+ }
/*handling of commands coming from upper level of scsi driver */
else
{
}
stat_result(host_index) = cmd_result;
last_scsi_command(host_index)[ldn] = NO_SCSI;
+ last_scsi_type(host_index)[ldn] = 0;
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
return;
}
else if (last_scsi_command(host_index)[ldn] == IM_ABORT_IMM_CMD)
{ /* react on SCSI abort command */
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
-#endif
+#endif
disk_rw_in_progress = 0;
PS2_DISK_LED_OFF();
cmd = ld(host_index)[ldn].cmd;
+ ld(host_index)[ldn].cmd = NULL;
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
cmd->result = DID_NO_CONNECT << 16;
else
cmd->result = DID_ABORT << 16;
stat_result(host_index) = cmd_result;
last_scsi_command(host_index)[ldn] = NO_SCSI;
+ last_scsi_type(host_index)[ldn] = 0;
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
if (cmd->scsi_done)
- (cmd->scsi_done) (cmd); /* should be the internal_done */
+ (cmd->scsi_done)(cmd); /* should be the internal_done */
return;
}
else
reset_status(host_index) = IM_RESET_FINISHED_OK;
stat_result(host_index) = cmd_result;
last_scsi_command(host_index)[ldn] = NO_SCSI;
+
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
return;
- }
+ }
}
last_scsi_command(host_index)[ldn] = NO_SCSI;
+ last_scsi_type(host_index)[ldn] = 0;
cmd = ld(host_index)[ldn].cmd;
+ ld(host_index)[ldn].cmd = NULL;
#ifdef IM_DEBUG_TIMEOUT
if (cmd)
{
- if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN))
+ if ((cmd->target == TIMEOUT_PUN)&&
+ (cmd->lun == TIMEOUT_LUN))
{
printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n",
cmd->target, cmd->lun);
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
return;
}
}
#endif
/*if no command structure, just return, else clear cmd */
if (!cmd)
- return;
- ld(host_index)[ldn].cmd = NULL;
-
+ {
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
+ return;
+ }
+
#ifdef IM_DEBUG_INT
- printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n",
- cmd->cmnd[0], intr_reg,
- ld(host_index)[ldn].tsb.dev_status,
+ printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n",
+ cmd->cmnd[0], intr_reg,
+ ld(host_index)[ldn].tsb.dev_status,
ld(host_index)[ldn].tsb.cmd_status,
- ld(host_index)[ldn].tsb.dev_error,
+ ld(host_index)[ldn].tsb.dev_error,
ld(host_index)[ldn].tsb.cmd_error);
#endif
-
+
/*if this is end of media read/write, may turn off PS/2 disk led */
if ((ld(host_index)[ldn].device_type!=TYPE_NO_LUN)&&
(ld(host_index)[ldn].device_type!=TYPE_NO_DEVICE))
}
/* IBM describes the status-mask to be 0x1e, but this is not conform
- * with SCSI-defintion, I suppose, it is a printing error in the
- * technical reference and assume as mask 0x3e. (ML) */
- cmd->result = (ld(host_index)[ldn].tsb.dev_status & 0x3e);
- /* write device status into cmd->result, and call done function */
+ * with SCSI-defintion, I suppose, the reason for it is that IBM
+ * adapters do not support CMD_TERMINATED, TASK_SET_FULL and
+ * ACA_ACTIVE as returning statusbyte information. (ML) */
if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
- IBM_DS(host_index).total_errors++;
- if (interror == NO_SCSI) /* unexpected interrupt :-( */
- cmd->result |= DID_BAD_INTR << 16;
+ {
+ cmd->result = (unsigned char)(ld(host_index)[ldn].tsb.dev_status & 0x1e);
+ IBM_DS(host_index).total_errors++;
+ }
else
+ cmd->result = 0;
+ /* write device status into cmd->result, and call done function */
+ if (lastSCSI == NO_SCSI) /* unexpected interrupt :-( */
+ cmd->result |= DID_BAD_INTR << 16;
+ else /* things went right :-) */
cmd->result |= DID_OK << 16;
- (cmd->scsi_done) (cmd);
- }
- if (interror == NO_SCSI)
+ outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&intr_lock, flags);
+#endif
+ /* This is for Kernel 2.2.x. Something weired happens here.
+ * Between the command got queued and the interrupt is released,
+ * the flags sometimes contain different values, which must
+ * be a strange thing. E.g. it appears when cold-booting with a
+ * tape drive at id0. */
+ cmd->flags &= 0x3f;
+ if (cmd->scsi_done)
+ (cmd->scsi_done)(cmd);
+ }
+ if (lastSCSI == NO_SCSI)
printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
return;
}
/*--------------------------------------------------------------------*/
-static void issue_cmd (int host_index, unsigned long cmd_reg,
+static void issue_cmd (int host_index, unsigned long cmd_reg,
unsigned char attn_reg)
{
static unsigned long flags;
- /* must wait for attention reg not busy */
+ /* must wait for attention reg not busy */
while (1)
{
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&issue_lock, flags);
- if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+#endif
+ if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
break;
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&issue_lock, flags);
+#endif
}
/*write registers and enable system interrupts */
outl (cmd_reg, IM_CMD_REG(host_index));
outb (attn_reg, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&issue_lock, flags);
+#endif
+ return;
}
/*--------------------------------------------------------------------*/
static void internal_done (Scsi_Cmnd * cmd)
{
cmd->SCp.Status++;
+ return;
}
/*--------------------------------------------------------------------*/
/* SCSI-SCB-command for device_inquiry */
static int device_inquiry(int host_index, int ldn)
-{
+{
int retries;
- Scsi_Cmnd *cmd;
+ Scsi_Cmnd cmd;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
-
+
scb = &(ld(host_index)[ldn].scb);
tsb = &(ld(host_index)[ldn].tsb);
buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
ld(host_index)[ldn].tsb.dev_status = 0; /* prepare stusblock */
- cmd = kmalloc(sizeof(*cmd), GFP_KERNEL|GFP_DMA);
- if(cmd==NULL)
- {
- printk(KERN_ERR "ibmmca: out of memory for inquiry.\n");
- return 0;
- }
if (bypass_controller)
{ /* fill the commonly known field for device-inquiry SCSI cmnd */
- cmd->cmd_len = 6;
- memset (&(cmd->cmnd), 0x0, sizeof(char) * cmd->cmd_len);
- cmd->cmnd[0] = INQUIRY; /* device inquiry */
- cmd->cmnd[4] = 0xff; /* return buffer size = 255 */
- }
+ cmd.cmd_len = 6;
+ memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len);
+ cmd.cmnd[0] = INQUIRY; /* device inquiry */
+ cmd.cmnd[4] = 0xff; /* return buffer size = 255 */
+ }
for (retries = 0; retries < 3; retries++)
{
if (bypass_controller)
{ /* bypass the hardware integrated command set */
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
- scb->u1.scsi_cmd_length = cmd->cmd_len;
- memcpy (scb->u2.scsi_command, &(cmd->cmnd), cmd->cmd_len);
+ scb->command = IM_OTHER_SCSI_CMD_CMD | IM_NO_DISCONNECT;
+ scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+ scb->u1.scsi_cmd_length = cmd.cmd_len;
+ memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
last_scsi_command(host_index)[ldn] = INQUIRY;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
}
else
{
/*fill scb with inquiry command */
- scb->command = IM_DEVICE_INQUIRY_CMD;
- scb->enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+ scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
+ scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_type(host_index)[ldn] = IM_SCB;
}
scb->sys_buf_adr = virt_to_bus(buf);
scb->sys_buf_length = 0xff; /* maximum bufferlength gives max info */
scb->tsb_adr = virt_to_bus(tsb);
-
+
/*issue scb to passed ldn, and busy wait for interrupt */
got_interrupt(host_index) = 0;
- issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+ if ((scb->command & IM_OTHER_SCSI_CMD_CMD) == IM_OTHER_SCSI_CMD_CMD)
+ issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn);
+ else
+ issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
while (!got_interrupt(host_index))
barrier ();
-
+
/*if command succesful, break */
if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
(stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
- {
- return 1;
- }
+ return 1;
}
- kfree(cmd);
-
+
/*if all three retries failed, return "no device at this ldn" */
if (retries >= 3)
return 0;
struct im_scb *scb;
struct im_tsb *tsb;
unsigned char *buf;
-
+
scb = &(ld(host_index)[ldn].scb);
tsb = &(ld(host_index)[ldn].tsb);
buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
ld(host_index)[ldn].tsb.dev_status = 0;
-
+
if (bypass_controller)
{ /* read capacity in commonly known default SCSI-format */
cmd.cmd_len = 10;
memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len);
cmd.cmnd[0] = READ_CAPACITY; /* read capacity */
- }
+ }
for (retries = 0; retries < 3; retries++)
{
/*fill scb with read capacity command */
if (bypass_controller)
{ /* bypass the SCSI-command */
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL;
+ scb->command = IM_OTHER_SCSI_CMD_CMD;
+ scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd.cmd_len;
memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
last_scsi_command(host_index)[ldn] = READ_CAPACITY;
else
{
scb->command = IM_READ_CAPACITY_CMD;
- scb->enable = IM_READ_CONTROL;
+ scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
- last_scsi_type(host_index)[ldn] = IM_SCB;
+ last_scsi_type(host_index)[ldn] = IM_SCB;
}
scb->sys_buf_adr = virt_to_bus(buf);
scb->sys_buf_length = 8;
scb->tsb_adr = virt_to_bus(tsb);
-
+
/*issue scb to passed ldn, and busy wait for interrupt */
got_interrupt(host_index) = 0;
- issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+ if ((scb->command & IM_OTHER_SCSI_CMD_CMD) == IM_OTHER_SCSI_CMD_CMD)
+ issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn);
+ else
+ issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
while (!got_interrupt(host_index))
barrier ();
-
- /*if got capacity, get block length and return one device found */
+
+ /*if got capacity, get block length and return one device found */
if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
(stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
- {
- return 1;
- }
+ return 1;
}
/*if all three retries failed, return "no device at this ldn" */
if (retries >= 3)
return 1;
}
+static int get_pos_info(int host_index)
+{
+ int retries;
+ struct im_scb *scb;
+ struct im_tsb *tsb;
+ unsigned char *buf;
+
+ scb = &(ld(host_index)[MAX_LOG_DEV].scb);
+ tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
+ buf = (unsigned char *)(&(ld(host_index)[MAX_LOG_DEV].buf));
+ ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
+
+ for (retries = 0; retries < 3; retries++)
+ {
+ /*fill scb with get_pos_info command */
+ scb->command = IM_GET_POS_INFO_CMD;
+ scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER | IM_SUPRESS_EXCEPTION_SHORT;
+ last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
+ last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;
+
+ scb->sys_buf_adr = virt_to_bus(buf);
+ if (special(host_index)==IBM_SCSI2_FW)
+ scb->sys_buf_length = 256; /* get all info from F/W adapter */
+ else
+ scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */
+
+ scb->tsb_adr = virt_to_bus(tsb);
+
+ /*issue scb to ldn=15, and busy wait for interrupt */
+ got_interrupt(host_index) = 0;
+ issue_cmd (host_index, virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
+ while (!got_interrupt(host_index))
+ barrier ();
+
+ /*if got POS-stuff, get block length and return one device found */
+ if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
+ (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+ return 1;
+ }
+ /* if all three retries failed, return "no device at this ldn" */
+ if (retries >= 3)
+ return 0;
+ else
+ return 1;
+}
+
/* SCSI-immediate-command for assign. This functions maps/unmaps specific
ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(int host_index, unsigned int pun,
- unsigned int lun, unsigned int ldn,
+static int immediate_assign(int host_index, unsigned int pun,
+ unsigned int lun, unsigned int ldn,
unsigned int operation)
{
int retries;
unsigned long imm_command;
-
+
for (retries=0; retries<3; retries ++)
{
- imm_command = inl(IM_CMD_REG(host_index));
- imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */
- imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD);
- imm_command |= (unsigned long)((lun & 7) << 24);
- imm_command |= (unsigned long)((operation & 1) << 23);
- imm_command |= (unsigned long)((pun & 7) << 20);
- imm_command |= (unsigned long)((ldn & 15) << 16);
-
- last_scsi_command(host_index)[0xf] = IM_ASSIGN_IMM_CMD;
- last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+ /* select mutation level of the SCSI-adapter */
+ switch (special(host_index))
+ {
+ case IBM_SCSI2_FW:
+ imm_command = (unsigned long)(IM_ASSIGN_IMM_CMD);
+ imm_command |= (unsigned long)((lun & 7) << 24);
+ imm_command |= (unsigned long)((operation & 1) << 23);
+ imm_command |= (unsigned long)((pun & 7)<< 20)|((pun & 8)<< 24);
+ imm_command |= (unsigned long)((ldn & 15) << 16);
+ break;
+ default:
+ imm_command = inl(IM_CMD_REG(host_index));
+ imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */
+ imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD);
+ imm_command |= (unsigned long)((lun & 7) << 24);
+ imm_command |= (unsigned long)((operation & 1) << 23);
+ imm_command |= (unsigned long)((pun & 7) << 20);
+ imm_command |= (unsigned long)((ldn & 15) << 16);
+ break;
+ }
+ last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
+ last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
got_interrupt(host_index) = 0;
- issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | 0xf);
+ issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV);
while (!got_interrupt(host_index))
barrier ();
-
+
/*if command succesful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ return 1;
+ }
+ if (retries >= 3)
+ return 0;
+ else
+ return 1;
+}
+
+static int immediate_feature(int host_index, unsigned int speed,
+ unsigned int timeout)
+{
+ int retries;
+ unsigned long imm_command;
+
+ for (retries=0; retries<3; retries ++)
+ {
+ /* select mutation level of the SCSI-adapter */
+ switch (special(host_index))
{
- return 1;
+ default:
+ imm_command = IM_FEATURE_CTR_IMM_CMD;
+ imm_command |= (unsigned long)((speed & 0x7) << 29);
+ imm_command |= (unsigned long)((timeout & 0x1fff) << 16);
+ break;
+ }
+ last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
+ last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
+ got_interrupt(host_index) = 0;
+ /* we need to run into command errors in order to probe for the
+ * right speed! */
+ global_command_error_excuse = 1;
+ issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | MAX_LOG_DEV);
+ while (!got_interrupt(host_index))
+ barrier ();
+ if (global_command_error_excuse == CMD_FAIL)
+ {
+ global_command_error_excuse = 0;
+ return 2;
}
+ else
+ global_command_error_excuse = 0;
+
+ /*if command succesful, break */
+ if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+ return 1;
}
-
- if (retries >= 3)
+
+ if (retries >= 3)
return 0;
else
return 1;
int retries;
int ticks;
unsigned long imm_command;
-
+
for (retries=0; retries<3; retries ++)
{
imm_command = inl(IM_CMD_REG(host_index));
last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
got_interrupt(host_index) = 0;
- reset_status(host_index) = IM_RESET_IN_PROGRESS;
+ reset_status(host_index) = IM_RESET_IN_PROGRESS;
issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn);
- ticks = IM_RESET_DELAY*HZ;
- while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks)
+ ticks = IM_RESET_DELAY*HZ;
+ while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks)
{
mdelay(1+999/HZ);
barrier();
}
/* if reset did not complete, just claim */
- if (!ticks)
+ if (!ticks)
{
printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
IM_RESET_DELAY);
- reset_status(host_index) = IM_RESET_FINISHED_OK;
+ reset_status(host_index) = IM_RESET_FINISHED_OK;
/* did not work, finish */
return 1;
}
/*if command succesful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
- {
- return 1;
- }
+ return 1;
}
-
- if (retries >= 3)
+
+ if (retries >= 3)
return 0;
else
return 1;
{
const char hex[16] = "0123456789abcdef";
static char answer[2];
-
+
answer[1] = (char)(0x0);
if (value<=MAX_LOG_DEV)
answer[0] = hex[value];
else
answer[0] = '-';
-
+
return (char *)&answer;
}
-/*
+/* transfers bitpattern of the feature command to values in MHz */
+static char *ibmrate(unsigned int speed, int adaptertype)
+{
+ int i;
+ i=adaptertype;
+ switch (speed)
+ {
+ case 0: if (i) return "5.00"; else return "10.00"; break;
+ case 1: if (i) return "4.00"; else return "8.00"; break;
+ case 2: if (i) return "3.33"; else return "6.66"; break;
+ case 3: if (i) return "2.86"; else return "5.00"; break;
+ case 4: if (i) return "2.50"; else return "4.00"; break;
+ case 5: if (i) return "2.22"; else return "3.10"; break;
+ case 6: if (i) return "2.00"; else return "2.50"; break;
+ case 7: if (i) return "1.82"; else return "2.00"; break;
+ }
+ return "---";
+}
+
+static int probe_display(int what)
+{
+ static int rotator = 0;
+ const char rotor[] = "|/-\\";
+
+ if (!(display_mode & LED_DISP))
+ return 0;
+ if (!what)
+ {
+ outl(0x20202020,MOD95_LED_PORT);
+ outl(0x20202020,MOD95_LED_PORT+4);
+ }
+ else
+ {
+ outb('S',MOD95_LED_PORT+7);
+ outb('C',MOD95_LED_PORT+6);
+ outb('S',MOD95_LED_PORT+5);
+ outb('I',MOD95_LED_PORT+4);
+ outb('i',MOD95_LED_PORT+3);
+ outb('n',MOD95_LED_PORT+2);
+ outb('i',MOD95_LED_PORT+1);
+ outb((char)(rotor[rotator]),MOD95_LED_PORT);
+ rotator++;
+ if (rotator>3)
+ rotator=0;
+ }
+ return 0;
+}
+
+static int probe_bus_mode(int host_index)
+{
+ struct im_pos_info *info;
+ int num_bus = 0;
+ int ldn;
+
+ info = (struct im_pos_info *)(&(ld(host_index)[MAX_LOG_DEV].buf));
+
+ if (get_pos_info(host_index))
+ {
+ if (info->connector_size & 0xf000)
+ subsystem_connector_size(host_index)=16;
+ else
+ subsystem_connector_size(host_index)=32;
+ num_bus |= (info->pos_4b & 8) >> 3;
+ for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+ {
+ if ((special(host_index)==IBM_SCSI_WCACHE)||
+ (special(host_index)==IBM_7568_WCACHE))
+ {
+ if (!((info->cache_stat >> ldn) & 1))
+ ld(host_index)[ldn].cache_flag = 0;
+ }
+ if (!((info->retry_stat >> ldn) & 1))
+ ld(host_index)[ldn].retry_flag = 0;
+ }
+#ifdef IM_DEBUG_PROBE
+ printk("IBM MCA SCSI: SCSI-Cache bits: ");
+ for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+ {
+ printk("%d",ld(host_index)[ldn].cache_flag);
+ }
+ printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
+ for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+ {
+ printk("%d",ld(host_index)[ldn].retry_flag);
+ }
+ printk("\n");
+#endif
+ }
+ return num_bus;
+}
+
+/*
The following routine probes the SCSI-devices in four steps:
1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter.
2. ldn 0 is used to go through all possible combinations of pun,lun and
The assignment of ALL ldns avoids dynamical remapping by the adapter
itself.
*/
-static void check_devices (int host_index)
+static void check_devices (int host_index, int adaptertype)
{
int id, lun, ldn, ticks;
int count_devices; /* local counter for connected device */
-
+ int max_pun;
+ int num_bus;
+ int speedrun; /* local adapter_speed check variable */
+
/* assign default values to certain variables */
-
ticks = 0;
count_devices = 0;
IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
+
+ /* initialize the very important driver-informational arrays/structs */
+ memset (ld(host_index), 0,
+ sizeof(ld(host_index)));
for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
{
last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
last_scsi_type(host_index)[ldn] = 0;
+ ld(host_index)[ldn].cache_flag = 1;
+ ld(host_index)[ldn].retry_flag = 1;
}
-
- /* initialize the very important driver-informational arrays/structs */
- memset (ld(host_index), 0,
- sizeof(ld(host_index)));
- memset (get_ldn(host_index), TYPE_NO_DEVICE,
+ memset (get_ldn(host_index), TYPE_NO_DEVICE,
sizeof(get_ldn(host_index))); /* this is essential ! */
memset (get_scsi(host_index), TYPE_NO_DEVICE,
sizeof(get_scsi(host_index))); /* this is essential ! */
-
+
for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/
{
get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
luns. */
}
+ probe_display(0); /* Supercool display usage during SCSI-probing. */
+ /* This makes sense, when booting without any */
+ /* monitor connected on model XX95. */
+
/* STEP 1: */
+ adapter_speed(host_index) = global_adapter_speed;
+ speedrun = adapter_speed(host_index);
+ while (immediate_feature(host_index,speedrun,adapter_timeout)==2)
+ {
+ probe_display(1);
+ if (speedrun==7)
+ panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
+ speedrun++;
+ if (speedrun>7)
+ speedrun=7;
+ }
+ adapter_speed(host_index) = speedrun;
+ /* Get detailed information about the current adapter, necessary for
+ * device operations: */
+ num_bus=probe_bus_mode(host_index);
+
+ /* num_bus contains only valid data for the F/W adapter! */
+ if (adaptertype==IBM_SCSI2_FW) /* F/W SCSI adapter: */
+ {
+ /* F/W adapter PUN-space extension evaluation: */
+ if (num_bus)
+ {
+ printk("IBM MCA SCSI: Seperate bus mode (wide-addressing enabled)\n");
+ subsystem_maxid(host_index) = 16;
+ }
+ else
+ {
+ printk("IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
+ subsystem_maxid(host_index) = 8;
+ }
+ printk("IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n",
+ ibmrate(speedrun,adaptertype));
+ }
+ else /* all other IBM SCSI adapters: */
+ printk("IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n",
+ ibmrate(speedrun,adaptertype));
+
+ /* assign correct PUN device space */
+ max_pun = subsystem_maxid(host_index);
+
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index);
#endif
printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
for (ldn=0; ldn<MAX_LOG_DEV; ldn++)
{
+ probe_display(1);
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
}
lun = 0; /* default lun is 0 */
-
+
/* STEP 2: */
- printk("\nIBM MCA SCSI: Probing SCSI-devices.");
- for (id=0; id<8; id++)
+ printk("\nIBM MCA SCSI: Probing SCSI-devices");
+#ifndef IM_DEBUG_PROBE
+ printk(" (this can take up to 2 minutes)");
+#endif
+ printk(".");
+
+ for (id=0; id<max_pun ; id++)
#ifdef CONFIG_SCSI_MULTI_LUN
for (lun=0; lun<8; lun++)
#endif
{
+ probe_display(1);
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
immediate_assign(host_index,id,lun,PROBE_LDN,REMOVE_LDN);
}
}
-
- /* STEP 3: */
+
+ /* STEP 3: */
printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
-
+
ldn = 0;
lun = 0;
-
-#ifdef CONFIG_SCSI_MULTI_LUN
+
+#ifdef CONFIG_SCSI_MULTI_LUN
for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
#endif
- for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
+ for (id=0; id<max_pun && ldn<MAX_LOG_DEV; id++)
{
+ probe_display(1);
#ifdef IM_DEBUG_PROBE
printk(".");
#endif
if (id != subsystem_pun(host_index))
{
- if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN &&
+ if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN &&
get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE)
{
- /* Only map if accepted type. Always enter for
+ /* Only map if accepted type. Always enter for
lun == 0 to get no gaps into ldn-mapping for ldn<7. */
immediate_assign(host_index,id,lun,ldn,SET_LDN);
get_ldn(host_index)[id][lun]=ldn; /* map ldn */
- if (device_exists (host_index, ldn,
+ if (device_exists (host_index, ldn,
&ld(host_index)[ldn].block_length,
&ld(host_index)[ldn].device_type))
{
get_ldn(host_index)[id][lun]=ldn; /* map ldn */
ldn++;
}
- }
+ }
}
-
+
/* STEP 4: */
-
+
/* map remaining ldns to non-existing devices */
for (lun=1; lun<8 && ldn<MAX_LOG_DEV; lun++)
- for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
+ for (id=0; id<max_pun && ldn<MAX_LOG_DEV; id++)
{
if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN ||
get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE)
{
+ probe_display(1);
/* Map remaining ldns only to NON-existing pun,lun
combinations to make sure an inquiry will fail.
For MULTI_LUN, it is needed to avoid adapter autonome
get_ldn(host_index)[id][lun]=ldn;
ldn++;
}
- }
-
+ }
+
printk("\n");
if (ibm_ansi_order)
printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
else
printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
-
+
#ifdef IM_DEBUG_PROBE
/* Show the physical and logical mapping during boot. */
printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
printk(" Physical SCSI-Device Map Logical SCSI-Device Map\n");
printk("ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
- for (id=0; id<8; id++)
+ for (id=0; id<max_pun; id++)
{
printk("%2d ",id);
for (lun=0; lun<8; lun++)
printk("\n");
}
#endif
-
+
/* assign total number of found SCSI-devices to the statistics struct */
IBM_DS(host_index).total_scsi_devices = count_devices;
-
+
/* decide for output in /proc-filesystem, if the configuration of
SCSI-devices makes dynamical reassignment of devices necessary */
- if (count_devices>=MAX_LOG_DEV)
+ if (count_devices>=MAX_LOG_DEV)
IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */
- else
+ else
IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */
-
+
/* If no SCSI-devices are assigned, return 1 in order to cause message. */
if (ldn == 0)
printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
-
+
/* reset the counters for statistics on the current adapter */
+ IBM_DS(host_index).scbs = 0;
+ IBM_DS(host_index).long_scbs = 0;
IBM_DS(host_index).total_accesses = 0;
IBM_DS(host_index).total_interrupts = 0;
IBM_DS(host_index).dynamical_assignments = 0;
- memset (IBM_DS(host_index).ldn_access, 0x0,
+ memset (IBM_DS(host_index).ldn_access, 0x0,
sizeof (IBM_DS(host_index).ldn_access));
- memset (IBM_DS(host_index).ldn_read_access, 0x0,
+ memset (IBM_DS(host_index).ldn_read_access, 0x0,
sizeof (IBM_DS(host_index).ldn_read_access));
- memset (IBM_DS(host_index).ldn_write_access, 0x0,
+ memset (IBM_DS(host_index).ldn_write_access, 0x0,
sizeof (IBM_DS(host_index).ldn_write_access));
- memset (IBM_DS(host_index).ldn_inquiry_access, 0x0,
+ memset (IBM_DS(host_index).ldn_inquiry_access, 0x0,
sizeof (IBM_DS(host_index).ldn_inquiry_access));
- memset (IBM_DS(host_index).ldn_modeselect_access, 0x0,
+ memset (IBM_DS(host_index).ldn_modeselect_access, 0x0,
sizeof (IBM_DS(host_index).ldn_modeselect_access));
- memset (IBM_DS(host_index).ldn_assignments, 0x0,
+ memset (IBM_DS(host_index).ldn_assignments, 0x0,
sizeof (IBM_DS(host_index).ldn_assignments));
-
+ probe_display(0);
return;
}
/*--------------------------------------------------------------------*/
-static int device_exists (int host_index, int ldn, int *block_length,
+static int device_exists (int host_index, int ldn, int *block_length,
int *device_type)
{
unsigned char *buf;
-
+
/* if no valid device found, return immediately with 0 */
if (!(device_inquiry(host_index, ldn)))
return 0;
-
+
buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
/*if device is CD_ROM, assume block size 2048 and return */
*block_length = 2048; /* (standard blocksize for yellow-/red-book) */
return 1;
}
-
- if (*buf == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM
+
+ if (*buf == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM
therefore, the block_length is also 2048. */
{
*device_type = TYPE_WORM;
*block_length = 2048;
return 1;
}
-
+
/* if device is disk, use "read capacity" to find its block size */
if (*buf == TYPE_DISK)
{
*device_type = TYPE_DISK;
if (read_capacity( host_index, ldn))
{
- *block_length = *(buf+7) + (*(buf+6) << 8) +
+ *block_length = *(buf+7) + (*(buf+6) << 8) +
(*(buf+5) << 16) + (*(buf+4) << 24);
return 1;
}
else
return 0;
}
-
+
/* if this is a magneto-optical drive, treat it like a harddisk */
if (*buf == TYPE_MOD)
{
*device_type = TYPE_MOD;
if (read_capacity( host_index, ldn))
{
- *block_length = *(buf+7) + (*(buf+6) << 8) +
+ *block_length = *(buf+7) + (*(buf+6) << 8) +
(*(buf+5) << 16) + (*(buf+4) << 24);
return 1;
}
else
return 0;
- }
-
+ }
+
if (*buf == TYPE_TAPE) /* TAPE-device found */
{
*device_type = TYPE_TAPE;
*block_length = 0; /* not in use (setting by mt and mtst in op.) */
- return 1;
+ return 1;
}
-
+
if (*buf == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/
{
*device_type = TYPE_PROCESSOR;
*block_length = 0; /* they set their stuff on drivers */
return 1;
}
-
+
if (*buf == TYPE_SCANNER) /* other SCSI-scanners */
{
*device_type = TYPE_SCANNER;
*block_length = 0; /* they set their stuff on drivers */
return 1;
}
-
+
if (*buf == TYPE_MEDIUM_CHANGER) /* Medium-Changer */
{
*device_type = TYPE_MEDIUM_CHANGER;
changer device. */
return 1;
}
-
+
/* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are
- ignored! MO-drives are now supported and treated as harddisk. */
+ ignored! MO-drives are now supported and treated as harddisk. */
return 0;
}
/*--------------------------------------------------------------------*/
-
+
#ifdef CONFIG_SCSI_IBMMCA
-void ibmmca_scsi_setup (char *str, int *ints)
+void internal_ibmmca_scsi_setup (char *str, int *ints)
{
int i, j, io_base, id_base;
char *token;
-
+
io_base = 0;
id_base = 0;
-
+
if (str)
{
token = strtok(str,",");
j = 0;
while (token)
{
+ if (!strcmp(token,"activity"))
+ display_mode |= LED_ACTIVITY;
if (!strcmp(token,"display"))
- {
- use_display = 1;
- }
+ display_mode |= LED_DISP;
if (!strcmp(token,"adisplay"))
- {
- use_adisplay = 1;
- }
+ display_mode |= LED_ADISP;
if (!strcmp(token,"bypass"))
- {
- bypass_controller = 1;
- }
+ bypass_controller = 1;
if (!strcmp(token,"normal"))
- {
- ibm_ansi_order = 0;
- }
+ ibm_ansi_order = 0;
if (!strcmp(token,"ansi"))
- {
- ibm_ansi_order = 1;
- }
+ ibm_ansi_order = 1;
+ if (!strcmp(token,"fast"))
+ global_adapter_speed = 0;
+ if (!strcmp(token,"medium"))
+ global_adapter_speed = 4;
+ if (!strcmp(token,"slow"))
+ global_adapter_speed = 7;
if ( (*token == '-') || (isdigit(*token)) )
{
if (!(j%2) && (io_base < IM_MAX_HOSTS))
- {
- io_port[io_base++] = simple_strtoul(token,NULL,0);
- }
+ io_port[io_base++] = simple_strtoul(token,NULL,0);
if ((j%2) && (id_base < IM_MAX_HOSTS))
- {
- scsi_id[id_base++] = simple_strtoul(token,NULL,0);
- }
+ scsi_id[id_base++] = simple_strtoul(token,NULL,0);
j++;
}
token = strtok(NULL,",");
}
else if (ints)
{
- for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++)
+ for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++)
{
io_port[i] = ints[2*i+2];
scsi_id[i] = ints[2*i+2];
static int ibmmca_getinfo (char *buf, int slot, void *dev)
{
struct Scsi_Host *shpnt;
- int len, special;
+ int len, speciale,connectore;
unsigned int pos2, pos3;
static unsigned long flags;
-
+
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&info_lock, flags);
-
+#endif
+
shpnt = dev; /* assign host-structure to local pointer */
len = 0; /* set filled text-buffer index to 0 */
/* get the _special contents of the hostdata structure */
- special = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
+ speciale = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
+ connectore = ((struct ibmmca_hostdata *)shpnt->hostdata)->_connector_size;
pos2 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2;
pos3 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3;
-
- if (special == FORCED_DETECTION) /* forced detection */
+
+ if (speciale == FORCED_DETECTION) /* forced detection */
{
- len += sprintf (buf + len, "Adapter cathegory: forced detected\n");
+ len += sprintf (buf + len, "Adapter category: forced detected\n");
len += sprintf(buf + len, "***************************************\n");
len += sprintf(buf + len, "*** Forced detected SCSI Adapter ***\n");
len += sprintf(buf + len, "*** No chip-information available ***\n");
len += sprintf(buf + len, "***************************************\n");
}
- else if (special == INTEGRATED_SCSI)
+ else if (speciale == INTEGRATED_SCSI)
{ /* if the integrated subsystem has been found automatically: */
len += sprintf (buf + len, "Adapter category: integrated\n");
len += sprintf (buf + len, "Chip revision level: %d\n",
len += sprintf (buf + len, "8 kByte NVRAM status: %s\n",
(pos2 & 2) ? "locked" : "accessible");
}
- else if ((special>=0)&&
- (special<(sizeof(subsys_list)/sizeof(struct subsys_list_struct))))
- { /* if the subsystem is a slot adapter */
+ else if ((speciale>=0)&&
+ (speciale<(sizeof(subsys_list)/sizeof(struct subsys_list_struct))))
+ { /* if the subsystem is a slot adapter */
len += sprintf (buf + len, "Adapter category: slot-card\n");
- len += sprintf (buf + len, "Chip revision level: %d\n",
- ((pos2 & 0xf0) >> 4));
+ len += sprintf (buf + len, "ROM Segment Address: ");
+ if ((pos2 & 0xf0) == 0xf0)
+ len += sprintf (buf + len, "off\n");
+ else
+ len += sprintf (buf + len, "0x%x\n",
+ ((pos2 & 0xf0) << 13) + 0xc0000);
len += sprintf (buf + len, "Chip status: %s\n",
(pos2 & 1) ? "enabled" : "disabled");
- len += sprintf (buf + len, "Port offset: 0x%x\n",
+ len += sprintf (buf + len, "Adapter I/O Offset: 0x%x\n",
((pos2 & 0x0e) << 2));
}
else
}
/* common subsystem information to write to the slotn file */
len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
- len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x",
+ len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x\n",
(unsigned int)(shpnt->io_port),
(unsigned int)(shpnt->io_port+7));
- /* Now make sure, the bufferlength is divisible by 4 to avoid
+ len += sprintf (buf + len, "MCA-slot size: %d bits",connectore);
+ /* Now make sure, the bufferlength is devidable by 4 to avoid
* paging problems of the buffer. */
while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) )
{
}
len += sprintf (buf + len, "\n");
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&info_lock, flags);
+#endif
return len;
}
-
+
int ibmmca_detect (Scsi_Host_Template * scsi_template)
{
struct Scsi_Host *shpnt;
int port, id, i, j, list_size, slot;
-
+ int devices_on_irq_11 = 0;
+ int devices_on_irq_14 = 0;
+ int IRQ14_registered = 0;
+ int IRQ11_registered = 0;
+
found = 0; /* make absolutely sure, that found is set to 0 */
+ /* First of all, print the version number of the driver. This is
+ * important to allow better user bugreports in case of already
+ * having problems with the MCA_bus probing. */
+ printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
/* if this is not MCA machine, return "nothing found" */
if (!MCA_bus)
{
- printk("IBM MCA SCSI: No Microchannel-bus support present -> Aborting.\n");
+ printk("IBM MCA SCSI: No Microchannel-bus present --> Aborting.\n");
+ printk(" This machine does not have any IBM MCA-bus\n");
+ printk(" or the MCA-Kernel-support is not enabled!\n");
return 0;
}
- else
- printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
+#ifdef MODULE
+ /* If the driver is run as module, read from conf.modules or cmd-line */
+ if (boot_options)
+ option_setup(boot_options);
+#endif
+
/* get interrupt request level */
+#ifdef OLDKERN
+ if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi",
+ hosts))
+#else
if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmcascsi",
hosts))
+#endif
{
printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
return 0;
}
-
+ else
+ IRQ14_registered++;
+
/* if ibmmcascsi setup option was passed to kernel, return "found" */
for (i = 0; i < IM_MAX_HOSTS; i++)
if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8)
printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n",
io_port[i], scsi_id[i]);
if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i],
+ FORCED_DETECTION,
"forced detected SCSI Adapter")))
{
((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = 0;
((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = 0;
- ((struct ibmmca_hostdata *)shpnt->hostdata)->_special =
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = 0;
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = 0;
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = 0;
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_special =
FORCED_DETECTION;
- mca_set_adapter_name(MCA_INTEGSCSI, "forcibly detected SCSI Adapter");
+ mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
shpnt);
mca_mark_as_used(MCA_INTEGSCSI);
- }
+ devices_on_irq_14++;
+ }
}
if (found) return found;
-
+
/* The POS2-register of all PS/2 model SCSI-subsystems has the following
* interpretation of bits:
* Bit 7 - 4 : Chip Revision ID (Release)
* Bit 4 : Reserved = 0
* Bit 3 - 0 : Reserved = 0
* (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
- * Interfaces (1991)").
- * In short words, this means, that IBM PS/2 machines only support
- * 1 single subsystem by default. The slot-adapters must have another
+ * Interfaces (1991)").
+ * In short words, this means, that IBM PS/2 machines only support
+ * 1 single subsystem by default. The slot-adapters must have another
* configuration on pos2. Here, one has to assume the following
* things for POS2-register:
* Bit 7 - 4 : Chip Revision ID (Release)
* Bit 3 - 1 : port offset factor
* Bit 0 : Chip Enable (EN-Signal)
* As I found a patch here, setting the IO-registers to 0x3540 forced,
- * as there was a 0x05 in POS2 on a model 56, I assume, that the
+ * as there was a 0x05 in POS2 on a model 56, I assume, that the
* port 0x3540 must be fix for integrated SCSI-controllers.
* Ok, this discovery leads to the following implementation: (M.Lang) */
for (j=0;j<8;j++) /* read the pos-information */
pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j);
/* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present */
- if (( pos[2] != 0xff) || (pos[3] != 0xff ))
+ /* if (( pos[2] != 0xff) || (pos[3] != 0xff )) */
+ /* Previous if-arguments do fail! Therefore, we use now the following to
+ * make sure, we see a real integrated onboard SCSI-interface: */
+ if ((!pos[0] && !pos[1] && pos[2]>0 && pos[3]>0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) ||
+ (pos[0]==0xff && pos[1]==0xff && pos[2]<0xff && pos[3]<0xff && pos[4]==0xff && pos[5]==0xff && pos[6]==0xff && pos[7]==0xff))
{
if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
- {
- port = IM_IO_PORT;
- }
- else
+ port = IM_IO_PORT;
+ else
{ /* if disabled, no IRQs will be generated, as the chip won't
* listen to the incomming commands and will do really nothing,
* except for listening to the pos-register settings. If this
port = IM_IO_PORT; /* anyway, set the portnumber and warn */
printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
printk(" SCSI-operations may not work.\n");
- }
+ }
id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
-
- /* give detailed information on the subsystem. This helps me
+
+ /* give detailed information on the subsystem. This helps me
* additionally during debugging and analyzing bug-reports. */
printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n",
port, id);
/* register the found integrated SCSI-subsystem */
if ((shpnt = ibmmca_register(scsi_template, port, id,
+ INTEGRATED_SCSI,
"IBM Integrated SCSI Controller")))
{
((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
- ((struct ibmmca_hostdata *)shpnt->hostdata)->_special =
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_special =
INTEGRATED_SCSI;
mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
shpnt);
mca_mark_as_used(MCA_INTEGSCSI);
+ devices_on_irq_14++;
}
}
-
- /* now look for other adapters in MCA slots, */
+
+ /* now look for other adapters in MCA slots, */
/* determine the number of known IBM-SCSI-subsystem types */
/* see the pos[2] dependence to get the adapter port-offset. */
list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
{ /* (explanations see above) */
port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
- }
- else
+ }
+ else
{ /* anyway, set the portnumber and warn */
- port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+ port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
printk(" SCSI-operations may not work.\n");
+ }
+ if ((i==IBM_SCSI2_FW)&&(pos[6]!=0))
+ {
+ printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+ printk(" Impossible to determine adapter PUN!\n");
+ printk(" Guessing adapter PUN = 7.\n");
+ id = 7;
+ }
+ else
+ {
+ id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+ if (i==IBM_SCSI2_FW)
+ {
+ id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
+ * for F/W adapters */
+ }
+ }
+ if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+ { /* IRQ11 is used by SCSI-2 F/W Adapter/A */
+ printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+ /* get interrupt request level */
+#ifdef OLDKERN
+ if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ,
+ "ibmmcascsi", hosts))
+#else
+ if (request_irq (IM_IRQ_FW, do_interrupt_handler, SA_SHIRQ,
+ "ibmmcascsi", hosts))
+#endif
+ {
+ printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n",
+ IM_IRQ_FW);
+ }
+ else
+ IRQ11_registered++;
}
- id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
subsys_list[i].description, slot + 1, port, id);
- printk(" chip rev.=%d, port-offset=0x%x, subsystem=%s\n",
- ((pos[2] & 0xf0) >> 4),
+ if ((pos[2] & 0xf0) == 0xf0)
+ printk(" ROM Addr.=off,");
+ else
+ printk(" ROM Addr.=0x%x,",
+ ((pos[2] & 0xf0) << 13) + 0xc0000);
+ printk(" port-offset=0x%x, subsystem=%s\n",
((pos[2] & 0x0e) << 2),
(pos[2] & 1) ? "enabled." : "disabled.");
-
+
/* register the hostadapter */
- if ((shpnt = ibmmca_register(scsi_template, port, id,
+ if ((shpnt = ibmmca_register(scsi_template, port, id, i,
subsys_list[i].description)))
{
((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6];
((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
mca_set_adapter_name (slot, subsys_list[i].description);
mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
shpnt);
mca_mark_as_used(slot);
+ if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+ devices_on_irq_11++;
+ else
+ devices_on_irq_14++;
}
slot++; /* advance to next slot */
} /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
}
- if (!found)
- { /* maybe ESDI, or other producers' SCSI-hosts */
- free_irq (IM_IRQ, hosts);
- printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
+
+ /* now look for SCSI-adapters, by bugs mapped to the integrated SCSI
+ * area. E.g. a W/Cache in MCA-slot 9 ???? Arrrrgh!! */
+ list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+ for (i = 0; i < list_size; i++)
+ { /* scan each slot for a fitting adapter id */
+ slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
+ if (slot != MCA_NOTFOUND)
+ { /* scan through all slots */
+ for (j=0;j<8;j++) /* read the pos-information */
+ pos[j] = mca_read_stored_pos(slot, j);
+ if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
+ { /* (explanations see above) */
+ port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+ }
+ else
+ { /* anyway, set the portnumber and warn */
+ port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+ printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+ printk(" SCSI-operations may not work.\n");
+ }
+ if ((i==IBM_SCSI2_FW)&&(pos[6]!=0))
+ {
+ printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+ printk(" Impossible to determine adapter PUN!\n");
+ printk(" Guessing adapter PUN = 7.\n");
+ id = 7;
+ }
+ else
+ {
+ id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+ if (i==IBM_SCSI2_FW)
+ {
+ id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
+ * for F/W adapters */
+ }
+ }
+ if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+ { /* IRQ11 is used by SCSI-2 F/W Adapter/A */
+ printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+ /* get interrupt request level */
+#ifdef OLDKERN
+ if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ,
+ "ibmmcascsi", hosts))
+#else
+ if (request_irq (IM_IRQ_FW, do_interrupt_handler, SA_SHIRQ,
+ "ibmmcascsi", hosts))
+#endif
+ {
+ printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n",
+ IM_IRQ_FW);
+ }
+ else
+ IRQ11_registered++;
+ }
+ printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
+ subsys_list[i].description, slot + 1, port, id);
+ if ((pos[2] & 0xf0) == 0xf0)
+ printk(" ROM Addr.=off,");
+ else
+ printk(" ROM Addr.=0x%x,",
+ ((pos[2] & 0xf0) << 13) + 0xc0000);
+ printk(" port-offset=0x%x, subsystem=%s\n",
+ ((pos[2] & 0x0e) << 2),
+ (pos[2] & 1) ? "enabled." : "disabled.");
+
+ /* register the hostadapter */
+ if ((shpnt = ibmmca_register(scsi_template, port, id, i,
+ subsys_list[i].description)))
+ {
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos4 = pos[4];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos5 = pos[5];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos6 = pos[6];
+ ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
+
+ mca_set_adapter_name (slot, subsys_list[i].description);
+ mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
+ shpnt);
+ mca_mark_as_used(slot);
+ if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
+ devices_on_irq_11++;
+ else
+ devices_on_irq_14++;
+ }
+ slot++; /* advance to next slot */
+ } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
}
+
+ if ( IRQ11_registered && !devices_on_irq_11 )
+ free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */
+ if ( IRQ14_registered && !devices_on_irq_14 )
+ free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */
+ if ( !devices_on_irq_11 && !devices_on_irq_14 )
+ printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
}
static struct Scsi_Host *
-ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id,
- char *hostname)
+ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id,
+ int adaptertype, char *hostname)
{
struct Scsi_Host *shpnt;
int i, j;
unsigned int ctrl;
-
+
/* check I/O region */
if (check_region(port, IM_N_IO_PORT))
{
port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
return NULL;
}
-
+
/* register host */
shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
if (!shpnt)
printk("IBM MCA SCSI: Unable to register host.\n");
return NULL;
}
-
+
/* request I/O region */
request_region(port, IM_N_IO_PORT, hostname);
-
+
hosts[found] = shpnt; /* add new found hostadapter to the list */
+ special(found) = adaptertype; /* important assignment or else crash! */
+ subsystem_connector_size(found) = 0; /* preset slot-size */
shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
shpnt->io_port = port;
shpnt->n_io_port = IM_N_IO_PORT;
shpnt->this_id = id;
+ shpnt->max_id = 8; /* 8 PUNs are default */
/* now, the SCSI-subsystem is connected to Linux */
-
- ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */
+
+ ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n",
ctrl,inb(IM_STAT_REG(found)));
if (bypass_controller)
printk("IBM MCA SCSI: Subsystem SCSI-commands get bypassed.\n");
#endif
-
+
reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
- for (i = 0; i < 8; i++) /* reset the tables */
+ for (i = 0; i < 16; i++) /* reset the tables */
for (j = 0; j < 8; j++)
get_ldn(found)[i][j] = MAX_LOG_DEV;
/* check which logical devices exist */
- local_checking_phase_flag(found) = 1;
- check_devices(found); /* call by value, using the global variable hosts*/
+ /* after this line, local interrupting is possible: */
+ local_checking_phase_flag(found) = 1;
+ check_devices(found,adaptertype); /* call by value, using the global variable hosts*/
local_checking_phase_flag(found) = 0;
-
+
found++; /* now increase index to be prepared for next found subsystem */
/* an ibm mca subsystem has been detected */
return shpnt;
/*--------------------------------------------------------------------*/
/* The following routine is the SCSI command queue. The old edition is
- now improved by dynamical reassignment of ldn numbers that are
+ now improved by dynamical reassignment of ldn numbers that are
currently not assigned. The mechanism works in a way, that first
the physical structure is checked. If at a certain pun,lun a device
should be present, the routine proceeds to the ldn check from
get_ldn. An answer of 0xff would show-up, that the aimed device is
- currently not assigned any ldn. At this point, the dynamical
+ currently not assigned any ldn. At this point, the dynamical
remapping algorithm is called. It works in a way, that it goes in
cyclic order through the ldns from 7 to 14. If a ldn is assigned,
it takes 8 dynamical reassignment calls, until a device looses its
- ldn again. With this method it is assured, that while doing
+ ldn again. With this method it is assured, that while doing
intense I/O between up to eight devices, no dynamical remapping is
done there. ldns 0 through 6(!) are left untouched, which means, that
puns 0 through 7(!) on lun=0 are always accessible without remapping.
- These ldns are statically assigned by this driver. The subsystem always
- occupies at least one pun, therefore 7 ldns (at lun=0) for other devices
+ These ldns are statically assigned by this driver. The subsystem always
+ occupies at least one pun, therefore 7 ldns (at lun=0) for other devices
are sufficient. (The adapter uses always ldn=15, at whatever pun it is.) */
int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
{
int id,lun;
int target;
int host_index;
-
- if (ibm_ansi_order)
- target = 6 - cmd->target;
- else
- target = cmd->target;
-
+ int max_pun;
+ int i;
+ struct scatterlist *sl;
+
shpnt = cmd->host;
/* search for the right hostadapter */
for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
-
+
if (!hosts[host_index])
{ /* invalid hostadapter descriptor address */
cmd->result = DID_NO_CONNECT << 16;
- done (cmd);
+ if (done)
+ done (cmd);
return 0;
}
-
+
+ max_pun = subsystem_maxid(host_index);
+
+ if (ibm_ansi_order)
+ {
+ target = max_pun - 1 - cmd->target;
+ if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index)))
+ target--;
+ else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index)))
+ target++;
+ }
+ else
+ target = cmd->target;
+
/*if (target,lun) is NO LUN or not existing at all, return error */
if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)||
(get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE))
{
cmd->result = DID_NO_CONNECT << 16;
- done (cmd);
+ if (done)
+ done (cmd);
return 0;
}
-
+
/*if (target,lun) unassigned, do further checks... */
ldn = get_ldn(host_index)[target][cmd->lun];
if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */
while (ld(host_index)[next_ldn(host_index)].cmd) /* search for a occupied, but not in */
{ /* command-processing ldn. */
next_ldn(host_index)++;
- if (next_ldn(host_index)>=MAX_LOG_DEV)
+ if (next_ldn(host_index)>=MAX_LOG_DEV)
next_ldn(host_index) = 7;
if (current_ldn == next_ldn(host_index)) /* One circle done ? */
{ /* no non-processing ldn found */
printk(" Reporting DID_NO_CONNECT for device (%d,%d).\n",
target, cmd->lun);
cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
- done (cmd);
+ if (done)
+ done (cmd);
return 0;
}
}
-
+
/* unmap non-processing ldn */
- for (id=0; id<8; id ++)
+ for (id=0; id<max_pun; id ++)
for (lun=0; lun<8; lun++)
{
if (get_ldn(host_index)[id][lun] == next_ldn(host_index))
{
- get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
+ get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
/* unmap entry */
}
}
/* change ldn to the right value, that is now next_ldn */
ldn = next_ldn(host_index);
/* get device information for ld[ldn] */
- if (device_exists (host_index, ldn,
+ if (device_exists (host_index, ldn,
&ld(host_index)[ldn].block_length,
&ld(host_index)[ldn].device_type))
{
ld(host_index)[ldn].cmd = 0; /* To prevent panic set 0, because
devices that were not assigned,
should have nothing in progress. */
-
+
/* increase assignment counters for statistics in /proc */
IBM_DS(host_index).dynamical_assignments++;
IBM_DS(host_index).ldn_assignments[ldn]++;
}
else
- /* panic here, because a device, found at boottime has
+ /* panic here, because a device, found at boottime has
vanished */
panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
ldn, target, cmd->lun);
-
+
/* set back to normal interrupt_handling */
local_checking_phase_flag(host_index) = 0;
-
+
/* Information on syslog terminal */
printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
ldn, target, cmd->lun);
-
- /* increase next_ldn for next dynamical assignment */
+
+ /* increase next_ldn for next dynamical assignment */
next_ldn(host_index)++;
- if (next_ldn(host_index)>=MAX_LOG_DEV)
+ if (next_ldn(host_index)>=MAX_LOG_DEV)
next_ldn(host_index) = 7;
- }
+ }
else
- { /* wall against Linux accesses to the subsystem adapter */
+ { /* wall against Linux accesses to the subsystem adapter */
cmd->result = DID_BAD_TARGET << 16;
- done (cmd);
+ if (done)
+ done (cmd);
return 0;
}
}
-
+
/*verify there is no command already in progress for this log dev */
if (ld(host_index)[ldn].cmd)
panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n");
-
+
/*save done in cmd, and save cmd for the interrupt handler */
cmd->scsi_done = done;
ld(host_index)[ldn].cmd = cmd;
-
+
/*fill scb information independent of the scsi command */
scb = &(ld(host_index)[ldn].scb);
ld(host_index)[ldn].tsb.dev_status = 0;
- scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
+ scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb));
+ scsi_cmd = cmd->cmnd[0];
+
if (cmd->use_sg)
{
- int i = cmd->use_sg;
- struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer;
+ i = cmd->use_sg;
+ sl = (struct scatterlist *)(cmd->request_buffer);
if (i > 16)
panic ("IBM MCA SCSI: scatter-gather list too long.\n");
while (--i >= 0)
{
- ld(host_index)[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
+ ld(host_index)[ldn].sge[i].address = (void *)(virt_to_bus(sl[i].address));
ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
}
scb->enable |= IM_POINTER_TO_LIST;
else
{
scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
- scb->sys_buf_length = cmd->request_bufflen;
+ /* recent Linux midlevel SCSI places 1024 byte for inquiry
+ * command. Far too much for old PS/2 hardware. */
+ switch (scsi_cmd)
+ { /* avoid command errors by setting bufferlengths to
+ * ANSI-standard. */
+ case INQUIRY:
+ case REQUEST_SENSE:
+ case MODE_SENSE:
+ case MODE_SELECT:
+ scb->sys_buf_length = 255;
+ break;
+ case TEST_UNIT_READY:
+ scb->sys_buf_length = 0;
+ break;
+ default:
+ scb->sys_buf_length = cmd->request_bufflen;
+ break;
+ }
}
-
/*fill scb information dependent on scsi command */
- scsi_cmd = cmd->cmnd[0];
-
+
#ifdef IM_DEBUG_CMD
printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
#endif
-
+
/* for specific device-type debugging: */
#ifdef IM_DEBUG_CMD_SPEC_DEV
if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE)
- printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n",
+ printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n",
ld(host_index)[ldn].device_type, scsi_cmd, ldn);
#endif
-
+
/* for possible panics store current command */
- last_scsi_command(host_index)[ldn] = scsi_cmd;
- last_scsi_type(host_index)[ldn] = IM_SCB;
-
+ last_scsi_command(host_index)[ldn] = scsi_cmd;
+ last_scsi_type(host_index)[ldn] = IM_SCB;
/* update statistical info */
IBM_DS(host_index).total_accesses++;
IBM_DS(host_index).ldn_access[ldn]++;
-
+
switch (scsi_cmd)
{
case READ_6:
case READ_10:
case WRITE_10:
case READ_12:
- case WRITE_12:
- /* statistics for proc_info */
- if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12))
- IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
- else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)||
- (scsi_cmd == WRITE_12))
- IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
-
+ case WRITE_12:
/* Distinguish between disk and other devices. Only disks (that are the
- most frequently accessed devices) should be supported by the
- IBM-SCSI-Subsystem commands. */
+ most frequently accessed devices) should be supported by the
+ IBM-SCSI-Subsystem commands. */
switch (ld(host_index)[ldn].device_type)
{
case TYPE_DISK: /* for harddisks enter here ... */
case TYPE_MOD: /* ... try it also for MO-drives (send flames as */
/* you like, if this won't work.) */
- if (scsi_cmd == READ_6 || scsi_cmd == READ_10 ||
+ if (scsi_cmd == READ_6 || scsi_cmd == READ_10 ||
scsi_cmd == READ_12)
{ /* read command preparations */
+ scb->enable |= IM_READ_CONTROL;
+ IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
if (bypass_controller)
{
scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL;
+ scb->enable |= IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
}
else
- {
- scb->command = IM_READ_DATA_CMD;
- scb->enable |= IM_READ_CONTROL;
- }
+ scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
}
else
{ /* write command preparations */
+ IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
if (bypass_controller)
{
scb->command = IM_OTHER_SCSI_CMD_CMD;
+ scb->enable |= IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
}
else
- {
- scb->command = IM_WRITE_DATA_CMD;
- }
+ scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
}
-
+
if (!bypass_controller)
- {
+ {
if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6)
{
scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) |
scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
(((unsigned) cmd->cmnd[7]) << 8);
}
+ last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
+ last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
scb->u2.blk.length = ld(host_index)[ldn].block_length;
- }
+ }
if (++disk_rw_in_progress == 1)
PS2_DISK_LED_ON (shpnt->host_no, target);
break;
-
+
/* for other devices, enter here. Other types are not known by
Linux! TYPE_NO_LUN is forbidden as valid device. */
case TYPE_ROM:
case TYPE_PROCESSOR:
case TYPE_WORM:
case TYPE_SCANNER:
- case TYPE_MEDIUM_CHANGER:
-
+ case TYPE_MEDIUM_CHANGER:
/* If there is a sequential-device, IBM recommends to use
- IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
+ IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
Good/modern CD-ROM-drives are capable of
reading sequential AND random-access. This leads to the problem,
- that random-accesses are covered by the subsystem, but
+ that random-accesses are covered by the subsystem, but
sequentials are not, as like for tape-drives. Therefore, it is
the easiest way to use IM_OTHER_SCSI_CMD_CMD for all read-ops
on CD-ROM-drives in order not to run into timing problems and
to have a stable state. In addition, data-access on CD-ROMs
works faster like that. Strange, but obvious. */
-
+
scb->command = IM_OTHER_SCSI_CMD_CMD;
- if (scsi_cmd == READ_6 || scsi_cmd == READ_10 ||
+ if (scsi_cmd == READ_6 || scsi_cmd == READ_10 ||
scsi_cmd == READ_12) /* enable READ */
- {
- scb->enable |= IM_READ_CONTROL;
- }
-
+ scb->enable |= IM_READ_CONTROL;
+ scb->enable |= IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-
- /* Read/write on this non-disk devices is also displayworthy,
- so flash-up the LED/display. */
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+
+ /* Read/write on this non-disk devices is also displayworthy,
+ so flash-up the LED/display. */
if (++disk_rw_in_progress == 1)
PS2_DISK_LED_ON (shpnt->host_no, target);
break;
if (bypass_controller)
{
scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+ scb->u1.log_blk_adr = 0;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
}
else
{
scb->command = IM_DEVICE_INQUIRY_CMD;
scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+ scb->u1.log_blk_adr = 0;
}
break;
-
+ case TEST_UNIT_READY:
+ scb->command = IM_OTHER_SCSI_CMD_CMD;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+ scb->u1.log_blk_adr = 0;
+ scb->u1.scsi_cmd_length = 6;
+ memcpy (scb->u2.scsi_command, cmd->cmnd, 6);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+ break;
case READ_CAPACITY:
/* the length of system memory buffer must be exactly 8 bytes */
if (scb->sys_buf_length > 8)
if (bypass_controller)
{
scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
}
else
{
scb->command = IM_READ_CAPACITY_CMD;
- scb->enable |= IM_READ_CONTROL;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
}
break;
-
- /* Commands that need read-only-mode (system <- device): */
+
+ /* Commands that need read-only-mode (system <- device): */
case REQUEST_SENSE:
- if (bypass_controller)
+ if (bypass_controller)
{
scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
}
else
{
scb->command = IM_REQUEST_SENSE_CMD;
- scb->enable |= IM_READ_CONTROL;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
}
break;
-
- /* Commands that need write-only-mode (system -> device): */
+
+ /* Commands that need write-only-mode (system -> device): */
case MODE_SELECT:
case MODE_SELECT_10:
IBM_DS(host_index).ldn_modeselect_access[ldn]++;
- scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
+ scb->command = IM_OTHER_SCSI_CMD_CMD;
+ scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled*/
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
break;
-
- /* For other commands, read-only is useful. Most other commands are
+
+ /* For other commands, read-only is useful. Most other commands are
running without an input-data-block. */
default:
scb->command = IM_OTHER_SCSI_CMD_CMD;
- scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+ scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
scb->u1.scsi_cmd_length = cmd->cmd_len;
memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+ last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
break;
}
-
/*issue scb command, and return */
- issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+ if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB)
+ {
+ issue_cmd (host_index, virt_to_bus(scb), IM_LONG_SCB | ldn);
+ IBM_DS(host_index).long_scbs++;
+ }
+ else
+ {
+ issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+ IBM_DS(host_index).scbs++;
+ }
return 0;
}
/* Abort does not work, as the adapter never generates an interrupt on
* whatever situation is simulated, even when really pending commands
* are running on the adapters' hardware ! */
-
+
struct Scsi_Host *shpnt;
unsigned int ldn;
void (*saved_done) (Scsi_Cmnd *);
int target;
int host_index;
+ int max_pun;
static unsigned long flags;
unsigned long imm_command;
/* return SCSI_ABORT_SNOOZE ; */
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&abort_lock, flags);
- if (ibm_ansi_order)
- target = 6 - cmd->target;
- else
- target = cmd->target;
-
+#endif
shpnt = cmd->host;
/* search for the right hostadapter */
- for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
-
+ for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
if (!hosts[host_index])
{ /* invalid hostadapter descriptor address */
cmd->result = DID_NO_CONNECT << 16;
if (cmd->scsi_done)
- (cmd->done) (cmd);
+ (cmd->scsi_done) (cmd);
return SCSI_ABORT_SNOOZE;
}
-
+
+ max_pun = subsystem_maxid(host_index);
+
+ if (ibm_ansi_order)
+ {
+ target = max_pun - 1 - cmd->target;
+ if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index)))
+ target--;
+ else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index)))
+ target++;
+ }
+ else
+ target = cmd->target;
+
/*get logical device number, and disable system interrupts */
printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n",
target, cmd->lun);
/*if cmd for this ldn has already finished, no need to abort */
if (!ld(host_index)[ldn].cmd)
{
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&abort_lock, flags);
+#endif
return SCSI_ABORT_NOT_RUNNING;
}
- /* Clear ld.cmd, save done function, install internal done,
- * send abort immediate command (this enables sys. interrupts),
- * and wait until the interrupt arrives.
+ /* Clear ld.cmd, save done function, install internal done,
+ * send abort immediate command (this enables sys. interrupts),
+ * and wait until the interrupt arrives.
*/
saved_done = cmd->scsi_done;
cmd->scsi_done = internal_done;
{
if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
break;
+#ifdef OLDKERN
+ restore_flags (flags);
+#else
spin_unlock_irqrestore(&abort_lock, flags);
-
+#endif
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&abort_lock, flags);
+#endif
}
/*write registers and enable system interrupts */
outl (imm_command, IM_CMD_REG(host_index));
outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN
+ restore_flags (flags);
+#else
spin_unlock_irqrestore(&abort_lock, flags);
-
+#endif
+
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort submitted, waiting for adapter response...\n");
-#endif
+#endif
while (!cmd->SCp.Status)
- barrier ();
- cmd->scsi_done = saved_done;
- /*if abort went well, call saved done, then return success or error */
+ barrier ();
+ cmd->scsi_done = saved_done;
+ /*if abort went well, call saved done, then return success or error */
if (cmd->result == (DID_ABORT << 16))
{
cmd->result |= DID_ABORT << 16;
ld(host_index)[ldn].cmd = NULL;
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort finished with success.\n");
-#endif
+#endif
return SCSI_ABORT_SUCCESS;
}
else
ld(host_index)[ldn].cmd = NULL;
#ifdef IM_DEBUG_PROBE
printk("IBM MCA SCSI: Abort failed.\n");
-#endif
+#endif
return SCSI_ABORT_ERROR;
}
}
static unsigned long flags;
unsigned long imm_command;
+ if (cmd == NULL)
+ {
+ printk("IBM MCA SCSI: Reset called with NULL-command!\n");
+ return(SCSI_RESET_SNOOZE);
+ }
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&reset_lock, flags);
+#endif
ticks = IM_RESET_DELAY*HZ;
shpnt = cmd->host;
/* search for the right hostadapter */
{ /* invalid hostadapter descriptor address */
if (!local_checking_phase_flag(host_index))
{
- cmd->result = DID_NO_CONNECT << 16;
- if (cmd->scsi_done)
- (cmd->done) (cmd);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+ if (flags & SCSI_RESET_SYNCHRONOUS)
+ {
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
+ spin_unlock_irqrestore(&reset_lock, flags);
+#endif
+ cmd->result = DID_NO_CONNECT << 16;
+ if (cmd->scsi_done)
+ (cmd->scsi_done) (cmd);
+ }
+#endif
}
return SCSI_ABORT_SNOOZE;
}
if (local_checking_phase_flag(host_index))
{
printk("IBM MCA SCSI: unable to reset while checking devices.\n");
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&reset_lock, flags);
+#endif
return SCSI_RESET_SNOOZE;
}
{
if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
break;
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&reset_lock, flags);
+#endif
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&reset_lock, flags);
+#endif
}
/*write registers and enable system interrupts */
outl (imm_command, IM_CMD_REG(host_index));
printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
IM_RESET_DELAY);
reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&reset_lock, flags);
+#endif
return SCSI_RESET_ERROR;
}
-
+
if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f)
{ /* analysis done by this routine and not by the intr-routine */
if (inb(IM_INTR_REG(host_index))==0xaf)
else /* failed, 4get it */
reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
outb (IM_EOI | 0xf, IM_ATTN_REG(host_index));
- }
-
+ }
+
/* if reset failed, just return an error */
if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
printk("IBM MCA SCSI: reset failed.\n");
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&reset_lock, flags);
+#endif
return SCSI_RESET_ERROR;
}
-
+
/* so reset finished ok - call outstanding done's, and return success */
- printk ("IBM MCA SCSI: Reset completed without known error.\n");
+ printk ("IBM MCA SCSI: Reset successfully completed.\n");
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&reset_lock, flags);
+#endif
for (i = 0; i < MAX_LOG_DEV; i++)
{
cmd_aid = ld(host_index)[i].cmd;
{
ld(host_index)[i].cmd = NULL;
cmd_aid->result = DID_RESET << 16;
- (cmd_aid->scsi_done) (cmd_aid);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,132)
+ if (flags & SCSI_RESET_SYNCHRONOUS)
+ {
+ cmd_aid->result = DID_BUS_BUSY << 16;
+ if (cmd_aid->scsi_done)
+ (cmd_aid->scsi_done) (cmd_aid);
+ }
+#endif
}
}
- return SCSI_RESET_SUCCESS;
+ if (flags & SCSI_RESET_SUGGEST_HOST_RESET)
+ return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
+ else if (flags & SCSI_RESET_SUGGEST_BUS_RESET)
+ return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+ else
+ return SCSI_RESET_SUCCESS;
}
/*--------------------------------------------------------------------*/
{
int a;
int i;
-
+
a = 0;
for (i=0; i<=MAX_LOG_DEV; i++)
a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i];
{
int a;
int i;
-
+
a = 0;
for (i=0; i<=MAX_LOG_DEV; i++)
a+=IBM_DS(host_index).ldn_inquiry_access[i];
{
int a;
int i;
-
+
a = 0;
for (i=0; i<=MAX_LOG_DEV; i++)
a+=IBM_DS(host_index).ldn_modeselect_access[i];
int i,id,lun,host_index;
struct Scsi_Host *shpnt;
unsigned long flags;
-
+ int max_pun;
+
+#ifdef OLDKERN
+ save_flags(flags);
+ cli();
+#else
spin_lock_irqsave(&proc_lock, flags);
+#endif
for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
shpnt = hosts[i];
host_index = i;
if (!shpnt) {
- len += sprintf(buffer+len, "\nCan't find adapter for host number %d\n", hostno);
+ len += sprintf(buffer+len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno);
return len;
}
-
+ max_pun = subsystem_maxid(host_index);
+
len += sprintf(buffer+len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n",
IBMMCA_SCSI_DRIVER_VERSION);
len += sprintf(buffer+len, " SCSI Access-Statistics:\n");
(bypass_controller) ? "software" : "hardware integrated");
len += sprintf(buffer+len, " Total Interrupts.........: %d\n",
IBM_DS(host_index).total_interrupts);
- len += sprintf(buffer+len, " Total SCSI Accesses......: %d\n",
+ len += sprintf(buffer+len, " Total SCSI Accesses......: %d\n",
IBM_DS(host_index).total_accesses);
+ len += sprintf(buffer+len, " Total short SCBs.........: %d\n",
+ IBM_DS(host_index).scbs);
+ len += sprintf(buffer+len, " Total long SCBs..........: %d\n",
+ IBM_DS(host_index).long_scbs);
len += sprintf(buffer+len, " Total SCSI READ/WRITE..: %d\n",
ldn_access_total_read_write(host_index));
len += sprintf(buffer+len, " Total SCSI Inquiries...: %d\n",
i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i],
IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
len += sprintf(buffer+len, " -----------------------------------------------------------\n\n");
-
+
len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n");
len += sprintf(buffer+len, " Number of physical SCSI-devices..: %d (+ Adapter)\n",
IBM_DS(host_index).total_scsi_devices);
- len += sprintf(buffer+len, " Dynamical Assignment necessaray..: %s\n",
+ len += sprintf(buffer+len, " Dynamical Assignment necessary...: %s\n",
IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
len += sprintf(buffer+len, " Next LDN to be assigned..........: 0x%x\n",
next_ldn(host_index));
len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n");
len += sprintf(buffer+len, " Physical SCSI-Device Map Logical SCSI-Device Map\n");
len += sprintf(buffer+len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
- for (id=0; id<=7; id++)
+ for (id=0; id<max_pun; id++)
{
len += sprintf(buffer+len, " %2d ",id);
for (lun=0; lun<8; lun++)
- len += sprintf(buffer+len,"%2s ",ti_p(get_scsi(host_index)[id][lun]));
-
+ len += sprintf(buffer+len,"%2s ",ti_p(get_scsi(host_index)[id][lun]));
len += sprintf(buffer+len, " %2d ",id);
for (lun=0; lun<8; lun++)
len += sprintf(buffer+len,"%2s ",ti_l(get_ldn(host_index)[id][lun]));
len += sprintf(buffer+len,"\n");
}
-
+
len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
len += sprintf(buffer+len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
len += sprintf(buffer+len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
-
+
*start = buffer + offset;
len -= offset;
- if (len > length)
+ if (len > length)
len = length;
+#ifdef OLDKERN
+ restore_flags(flags);
+#else
spin_unlock_irqrestore(&proc_lock, flags);
+#endif
return len;
}
+void ibmmca_scsi_setup (char *str, int *ints)
+{
+ internal_ibmmca_scsi_setup (str, ints);
+}
+
+static int option_setup(char *str)
+{
+ int ints[IM_MAX_HOSTS];
+ char *cur = str;
+ int i = 1;
+
+ while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) {
+ ints[i++] = simple_strtoul(cur, NULL, 0);
+ if ((cur = strchr(cur,',')) != NULL) cur++;
+ }
+ ints[0] = i - 1;
+ internal_ibmmca_scsi_setup(cur, ints);
+ return 0;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18)
+__setup("ibmmcascsi=", option_setup);
+#endif
+
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = IBMMCA;
#include "scsi_module.c"
-
-/*
- * Module parameters
- */
-
-MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
-MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
-MODULE_PARM(display, "1i");
-MODULE_PARM(adisplay, "1i");
-MODULE_PARM(bypass, "1i");
-MODULE_PARM(normal, "1i");
-MODULE_PARM(ansi, "1i");
#endif
/*--------------------------------------------------------------------*/
+
+/*
+ * Low Level Driver for the IBM Microchannel SCSI Subsystem
+ * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver
+ * For use under the GNU public license within the Linux-kernel project.
+ */
+
#ifndef _IBMMCA_H
#define _IBMMCA_H
#include <linux/version.h>
#endif
-#ifndef ibmmca_header_linux_version
-#define ibmmca_header_linux_version(v,p,s) (((v)<<16)+((p)<<8)+(s))
-#endif
-
-/*
- * Low Level Driver for the IBM Microchannel SCSI Subsystem
- * (Headerfile, see README.ibmmca for description of the IBM MCA SCSI-driver)
- */
+/* Note to the Linux-toplevel-maintainers:
+ * This file contains the unified header for all available Linux-distributions.
+ * For reasons of maintenance, it is recommended to keep this unmodified to
+ * be downward compatible until I no longer get any requests from people
+ * using older kernel releases on their PS/2 machines. (23 Apr 2000, M.Lang) */
/* Common forward declarations for all Linux-versions: */
-/*services provided to the higher level of Linux SCSI driver */
+/* Interfaces to the midlevel Linux SCSI driver */
extern int ibmmca_proc_info (char *, char **, off_t, int, int, int);
extern int ibmmca_detect (Scsi_Host_Template *);
extern int ibmmca_release (struct Scsi_Host *);
extern int ibmmca_biosparam (Disk *, kdev_t, int *);
/*structure for /proc filesystem */
+extern struct proc_dir_entry proc_scsi_ibmmca;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,75)
+/* Stuff for Linux >= 2.1.75: */
/*
* 2/8/98
* Note to maintainer of IBMMCA. Do not change this initializer back to
* the old format. Please ask eric@andante.jic.com if you have any questions
* about this, but it will break things in the future.
*/
-#define IBMMCA { \
+/*initialization for Scsi_host_template type (Linux >= 2.1.75 && < 2.3.27) */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27)
+#define IBMMCA { \
+ proc_dir: &proc_scsi_ibmmca, /*proc_dir*/ \
+ proc_info: ibmmca_proc_info, /*proc info fn*/ \
+ name: "IBM SCSI-Subsystem", /*name*/ \
+ detect: ibmmca_detect, /*detect fn*/ \
+ release: ibmmca_release, /*release fn*/ \
+ command: ibmmca_command, /*command fn*/ \
+ queuecommand: ibmmca_queuecommand, /*queuecommand fn*/ \
+ abort: ibmmca_abort, /*abort fn*/ \
+ reset: ibmmca_reset, /*reset fn*/ \
+ bios_param: ibmmca_biosparam, /*bios fn*/ \
+ can_queue: 16, /*can_queue*/ \
+ this_id: 7, /*set by detect*/ \
+ sg_tablesize: 16, /*sg_tablesize*/ \
+ cmd_per_lun: 1, /*cmd_per_lun*/ \
+ unchecked_isa_dma: 0, /*32-Bit Busmaster */ \
+ use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \
+ }
+#else
+#define IBMMCA { \
proc_name: "ibmmca", /*proc_name*/ \
proc_info: ibmmca_proc_info, /*proc info fn*/ \
name: "IBM SCSI-Subsystem", /*name*/ \
unchecked_isa_dma: 0, /*32-Bit Busmaster */ \
use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \
}
+#endif
+#else
+/* Stuff for Linux < 2.1.75: */
+
+/*initialization for Scsi_host_template type (Linux < 2.1.75) */
+#define IBMMCA { \
+ NULL, /*next*/ \
+ NULL, /*usage_count*/ \
+ &proc_scsi_ibmmca, /*proc_dir*/ \
+ ibmmca_proc_info, /*proc info fn*/ \
+ "IBM SCSI-Subsystem", /*name*/ \
+ ibmmca_detect, /*detect fn*/ \
+ ibmmca_release, /*release fn*/ \
+ NULL, /*info fn*/ \
+ ibmmca_command, /*command fn*/ \
+ ibmmca_queuecommand, /*queuecommand fn*/ \
+ ibmmca_abort, /*abort fn*/ \
+ ibmmca_reset, /*reset fn*/ \
+ NULL, /*slave_attach fn*/ \
+ ibmmca_biosparam, /*bios fn*/ \
+ 16, /*can_queue*/ \
+ 7, /*set by detect*/ \
+ 16, /*sg_tablesize*/ \
+ 1, /*cmd_per_lun*/ \
+ 0, /*present*/ \
+ 0, /*unchecked_isa_dma*/ \
+ ENABLE_CLUSTERING /*use_clustering*/ \
+ }
+#endif /* kernelversion selection */
#endif /* _IBMMCA_H */
* their hosts through the modules entrypoints, and don't use the big
* list in hosts.c.
*/
-#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE) /* a big #ifdef block... */
+#if defined(CONFIG_MODULES) || defined(CONFIG_BLK_DEV_IDESCSI) || defined(CONFIG_USB_STORAGE) || defined(CONFIG_USB_MICROTEK) /* a big #ifdef block... */
/*
* This entry point should be called by a loadable module if it is trying
* any later version.
*
*/
- static char * sg_version_str = "Version: 3.1.15 (20000528)";
- static int sg_version_num = 30115; /* 2 digits for each component */
+ static char * sg_version_str = "Version: 3.1.16 (20000716)";
+ static int sg_version_num = 30116; /* 2 digits for each component */
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
* - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
Sg_scatter_hold * req_schp = &srp->data;
Sg_scatter_hold * rsv_schp = &sfp->reserve;
+ srp->res_used = 1;
SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
- /* round request up to next highest SG_SECTOR_SZ byte boundary */
- size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
+ size = (size + 1) & (~1); /* round to even for aha1542 */
if (rsv_schp->k_use_sg > 0) {
int k, num;
int rem = size;
for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
num = (int)sclp->length;
if (rem <= num) {
- sfp->save_scat_len = num;
- sclp->length = (unsigned)rem;
- break;
+ if (0 == k) {
+ req_schp->k_use_sg = 0;
+ req_schp->buffer = sclp->address;
+ }
+ else {
+ sfp->save_scat_len = num;
+ sclp->length = (unsigned)rem;
+ req_schp->k_use_sg = k + 1;
+ req_schp->sglist_len = rsv_schp->sglist_len;
+ req_schp->buffer = rsv_schp->buffer;
+ }
+ req_schp->bufflen = size;
+ req_schp->buffer_mem_src = rsv_schp->buffer_mem_src;
+ req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+ break;
}
else
rem -= num;
}
- if (k < rsv_schp->k_use_sg) {
- req_schp->k_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->buffer_mem_src = rsv_schp->buffer_mem_src;
- req_schp->b_malloc_len = rsv_schp->b_malloc_len;
- }
- else
+ if (k >= rsv_schp->k_use_sg)
SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));
}
else {
req_schp->bufflen = size;
req_schp->buffer = rsv_schp->buffer;
req_schp->buffer_mem_src = rsv_schp->buffer_mem_src;
- req_schp->k_use_sg = rsv_schp->k_use_sg;
req_schp->b_malloc_len = rsv_schp->b_malloc_len;
}
- srp->res_used = 1;
}
static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",
(int)req_schp->k_use_sg));
- if (rsv_schp->k_use_sg > 0) {
+ if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {
struct scatterlist * sclp = (struct scatterlist *)rsv_schp->buffer;
if (sfp->save_scat_len > 0)
}
static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
-{ /* if this is to be locked remember that it is called from _bh */
+{
Sg_request * srp;
Sg_request * tsrp;
int dirty = 0;
int res = 0;
- /* no lock since not expecting any parallel action on this fd */
srp = sfp->headrp;
if (srp) {
while (srp) {
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o
-obj-$(CONFIG_SOUND_AD1816) += ad1816.o
+obj-$(CONFIG_SOUND_AD1816) += ad1816.o sound.o
obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o
module_init(acm_init);
module_exit(acm_exit);
+
+MODULE_AUTHOR("Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik");
+MODULE_DESCRIPTION("USB Abstract Control Model driver for USB modems and ISDN adapters");
usb_deregister(&usb_audio_driver);
}
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>, Thomas Sailer (sailer@ife.ee.ethz.ch)");
+MODULE_DESCRIPTION("USB Audio Class driver");
#endif
MODULE_AUTHOR ("Deti Fliegl, deti@fliegl.de");
MODULE_DESCRIPTION ("DAB-USB Interface Driver for Linux (c)1999");
MODULE_PARM (buffers, "i");
+MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
int __init init_module (void)
{
usb_deregister(&usb_dsbr100_driver);
}
+MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
+MODULE_DESCRIPTION("D-Link DSB-R100 USB radio driver");
+
/*
vi: ts=8
Sigh. Of course, I am one of the ts=2 heretics, but Linus' wish is
module_init(evdev_init);
module_exit(evdev_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Event character device driver");
module_init(hid_init);
module_exit(hid_exit);
+
+MODULE_AUTHOR("Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("USB HID support drivers");
static int init_model2_yb = -1;
MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
MODULE_PARM(flags, "i");
+MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=seperate frames, 6=clean frames");
MODULE_PARM(framerate, "i");
+MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
MODULE_PARM(lighting, "i");
+MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
MODULE_PARM(sharpness, "i");
+MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
MODULE_PARM(videosize, "i");
+MODULE_PARM_DESC(videosize, "Image size: 0=128x96, 1=176x144, 2=352x288, 3=320x240, 4=352x240 (default=1)");
MODULE_PARM(init_brightness, "i");
+MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
MODULE_PARM(init_contrast, "i");
+MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
MODULE_PARM(init_color, "i");
+MODULE_PARM_DESC(init_color, "Dolor preconfiguration: 0-255 (default=128)");
MODULE_PARM(init_hue, "i");
+MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
MODULE_PARM(hue_correction, "i");
+MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
MODULE_PARM(init_model2_rg, "i");
+MODULE_PARM_DESC(init_model2_rg, "Model2 preconfiguration: 0-255 (default=112)");
MODULE_PARM(init_model2_rg2, "i");
+MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
MODULE_PARM(init_model2_sat, "i");
+MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
MODULE_PARM(init_model2_yb, "i");
+MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
MODULE_AUTHOR ("module author");
MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
#include <linux/config.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_WMFORCE 0xc281
#include <linux/random.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Input layer module");
EXPORT_SYMBOL(input_register_device);
EXPORT_SYMBOL(input_unregister_device);
static struct joydev *joydev_table[JOYDEV_MINORS];
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Joystick device driver");
MODULE_SUPPORTED_DEVICE("input/js");
static int joydev_correct(int value, struct js_corr *corr)
module_init(keybdev_init);
module_exit(keybdev_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Input driver to keyboard driver binding");
module_init(microtek_drv_init);
module_exit(microtek_drv_exit);
+
+MODULE_AUTHOR("John Fremlin <vii@penguinpowered.com>, Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>");
+MODULE_DESCRIPTION("Microtek Scanmaker X6 USB scanner driver");
module_init(mousedev_init);
module_exit(mousedev_exit);
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
static int retry_sync = 0;
MODULE_PARM(autoadjust, "i");
+MODULE_PARM_DESC(autoadjust, "CCD dynamically changes exposure");
MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level: 0=none, 1=init/detection, 2=warning, 3=config/control, 4=function call, 5=max");
MODULE_PARM(fix_rgb_offset, "i");
+MODULE_PARM_DESC(fix_rgb_offset, "Fix vertical misalignment of red and blue at 640x480");
MODULE_PARM(snapshot, "i");
+MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
MODULE_PARM(sensor, "i");
+MODULE_PARM_DESC(sensor, "Override sensor detection");
MODULE_PARM(i2c_detect_tries, "i");
+MODULE_PARM_DESC(i2c_detect_tries, "Number of tries to detect sensor");
MODULE_PARM(aperture, "i");
+MODULE_PARM_DESC(aperture, "Read the OV7610/7620 specs");
MODULE_PARM(force_rgb, "i");
+MODULE_PARM_DESC(force_rgb, "Read RBG instead of BGR");
MODULE_PARM(buf_timeout, "i");
+MODULE_PARM_DESC(buf_timeout, "Number of seconds before buffer deallocation");
MODULE_PARM(cams, "i");
+MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
MODULE_PARM(retry_sync, "i");
+MODULE_PARM_DESC(retry_sync, "Prevent apps from timing out");
MODULE_AUTHOR("Mark McClelland <mmcclelland@delphi.com> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
MODULE_DESCRIPTION("OV511 USB Camera Driver");
MODULE_AUTHOR("Petko Manolov <petkan@spct.net>");
MODULE_DESCRIPTION("ADMtek AN986 Pegasus USB Ethernet driver");
MODULE_PARM(loopback, "i");
-
+MODULE_PARM_DESC(loopback, "Enable loopback mode (Bit 0) and ??? (Bit 1)");
static struct usb_eth_dev usb_dev_id[] = {
{"Billionton USB-100", 0x08dd, 0x0986, NULL},
module_init(usblp_init);
module_exit(usblp_exit);
+
+MODULE_AUTHOR("Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap");
+MODULE_DESCRIPTION("USB Printer Device Class driver");
module_init(usb_rio_init);
module_exit(usb_rio_cleanup);
+MODULE_AUTHOR("Cesar Miquel <miquel@df.uba.ar>");
+MODULE_DESCRIPTION("USB Rio 500 driver");
obj-n :=
obj- :=
-ifeq ($(CONFIG_USB_SERIAL),y)
- obj-y += usbserial.o
-endif
-ifeq ($(CONFIG_USB_SERIAL),m)
- obj-m += usbserial.o
-endif
-
+obj-$(CONFIG_USB_SERIAL) += usbserial.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
module_init(digi_init);
module_exit(digi_exit);
+MODULE_AUTHOR("Peter Berger <pberger@brimson.com>, Al Borchers <borchers@steinerpoint.com>");
+MODULE_DESCRIPTION("Digi AccelePort USB-4 Serial Converter driver");
module_init(ftdi_sio_init);
module_exit(ftdi_sio_exit);
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>");
+MODULE_DESCRIPTION("USB FTDI SIO driver");
module_init(keyspan_init);
module_exit(keyspan_exit);
+MODULE_AUTHOR("Hugh Blemings <hugh@linuxcare.com>");
+MODULE_DESCRIPTION("Keyspan USB to Serial Converter driver");
module_init(keyspan_pda_init);
module_exit(keyspan_pda_exit);
+MODULE_AUTHOR("Brian Warner <warner@lothar.com>");
+MODULE_DESCRIPTION("USB Keyspan PDA Converter driver");
module_init(visor_init);
module_exit(visor_exit);
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
+MODULE_DESCRIPTION("USB HandSpring Visor driver");
module_init(whiteheat_init);
module_exit(whiteheat_exit);
+MODULE_AUTHOR("Greg Kroah-Hartman <greg@kroah.com>");
+MODULE_DESCRIPTION("USB ConnectTech WhiteHEAT driver");
CFLAGS_transport.o:= -I../../scsi/
CFLAGS_debug.o:= -I../../scsi/
CFLAGS_usb.o:= -I../../scsi/
-CFLAGS_scm.o:= -I../../scsi/
+CFLAGS_shuttle_usbat.o:= -I../../scsi/
+CFLAGS_sddr09.o:= -I../../scsi/
ifeq ($(CONFIG_USB_STORAGE_DEBUG),y)
O_OBJS += debug.o
endif
ifeq ($(CONFIG_USB_STORAGE_HP8200e),y)
- O_OBJS += scm.o
+ O_OBJS += shuttle_usbat.o
endif
ifeq ($(CONFIG_USB_STORAGE_SDDR09),y)
- O_OBJS += scm.o
+ O_OBJS += sddr09.o
endif
ifeq ($(CONFIG_USB_STORAGE_FREECOM),y)
+++ /dev/null
-/* Driver for SCM Microsystems USB-ATAPI cable
- *
- * $Id: scm.c,v 1.4 2000/07/24 19:19:52 mdharm Exp $
- *
- * SCM driver v0.2:
- *
- * Removed any reference to maxlen for bulk transfers.
- * Changed scm_bulk_transport to allow for transfers without commands.
- * Changed hp8200e transport to use the request_bufflen field in the
- * SCSI command for the length of the transfer, rather than calculating
- * it ourselves based on the command.
- *
- * SCM driver v0.1:
- *
- * First release - hp8200e.
- *
- * Current development and maintainance by:
- * (c) 2000 Robert Baruch (autophile@dol.net)
- *
- * Many originally ATAPI devices were slightly modified to meet the USB
- * market by using some kind of translation from ATAPI to USB on the host,
- * and the peripheral would translate from USB back to ATAPI.
- *
- * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only,
- * which does the USB-to-ATAPI conversion. By obtaining the data sheet on
- * their device under nondisclosure agreement, I have been able to write
- * this driver for Linux.
- *
- * The chip used in the device can also be used for EPP and ISA translation
- * as well. This driver is only guaranteed to work with the ATAPI
- * translation.
- *
- * The only peripherals that I know of (as of 14 Jul 2000) that uses this
- * device is the Hewlett-Packard 8200e CD-Writer Plus.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "transport.h"
-#include "protocol.h"
-#include "usb.h"
-#include "debug.h"
-#include "scm.h"
-
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/malloc.h>
-
-extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
- u8 request, u8 requesttype, u16 value, u16 index,
- void *data, u16 size);
-extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
- unsigned int len, unsigned int *act_len);
-
-/*
- * Send a control message and wait for the response.
- *
- * us - the pointer to the us_data structure for the device to use
- *
- * request - the URB Setup Packet's first 6 bytes. The first byte always
- * corresponds to the request type, and the second byte always corresponds
- * to the request. The other 4 bytes do not correspond to value and index,
- * since they are used in a custom way by the SCM protocol.
- *
- * xfer_data - a buffer from which to get, or to which to store, any data
- * that gets send or received, respectively, with the URB. Even though
- * it looks like we allocate a buffer in this code for the data, xfer_data
- * must contain enough allocated space.
- *
- * xfer_len - the number of bytes to send or receive with the URB.
- *
- */
-
-static int scm_send_control(struct us_data *us,
- unsigned char command[8],
- unsigned char *xfer_data,
- unsigned int xfer_len) {
-
- int result;
- int pipe;
- void *buffer = NULL;
-
- command[6] = xfer_len&0xFF;
- command[7] = (xfer_len>>8)&0xFF;
-
- // Get the receive or send control pipe number, based on
- // the direction indicated by the request type.
-
- if (command[0] & USB_DIR_IN)
- pipe = usb_rcvctrlpipe(us->pusb_dev,0);
- else
- pipe = usb_sndctrlpipe(us->pusb_dev,0);
-
-
- // If data is going to be sent or received with the URB,
- // then allocate a buffer for it. If data is to be sent,
- // copy the data into the buffer.
-
- if (xfer_len > 0) {
- buffer = kmalloc(xfer_len, GFP_KERNEL);
- if (!(command[0] & USB_DIR_IN))
- memcpy(buffer, xfer_data, xfer_len);
- }
-
- // Send the URB to the device and wait for a response.
-
- /* Why are request and request type reversed in this call? */
-
- result = usb_stor_control_msg(us, pipe,
- command[1], command[0],
- (((unsigned short)command[3])<<8) | command[2],
- (((unsigned short)command[5])<<8) | command[3],
- buffer,
- xfer_len);
-
-
- // If data was sent or received with the URB, free the buffer we
- // allocated earlier, but not before reading the data out of the
- // buffer if we wanted to receive data.
-
- if (xfer_len > 0) {
- if (command[0] & USB_DIR_IN)
- memcpy(xfer_data, buffer, xfer_len);
- kfree(buffer);
- }
-
- // Check the return code for the command.
-
- if (result < 0) {
- /* a stall is a fatal condition from the device */
- if (result == -EPIPE) {
- US_DEBUGP("-- Stall on control pipe. Clearing\n");
- result = usb_clear_halt(us->pusb_dev, pipe);
- US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
- return USB_STOR_TRANSPORT_FAILED;
- }
-
- /* Uh oh... serious problem here */
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- return USB_STOR_TRANSPORT_GOOD;
-}
-
-static int scm_raw_bulk(struct us_data *us,
- int direction,
- unsigned char *data,
- unsigned short len) {
-
- int result;
- int act_len;
- int pipe;
-
- if (direction == SCSI_DATA_READ)
- pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
- else
- pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
-
- result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
-
- /* if we stall, we need to clear it before we go on */
- if (result == -EPIPE) {
- US_DEBUGP("EPIPE: clearing endpoint halt for"
- " pipe 0x%x, stalled at %d bytes\n",
- pipe, act_len);
- usb_clear_halt(us->pusb_dev, pipe);
- }
-
- if (result) {
-
- /* NAK - that means we've retried a few times already */
- if (result == -ETIMEDOUT) {
- US_DEBUGP("scm_raw_bulk():"
- " device NAKed\n");
- return US_BULK_TRANSFER_FAILED;
- }
-
- /* -ENOENT -- we canceled this transfer */
- if (result == -ENOENT) {
- US_DEBUGP("scm_raw_bulk():"
- " transfer aborted\n");
- return US_BULK_TRANSFER_ABORTED;
- }
-
- if (result == -EPIPE) {
- US_DEBUGP("scm_raw_bulk():"
- " output pipe stalled\n");
- return USB_STOR_TRANSPORT_FAILED;
- }
-
- /* the catch-all case */
- US_DEBUGP("us_transfer_partial(): unknown error\n");
- return US_BULK_TRANSFER_FAILED;
- }
-
- if (act_len != len) {
- US_DEBUGP("Warning: Transferred only %d bytes\n",
- act_len);
- return US_BULK_TRANSFER_SHORT;
- }
-
- US_DEBUGP("Transfered %d of %d bytes\n", act_len, len);
-
- return US_BULK_TRANSFER_GOOD;
-}
-
-/*
- * Note: direction must be set if command_len == 0.
- */
-
-static int scm_bulk_transport(struct us_data *us,
- unsigned char *command,
- unsigned short command_len,
- int direction,
- unsigned char *data,
- unsigned short len,
- int use_sg) {
-
- int result = USB_STOR_TRANSPORT_GOOD;
- int transferred = 0;
- unsigned char execute[8] = {
- 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- int i;
- struct scatterlist *sg;
- char string[64];
-
- if (command_len != 0) {
-
- /* Fix up the command's data length */
-
- command[6] = len&0xFF;
- command[7] = (len>>8)&0xFF;
-
- result = scm_send_control(us,
- execute,
- command,
- command_len);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
- }
-
- if (len==0)
- return USB_STOR_TRANSPORT_GOOD;
-
-
- /* transfer the data payload for the command, if there is any */
-
-
- if (command_len != 0)
- direction = (command[0]&0x80) ? SCSI_DATA_READ :
- SCSI_DATA_WRITE;
-
- if (direction == SCSI_DATA_WRITE) {
-
- /* Debug-print the first 48 bytes of the write transfer */
-
- if (!use_sg) {
- string[0] = 0;
- for (i=0; i<len && i<48; i++) {
- sprintf(string+strlen(string), "%02X ",
- data[i]);
- if ((i%16)==15) {
- US_DEBUGP("%s\n", string);
- string[0] = 0;
- }
- }
- if (string[0]!=0)
- US_DEBUGP("%s\n", string);
- }
- }
-
-
- US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
- ( direction==SCSI_DATA_READ ? "in" : "out"),
- len, use_sg);
-
- if (!use_sg)
- result = scm_raw_bulk(us, direction, data, len);
- else {
- sg = (struct scatterlist *)data;
- for (i=0; i<use_sg && transferred<len; i++) {
- result = scm_raw_bulk(us, direction,
- sg[i].address,
- len-transferred > sg[i].length ?
- sg[i].length : len-transferred);
- if (result!=US_BULK_TRANSFER_GOOD)
- break;
- transferred += sg[i].length;
- }
- }
-
- return result;
-}
-
-int scm_read(struct us_data *us,
- unsigned char access,
- unsigned char reg,
- unsigned char *content) {
-
- int result;
- unsigned char command[8] = {
- 0xC0, access, reg, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- result = scm_send_control(us, command, content, 1);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // US_DEBUGP("SCM: Reg %d -> %02X\n", reg, *content);
-
- return result;
-}
-
-int scm_write(struct us_data *us,
- unsigned char access,
- unsigned char reg,
- unsigned char content) {
-
- int result;
- unsigned char command[8] = {
- 0x40, access|0x01, reg, content, 0x00, 0x00, 0x00, 0x00
- };
-
- result = scm_send_control(us, command, NULL, 0);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // US_DEBUGP("SCM: Reg %d <- %02X\n", reg, content);
-
- return result;
-}
-
-int scm_set_shuttle_features(struct us_data *us,
- unsigned char external_trigger,
- unsigned char epp_control,
- unsigned char mask_byte,
- unsigned char test_pattern,
- unsigned char subcountH,
- unsigned char subcountL) {
-
- int result;
- unsigned char command[8] = {
- 0x40, 0x81, epp_control, external_trigger,
- test_pattern, mask_byte, subcountL, subcountH
- };
-
- result = scm_bulk_transport(us, command, 8, 0, NULL, 0, 0);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- return result;
-}
-
-int scm_read_block(struct us_data *us,
- unsigned char access,
- unsigned char reg,
- unsigned char *content,
- unsigned short len,
- int use_sg) {
-
- int result;
- unsigned char command[8] = {
- 0xC0, access|0x02, reg, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- result = scm_bulk_transport(us,
- command, 8, 0, content, len, use_sg);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // US_DEBUGP("SCM: Read data, result %d\n", result);
-
- return result;
-}
-
-/*
- * Block, waiting for an ATA device to become not busy or to report
- * an error condition.
- */
-
-int scm_wait_not_busy(struct us_data *us) {
-
- int i;
- int result;
- unsigned char status;
-
- /* Synchronizing cache on a CDR could take a heck of a long time,
- but probably not more than 15 minutes or so */
-
- for (i=0; i<500; i++) {
- result = scm_read(us, SCM_ATA, 0x17, &status);
- US_DEBUGP("SCM: Write ATA data status is %02X\n", status);
- if (result!=USB_STOR_TRANSPORT_GOOD)
- return result;
- if (status&0x01) // check condition
- return USB_STOR_TRANSPORT_FAILED;
- if (status&0x20) // device fault
- return USB_STOR_TRANSPORT_FAILED;
- if ((status&0x80)!=0x80) // not busy
- break;
- if (i<5)
- wait_ms(100);
- else if (i<20)
- wait_ms(500);
- else if (i<49)
- wait_ms(1000);
- else if (i<499)
- wait_ms(2000);
- }
-
- if (i==500)
- return USB_STOR_TRANSPORT_FAILED;
-
- return USB_STOR_TRANSPORT_GOOD;
-}
-
-int scm_write_block(struct us_data *us,
- unsigned char access,
- unsigned char reg,
- unsigned char *content,
- unsigned short len,
- int use_sg) {
-
- int result;
- unsigned char command[8] = {
- 0x40, access|0x03, reg, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- result = scm_bulk_transport(us,
- command, 8, 0, content, len, use_sg);
-
- if (result!=USB_STOR_TRANSPORT_GOOD)
- return result;
-
- return scm_wait_not_busy(us);
-}
-
-int scm_write_block_test(struct us_data *us,
- unsigned char access,
- unsigned char *registers,
- unsigned char *data_out,
- unsigned short num_registers,
- unsigned char data_reg,
- unsigned char status_reg,
- unsigned char qualifier,
- unsigned char timeout,
- unsigned char *content,
- unsigned short len,
- int use_sg) {
-
- int result;
- unsigned char command[16] = {
- 0x40, access|0x07, 0x07, 0x17, 0xfc, 0xe7, 0x00, 0x00,
- 0x40, access|0x05, data_reg, status_reg,
- qualifier, timeout, 0x00, 0x00
- };
- int i;
- unsigned char data[num_registers*2];
- int transferred;
- struct scatterlist *sg;
- char string[64];
-
- command[14] = len&0xFF;
- command[15] = (len>>8)&0xFF;
-
- for (i=0; i<num_registers; i++) {
- data[i<<1] = registers[i];
- data[1+(i<<1)] = data_out[i];
- }
-
- result = scm_bulk_transport(us,
- command, 16, 0, data, num_registers*2, 0);
-
- if (result!=USB_STOR_TRANSPORT_GOOD)
- return result;
-
- transferred = 0;
-
- US_DEBUGP("Transfer out %d bytes, sg buffers %d\n",
- len, use_sg);
-
- if (!use_sg) {
-
- /* Debug-print the first 48 bytes of the transfer */
-
- string[0] = 0;
- for (i=0; i<len && i<48; i++) {
- sprintf(string+strlen(string), "%02X ",
- content[i]);
- if ((i%16)==15) {
- US_DEBUGP("%s\n", string);
- string[0] = 0;
- }
- }
- if (string[0]!=0)
- US_DEBUGP("%s\n", string);
-
- result = scm_raw_bulk(us, SCSI_DATA_WRITE, content, len);
-
- } else {
-
- sg = (struct scatterlist *)content;
- for (i=0; i<use_sg && transferred<len; i++) {
- result = scm_raw_bulk(us, SCSI_DATA_WRITE,
- sg[i].address,
- len-transferred > sg[i].length ?
- sg[i].length : len-transferred);
- if (result!=US_BULK_TRANSFER_GOOD)
- break;
- transferred += sg[i].length;
- }
- }
-
- if (result!=USB_STOR_TRANSPORT_GOOD)
- return result;
-
- return scm_wait_not_busy(us);
-}
-
-int scm_multiple_write(struct us_data *us,
- unsigned char access,
- unsigned char *registers,
- unsigned char *data_out,
- unsigned short num_registers) {
-
- int result;
- unsigned char data[num_registers*2];
- int i;
- unsigned char cmd[8] = {
- 0x40, access|0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
- for (i=0; i<num_registers; i++) {
- data[i<<1] = registers[i];
- data[1+(i<<1)] = data_out[i];
- }
-
- result = scm_bulk_transport(us, cmd, 8, 0, data, num_registers*2, 0);
-
- if (result!=USB_STOR_TRANSPORT_GOOD)
- return result;
-
- return scm_wait_not_busy(us);
-}
-
-static int hp_8200e_select_and_test_registers(struct us_data *us) {
-
- int result;
- int selector;
- unsigned char status;
-
- // try device = master, then device = slave.
-
- for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
-
- if ( (result = scm_write(us, SCM_ATA, 0x16, selector)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read(us, SCM_ATA, 0x17, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read(us, SCM_ATA, 0x16, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read(us, SCM_ATA, 0x14, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read(us, SCM_ATA, 0x15, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_write(us, SCM_ATA, 0x14, 0x55)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_write(us, SCM_ATA, 0x15, 0xAA)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read(us, SCM_ATA, 0x14, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read(us, SCM_ATA, 0x15, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
- }
-
- return result;
-}
-
-int scm_read_user_io(struct us_data *us,
- unsigned char *data_flags) {
-
- unsigned char command[8] = {
- 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- int result;
-
- result = scm_send_control(us, command, data_flags, 1);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // US_DEBUGP("SCM: User I/O flags -> %02X\n", *data_flags);
-
- return result;
-}
-
-int scm_write_user_io(struct us_data *us,
- unsigned char enable_flags,
- unsigned char data_flags) {
-
- unsigned char command[8] = {
- 0x40, 0x82, enable_flags, data_flags, 0x00, 0x00, 0x00, 0x00
- };
- int result;
-
- result = scm_send_control(us, command, NULL, 0);
-
- if (result != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // US_DEBUGP("SCM: User I/O flags <- %02X\n", data_flags);
-
- return result;
-}
-
-static int init_sddr09(struct us_data *us) {
-
- int result;
- unsigned char data[14];
- unsigned char command[8] = {
- 0xc1, 0x01, 0, 0, 0, 0, 0, 0
- };
- unsigned char command2[8] = {
- 0x41, 0, 0, 0, 0, 0, 0, 0
- };
- unsigned char tur[12] = {
- 0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
- };
-
- if ( (result = scm_send_control(us, command, data, 2)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
-
- command[1] = 0x08;
-
- if ( (result = scm_send_control(us, command, data, 2)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
-/*
- if ( (result = scm_send_control(us, command2, tur, 12)) !=
- USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("SDDR09: request sense failed\n");
- return result;
- }
-
- if ( (result = scm_raw_bulk(
- us, SCSI_DATA_READ, data, 14)) !=
- USB_STOR_TRANSPORT_GOOD) {
- US_DEBUGP("SDDR09: request sense bulk in failed\n");
- return result;
- }
-
- US_DEBUGP("SDDR09: request sense worked\n");
-*/
- return result;
-}
-
-static int init_8200e(struct us_data *us) {
-
- int result;
- unsigned char status;
-
- // Enable peripheral control signals
-
- if ( (result = scm_write_user_io(us,
- SCM_UIO_OE1 | SCM_UIO_OE0,
- SCM_UIO_EPAD | SCM_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- wait_ms(2000);
-
- if ( (result = scm_read_user_io(us, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read_user_io(us, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // Reset peripheral, enable periph control signals
- // (bring reset signal up)
-
- if ( (result = scm_write_user_io(us,
- SCM_UIO_DRVRST | SCM_UIO_OE1 | SCM_UIO_OE0,
- SCM_UIO_EPAD | SCM_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // Enable periph control signals
- // (bring reset signal down)
-
- if ( (result = scm_write_user_io(us,
- SCM_UIO_OE1 | SCM_UIO_OE0,
- SCM_UIO_EPAD | SCM_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- wait_ms(250);
-
- // Write 0x80 to ISA port 0x3F
-
- if ( (result = scm_write(us, SCM_ISA, 0x3F, 0x80)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // Read ISA port 0x27
-
- if ( (result = scm_read(us, SCM_ISA, 0x27, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read_user_io(us, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = hp_8200e_select_and_test_registers(us)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read_user_io(us, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- // Enable periph control signals and card detect
-
- if ( (result = scm_write_user_io(us,
- SCM_UIO_ACKD |SCM_UIO_OE1 | SCM_UIO_OE0,
- SCM_UIO_EPAD | SCM_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_read_user_io(us, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- wait_ms(1400);
-
- if ( (result = scm_read_user_io(us, &status)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = hp_8200e_select_and_test_registers(us)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- if ( (result = scm_set_shuttle_features(us,
- 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) !=
- USB_STOR_TRANSPORT_GOOD)
- return result;
-
- return result;
-}
-
-/*
- * Transport for the HP 8200e
- */
-int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- int result;
- unsigned char status;
- unsigned char registers[32];
- unsigned char data[32];
- unsigned int len;
- int i;
- char string[64];
-
- /* This table tells us:
- X = command not supported
- L = return length in cmnd[4] (8 bits).
- H = return length in cmnd[7] and cmnd[8] (16 bits).
- D = return length in cmnd[6] to cmnd[9] (32 bits).
- B = return length/blocksize in cmnd[6] to cmnd[8].
- T = return length in cmnd[6] to cmnd[8] (24 bits).
- 0-9 = fixed return length
- W = 24 bytes
- h = return length/2048 in cmnd[7-8].
- */
-
- static char *lengths =
-
- /* 0123456789ABCDEF 0123456789ABCDEF */
-
- "0XXL0XXXXXXXXXXX" "XXLXXXXXXXX0XX0X" /* 00-1F */
- "XXXXX8XXhXH0XXX0" "XXXXX0XXXXXXXXXX" /* 20-3F */
- "XXHHL0X0XXH0XX0X" "XHH00HXX0TH0H0XX" /* 40-5F */
- "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */
- "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */
- "X0XXX0XXDXDXXXXX" "XXXXXXXXX000XHBX" /* A0-BF */
- "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
- "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
-
- if (us->flags & US_FL_NEED_INIT) {
- US_DEBUGP("8200e: initializing\n");
- init_8200e(us);
- us->flags &= ~US_FL_NEED_INIT;
- }
-
- len = srb->request_bufflen;
-
-/* if (srb->sc_data_direction == SCSI_DATA_WRITE)
- len = srb->request_bufflen;
- else {
-
- switch (lengths[srb->cmnd[0]]) {
-
- case 'L':
- len = srb->cmnd[4];
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- len = lengths[srb->cmnd[0]]-'0';
- break;
- case 'H':
- len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
- break;
- case 'h':
- len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
- len <<= 11; // *2048
- break;
- case 'T':
- len = (((unsigned int)srb->cmnd[6])<<16) |
- (((unsigned int)srb->cmnd[7])<<8) |
- srb->cmnd[8];
- break;
- case 'D':
- len = (((unsigned int)srb->cmnd[6])<<24) |
- (((unsigned int)srb->cmnd[7])<<16) |
- (((unsigned int)srb->cmnd[8])<<8) |
- srb->cmnd[9];
- break;
- case 'W':
- len = 24;
- break;
- case 'B':
- // Let's try using the command structure's
- // request_bufflen here
- len = srb->request_bufflen;
- break;
- default:
- US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
- srb->cmnd[0]);
- return USB_STOR_TRANSPORT_ERROR;
- }
- } */
-
- if (len > 0xFFFF) {
- US_DEBUGP("Error: len = %08X... what do I do now?\n",
- len);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- // US_DEBUGP("XXXXXXXXXXXXXXXX req_bufflen %d, len %d, bufflen %d\n",
- // srb->request_bufflen, len, srb->bufflen);
-
- /* Send A0 (ATA PACKET COMMAND).
- Note: I guess we're never going to get any of the ATA
- commands... just ATA Packet Commands.
- */
-
- registers[0] = 0x11;
- registers[1] = 0x12;
- registers[2] = 0x13;
- registers[3] = 0x14;
- registers[4] = 0x15;
- registers[5] = 0x16;
- registers[6] = 0x17;
- data[0] = 0x00;
- data[1] = 0x00;
- data[2] = 0x00;
- data[3] = len&0xFF; // (cylL) = expected length (L)
- data[4] = (len>>8)&0xFF; // (cylH) = expected length (H)
- data[5] = 0xB0; // (device sel) = slave
- data[6] = 0xA0; // (command) = ATA PACKET COMMAND
-
- if (srb->sc_data_direction == SCSI_DATA_WRITE) {
-
- for (i=7; i<19; i++) {
- registers[i] = 0x10;
- data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
- }
-
- result = scm_write_block_test(us, SCM_ATA,
- registers, data, 19,
- 0x10, 0x17, 0xFD, 0x30,
- srb->request_buffer,
- len, srb->use_sg);
-
- return result;
- }
-
- if ( (result = scm_multiple_write(us,
- SCM_ATA,
- registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
- return result;
- }
-
- // Write the 12-byte command header.
-
- if ( (result = scm_write_block(us,
- SCM_ATA, 0x10, srb->cmnd, 12, 0)) !=
- USB_STOR_TRANSPORT_GOOD) {
- return result;
- }
-
- // If there is response data to be read in
- // then do it here.
-
- if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) {
-
- // How many bytes to read in? Check cylL register
-
- if ( (result = scm_read(us, SCM_ATA, 0x14, &status)) !=
- USB_STOR_TRANSPORT_GOOD) {
- return result;
- }
-
- if (len>0xFF) { // need to read cylH also
- len = status;
- if ( (result = scm_read(us, SCM_ATA, 0x15, &status)) !=
- USB_STOR_TRANSPORT_GOOD) {
- return result;
- }
- len += ((unsigned int)status)<<8;
- }
- else
- len = status;
-
-
- result = scm_read_block(us, SCM_ATA, 0x10,
- srb->request_buffer, len, srb->use_sg);
-
- /* Debug-print the first 32 bytes of the transfer */
-
- if (!srb->use_sg) {
- string[0] = 0;
- for (i=0; i<len && i<32; i++) {
- sprintf(string+strlen(string), "%02X ",
- ((unsigned char *)srb->request_buffer)[i]);
- if ((i%16)==15) {
- US_DEBUGP("%s\n", string);
- string[0] = 0;
- }
- }
- if (string[0]!=0)
- US_DEBUGP("%s\n", string);
- }
- }
-
- // US_DEBUGP("Command result %d\n", result);
-
- return result;
-}
-
-
-/*
- * Transport for the Sandisk SDDR-09
- */
-int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
-{
- int result;
- unsigned int len;
- unsigned char send_scsi_command[8] = {
- 0x41, 0, 0, 0, 0, 0, 0, 0
- };
- int i;
- char string[64];
- unsigned char *ptr;
- unsigned char inquiry_response[36] = {
- 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00,
- 'S', 'a', 'n', 'D', 'i', 's', 'k', ' ',
- 'I', 'm', 'a', 'g', 'e', 'M', 'a', 't',
- 'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
- ' ', ' ', ' ', ' '
- };
-
- /* This table tells us:
- X = command not supported
- L = return length in cmnd[4] (8 bits).
- H = return length in cmnd[7] and cmnd[8] (16 bits).
- D = return length in cmnd[6] to cmnd[9] (32 bits).
- B = return length/blocksize in cmnd[6] to cmnd[8].
- T = return length in cmnd[6] to cmnd[8] (24 bits).
- 0-9 = fixed return length
- W = 24 bytes
- h = return length/2048 in cmnd[7-8].
- */
-
- static char *lengths =
-
- /* 0123456789ABCDEF 0123456789ABCDEF */
-
- "0XXL0XXXXXXXXXXX" "XXLXXXXXXXX0XX0X" /* 00-1F */
- "XXXXX8XXhXH0XXX0" "XXXXX0XXXXXXXXXX" /* 20-3F */
- "XXHHL0X0XXH0XX0X" "XHH00HXX0TH0H0XX" /* 40-5F */
- "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */
- "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */
- "X0XXX0XXDXDXXXXX" "XXXXXXXXX000XHBX" /* A0-BF */
- "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
- "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
-
- if (us->flags & US_FL_NEED_INIT) {
- US_DEBUGP("SDDR-09: initializing\n");
- init_sddr09(us);
- us->flags &= ~US_FL_NEED_INIT;
- }
-
- /* if (srb->sc_data_direction == SCSI_DATA_WRITE) */
- len = srb->request_bufflen;
- /* else {
-
- switch (lengths[srb->cmnd[0]]) {
-
- case 'L':
- len = srb->cmnd[4];
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- len = lengths[srb->cmnd[0]]-'0';
- break;
- case 'H':
- len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
- break;
- case 'h':
- len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
- len <<= 11; // *2048
- break;
- case 'T':
- len = (((unsigned int)srb->cmnd[6])<<16) |
- (((unsigned int)srb->cmnd[7])<<8) |
- srb->cmnd[8];
- break;
- case 'D':
- len = (((unsigned int)srb->cmnd[6])<<24) |
- (((unsigned int)srb->cmnd[7])<<16) |
- (((unsigned int)srb->cmnd[8])<<8) |
- srb->cmnd[9];
- break;
- case 'W':
- len = 24;
- break;
- case 'B':
- // Let's try using the command structure's
- // request_bufflen here
- len = srb->request_bufflen;
- break;
- default:
- US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
- srb->cmnd[0]);
- return USB_STOR_TRANSPORT_ERROR;
- }
- } */
-
- if (srb->request_bufflen > 0xFFFF) {
- US_DEBUGP("Error: len = %08X... what do I do now?\n",
- len);
- return USB_STOR_TRANSPORT_ERROR;
- }
-
- /* Dummy up a response for INQUIRY since SDDR09 doesn't
- respond to INQUIRY commands */
-
- if (srb->cmnd[0] == INQUIRY) {
- memcpy(srb->request_buffer, inquiry_response, 36);
- return USB_STOR_TRANSPORT_GOOD;
- }
-
- for (; srb->cmd_len<12; srb->cmd_len++)
- srb->cmnd[srb->cmd_len] = 0;
-
- srb->cmnd[1] = 0x20;
-
- string[0] = 0;
- for (i=0; i<12; i++)
- sprintf(string+strlen(string), "%02X ", srb->cmnd[i]);
-
- US_DEBUGP("SDDR09: Send control for command %s\n",
- string);
-
- if ( (result = scm_send_control(us, send_scsi_command,
- srb->cmnd, 12)) != USB_STOR_TRANSPORT_GOOD)
- return result;
-
- US_DEBUGP("SDDR09: Control for command OK\n");
-
- if (srb->sc_data_direction == SCSI_DATA_WRITE ||
- srb->sc_data_direction == SCSI_DATA_READ) {
-
- US_DEBUGP("SDDR09: %s %d bytes\n",
- srb->sc_data_direction==SCSI_DATA_WRITE ?
- "sending" : "receiving",
- len);
-
- result = scm_bulk_transport(us,
- NULL, 0, srb->sc_data_direction,
- srb->request_buffer,
- len, srb->use_sg);
-
- return result;
-
- }
-
- return result;
-}
-
+++ /dev/null
-/* Driver for SCM Microsystems USB-ATAPI cable
- * Header File
- *
- * $Id: scm.h,v 1.3 2000/07/24 19:19:52 mdharm Exp $
- *
- * Current development and maintainance by:
- * (c) 2000 Robert Baruch (autophile@dol.net)
- *
- * See scm.c for more explanation
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _USB_SCM_H
-#define _USB_SCM_H
-
-#define SCM_EPP_PORT 0x10
-#define SCM_EPP_REGISTER 0x30
-#define SCM_ATA 0x40
-#define SCM_ISA 0x50
-
-/* SCM User I/O Data registers */
-
-#define SCM_UIO_EPAD 0x80 // Enable Peripheral Control Signals
-#define SCM_UIO_CDT 0x40 // Card Detect (Read Only)
- // CDT = ACKD & !UI1 & !UI0
-#define SCM_UIO_1 0x20 // I/O 1
-#define SCM_UIO_0 0x10 // I/O 0
-#define SCM_UIO_EPP_ATA 0x08 // 1=EPP mode, 0=ATA mode
-#define SCM_UIO_UI1 0x04 // Input 1
-#define SCM_UIO_UI0 0x02 // Input 0
-#define SCM_UIO_INTR_ACK 0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP)
-
-/* SCM User I/O Enable registers */
-
-#define SCM_UIO_DRVRST 0x80 // Reset Peripheral
-#define SCM_UIO_ACKD 0x40 // Enable Card Detect
-#define SCM_UIO_OE1 0x20 // I/O 1 set=output/clr=input
- // If ACKD=1, set OE1 to 1 also.
-#define SCM_UIO_OE0 0x10 // I/O 0 set=output/clr=input
-#define SCM_UIO_ADPRST 0x01 // Reset SCM chip
-
-/* SCM-specific commands */
-
-extern int scm_read(struct us_data *us, unsigned char access,
- unsigned char reg, unsigned char *content);
-extern int scm_write(struct us_data *us, unsigned char access,
- unsigned char reg, unsigned char content);
-extern int scm_read_block(struct us_data *us, unsigned char access,
- unsigned char reg, unsigned char *content, unsigned short len,
- int use_sg);
-extern int scm_write_block(struct us_data *us, unsigned char access,
- unsigned char reg, unsigned char *content, unsigned short len,
- int use_sg);
-extern int scm_multiple_write(struct us_data *us, unsigned char access,
- unsigned char *registers, unsigned char *data_out,
- unsigned short num_registers);
-extern int scm_read_user_io(struct us_data *us, unsigned char *data_flags);
-extern int scm_write_user_io(struct us_data *us,
- unsigned char enable_flags, unsigned char data_flags);
-
-/* HP 8200e stuff */
-
-extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us);
-
-/* Sandisk SDDR-09 stuff */
-
-extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
-
-#endif
/* Driver for USB Mass Storage compliant devices
* SCSI layer glue code
*
- * $Id: scsiglue.c,v 1.5 2000/07/24 18:55:39 mdharm Exp $
+ * $Id: scsiglue.c,v 1.6 2000/07/25 23:04:47 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
#include <linux/malloc.h>
-/* direction table -- this indicates the direction of the data
- * transfer for each command code -- a 1 indicates input
- */
-/* FIXME: we need to use the new direction indicators in the Scsi_Cmnd
- * structure, not this table. First we need to evaluate if it's being set
- * correctly for us, though
- */
-unsigned char us_direction[256/8] = {
- 0x28, 0x81, 0x14, 0x14, 0x20, 0x01, 0x90, 0x77,
- 0x0C, 0x20, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-
/*
* kernel thread actions
*/
/* Driver for USB Mass Storage compliant devices
* SCSI Connecting Glue Header File
*
- * $Id: scsiglue.h,v 1.2 2000/07/19 22:12:07 mdharm Exp $
+ * $Id: scsiglue.h,v 1.3 2000/07/25 23:04:47 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
#include "hosts.h"
extern unsigned char usb_stor_sense_notready[18];
-extern unsigned char us_direction[256/8];
extern Scsi_Host_Template usb_stor_host_template;
extern int usb_stor_scsiSense10to6(Scsi_Cmnd*);
extern int usb_stor_scsiSense6to10(Scsi_Cmnd*);
--- /dev/null
+/* Driver for SanDisk SDDR-09 SmartMedia reader
+ *
+ * SDDR09 driver v0.1:
+ *
+ * First release
+ *
+ * Current development and maintainance by:
+ * (c) 2000 Robert Baruch (autophile@dol.net)
+ *
+ * The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
+ * This chip is a programmable USB controller. In the SDDR-09, it has
+ * been programmed to obey a certain limited set of SCSI commands. This
+ * driver translates the "real" SCSI commands to the SDDR-09 SCSI
+ * commands.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "sddr09.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size);
+extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+ unsigned int len, unsigned int *act_len);
+
+#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+/*
+ * Send a control message and wait for the response.
+ *
+ * us - the pointer to the us_data structure for the device to use
+ *
+ * request - the URB Setup Packet's first 6 bytes. The first byte always
+ * corresponds to the request type, and the second byte always corresponds
+ * to the request. The other 4 bytes do not correspond to value and index,
+ * since they are used in a custom way by the SCM protocol.
+ *
+ * xfer_data - a buffer from which to get, or to which to store, any data
+ * that gets send or received, respectively, with the URB. Even though
+ * it looks like we allocate a buffer in this code for the data, xfer_data
+ * must contain enough allocated space.
+ *
+ * xfer_len - the number of bytes to send or receive with the URB.
+ *
+ */
+
+static int sddr09_send_control(struct us_data *us,
+ int pipe,
+ unsigned char request,
+ unsigned char requesttype,
+ unsigned short value,
+ unsigned short index,
+ unsigned char *xfer_data,
+ unsigned int xfer_len) {
+
+ int result;
+
+ // If data is going to be sent or received with the URB,
+ // then allocate a buffer for it. If data is to be sent,
+ // copy the data into the buffer.
+/*
+ if (xfer_len > 0) {
+ buffer = kmalloc(xfer_len, GFP_KERNEL);
+ if (!(command[0] & USB_DIR_IN))
+ memcpy(buffer, xfer_data, xfer_len);
+ }
+*/
+ // Send the URB to the device and wait for a response.
+
+ /* Why are request and request type reversed in this call? */
+
+ result = usb_stor_control_msg(us, pipe,
+ request, requesttype, value, index,
+ xfer_data, xfer_len);
+
+
+ // If data was sent or received with the URB, free the buffer we
+ // allocated earlier, but not before reading the data out of the
+ // buffer if we wanted to receive data.
+/*
+ if (xfer_len > 0) {
+ if (command[0] & USB_DIR_IN)
+ memcpy(xfer_data, buffer, xfer_len);
+ kfree(buffer);
+ }
+*/
+ // Check the return code for the command.
+
+ if (result < 0) {
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* a stall is a fatal condition from the device */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev, pipe);
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int sddr09_raw_bulk(struct us_data *us,
+ int direction,
+ unsigned char *data,
+ unsigned short len) {
+
+ int result;
+ int act_len;
+ int pipe;
+
+ if (direction == SCSI_DATA_READ)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("EPIPE: clearing endpoint halt for"
+ " pipe 0x%x, stalled at %d bytes\n",
+ pipe, act_len);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ if (result) {
+
+ /* NAK - that means we've retried a few times already */
+ if (result == -ETIMEDOUT) {
+ US_DEBUGP("usbat_raw_bulk():"
+ " device NAKed\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("usbat_raw_bulk():"
+ " transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ if (result == -EPIPE) {
+ US_DEBUGP("usbat_raw_bulk():"
+ " output pipe stalled\n");
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* the catch-all case */
+ US_DEBUGP("us_transfer_partial(): unknown error\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ if (act_len != len) {
+ US_DEBUGP("Warning: Transferred only %d bytes\n",
+ act_len);
+ return US_BULK_TRANSFER_SHORT;
+ }
+
+ US_DEBUGP("Transfered %d of %d bytes\n", act_len, len);
+
+ return US_BULK_TRANSFER_GOOD;
+}
+
+/*
+ * Note: direction must be set if command_len == 0.
+ */
+
+static int sddr09_bulk_transport(struct us_data *us,
+ unsigned char *command,
+ unsigned short command_len,
+ int direction,
+ unsigned char *data,
+ unsigned short len,
+ int use_sg) {
+
+ int result = USB_STOR_TRANSPORT_GOOD;
+ int transferred = 0;
+ unsigned char execute[8] = {
+ 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int i;
+ struct scatterlist *sg;
+ char string[64];
+/*
+ if (command_len != 0) {
+
+ // Fix up the command's data length
+
+ command[6] = len&0xFF;
+ command[7] = (len>>8)&0xFF;
+
+ result = sddr09_send_control(us,
+ execute,
+ command,
+ command_len);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+ }
+*/
+ if (len==0)
+ return USB_STOR_TRANSPORT_GOOD;
+
+
+ /* transfer the data payload for the command, if there is any */
+
+
+ if (command_len != 0)
+ direction = (command[0]&0x80) ? SCSI_DATA_READ :
+ SCSI_DATA_WRITE;
+
+ if (direction == SCSI_DATA_WRITE) {
+
+ /* Debug-print the first 48 bytes of the write transfer */
+
+ if (!use_sg) {
+ string[0] = 0;
+ for (i=0; i<len && i<48; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ data[i]);
+ if ((i%16)==15) {
+ US_DEBUGP("%s\n", string);
+ string[0] = 0;
+ }
+ }
+ if (string[0]!=0)
+ US_DEBUGP("%s\n", string);
+ }
+ }
+
+
+ US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
+ ( direction==SCSI_DATA_READ ? "in" : "out"),
+ len, use_sg);
+
+ if (!use_sg)
+ result = sddr09_raw_bulk(us, direction, data, len);
+ else {
+ sg = (struct scatterlist *)data;
+ for (i=0; i<use_sg && transferred<len; i++) {
+ result = sddr09_raw_bulk(us, direction,
+ sg[i].address,
+ len-transferred > sg[i].length ?
+ sg[i].length : len-transferred);
+ if (result!=US_BULK_TRANSFER_GOOD)
+ break;
+ transferred += sg[i].length;
+ }
+ }
+
+ return result;
+}
+
+int sddr09_read_data(struct us_data *us,
+ unsigned long address,
+ unsigned short sectors,
+ unsigned char *content,
+ int use_sg) {
+
+ int result;
+ unsigned char command[12] = {
+ 0xe8, 0x20, MSB_of(address>>16),
+ LSB_of(address>>16), MSB_of(address&0xFFFF),
+ LSB_of(address&0xFFFF), 0, 0, 0, 0,
+ MSB_of(sectors), LSB_of(sectors)
+ };
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = sddr09_bulk_transport(us,
+ NULL, 0, SCSI_DATA_READ, content,
+ sectors*512, use_sg);
+
+ return result;
+}
+
+int sddr09_read_control(struct us_data *us,
+ unsigned long address,
+ unsigned short sectors,
+ unsigned char *content,
+ int use_sg) {
+
+ int result;
+ unsigned char command[12] = {
+ 0xe8, 0x21, MSB_of(address>>16),
+ LSB_of(address>>16), MSB_of(address&0xFFFF),
+ LSB_of(address&0xFFFF), 0, 0, 0, 0,
+ MSB_of(sectors), LSB_of(sectors)
+ };
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = sddr09_bulk_transport(us,
+ NULL, 0, SCSI_DATA_READ, content,
+ sectors*64, use_sg);
+
+ return result;
+}
+
+int sddr09_read_deviceID(struct us_data *us,
+ unsigned char *manufacturerID,
+ unsigned char *deviceID) {
+
+ int result;
+ unsigned char command[12] = {
+ 0xed, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char content[64];
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
+
+ US_DEBUGP("Result of send_control for device ID is %d\n",
+ result);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = sddr09_bulk_transport(us,
+ NULL, 0, SCSI_DATA_READ, content,
+ 64, 0);
+
+ *manufacturerID = content[0];
+ *deviceID = content[1];
+
+ return result;
+}
+
+int sddr09_read_status(struct us_data *us,
+ unsigned char *status) {
+
+ int result;
+ unsigned char command[12] = {
+ 0xec, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char content[2];
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = sddr09_bulk_transport(us,
+ NULL, 0, SCSI_DATA_READ, status,
+ 1, 0);
+
+ return result;
+}
+
+int sddr09_reset(struct us_data *us) {
+
+ int result;
+ unsigned char command[12] = {
+ 0xeb, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ command,
+ 12);
+
+ return result;
+}
+
+/*
+static int init_sddr09(struct us_data *us) {
+
+ int result;
+ unsigned char data[14];
+ unsigned char command[8] = {
+ 0xc1, 0x01, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char command2[8] = {
+ 0x41, 0, 0, 0, 0, 0, 0, 0
+ };
+ unsigned char tur[12] = {
+ 0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ if ( (result = sddr09_send_control(us, command, data, 2)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
+
+ command[1] = 0x08;
+
+ if ( (result = sddr09_send_control(us, command, data, 2)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
+
+ if ( (result = sddr09_send_control(us, command2, tur, 12)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("SDDR09: request sense failed\n");
+ return result;
+ }
+
+ if ( (result = sddr09_raw_bulk(
+ us, SCSI_DATA_READ, data, 14)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ US_DEBUGP("SDDR09: request sense bulk in failed\n");
+ return result;
+ }
+
+ US_DEBUGP("SDDR09: request sense worked\n");
+
+ return result;
+}
+*/
+
+/*
+ * Transport for the Sandisk SDDR-09
+ */
+int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+ unsigned char send_scsi_command[8] = {
+ 0x41, 0, 0, 0, 0, 0, 0, 0
+ };
+ int i;
+ char string[64];
+ unsigned char inquiry_response[36] = {
+ 0x00, 0x80, 0x00, 0x02, 0x1F, 0x00, 0x00, 0x00,
+ 'S', 'a', 'n', 'D', 'i', 's', 'k', ' ',
+ 'I', 'm', 'a', 'g', 'e', 'M', 'a', 't',
+ 'e', ' ', 'S', 'D', 'D', 'R', '0', '9',
+ ' ', ' ', ' ', ' '
+ };
+ unsigned char deviceID;
+ unsigned char manufacturerID;
+ unsigned char *ptr;
+
+/*
+ if (us->flags & US_FL_NEED_INIT) {
+ US_DEBUGP("SDDR-09: initializing\n");
+ init_sddr09(us);
+ us->flags &= ~US_FL_NEED_INIT;
+ }
+*/
+
+ ptr = (unsigned char *)srb->request_buffer;
+
+ /* Dummy up a response for INQUIRY since SDDR09 doesn't
+ respond to INQUIRY commands */
+
+ if (srb->cmnd[0] == INQUIRY) {
+ memcpy(srb->request_buffer, inquiry_response, 36);
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ if (srb->cmnd[0] == READ_CAPACITY) {
+
+ US_DEBUGP("Reading capacity...\n");
+
+ result = sddr09_read_deviceID(us,
+ &manufacturerID,
+ &deviceID);
+
+ US_DEBUGP("Result of read_deviceID is %d\n",
+ result);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("Device ID = %02X\n", deviceID);
+ US_DEBUGP("Manuf ID = %02X\n", manufacturerID);
+
+ ptr[0] = 0;
+ ptr[1] = 0;
+ ptr[2] = 0;
+ ptr[3] = 0;
+
+ switch (deviceID) {
+
+ case 0x6e: // 1MB
+ case 0xe8:
+ case 0xec:
+ ptr[4] = 0;
+ ptr[5] = 0x10;
+ break;
+
+ case 0xea: // 2MB
+ case 0x64:
+ case 0x5d:
+ ptr[4] = 0;
+ ptr[5] = 0x20;
+ break;
+
+ case 0xe3: // 4MB
+ case 0xe5:
+ case 0x6b:
+ case 0xd5:
+ ptr[4] = 0;
+ ptr[5] = 0x40;
+ break;
+
+ case 0xe6: // 8MB
+ case 0xd6:
+ ptr[4] = 0;
+ ptr[5] = 0x80;
+ break;
+
+ case 0x75: // 32MB
+ ptr[4] = 0x02;
+ ptr[5] = 0;
+ break;
+
+ default: // unknown
+ ptr[4] = 0;
+ ptr[5] = 0;
+
+ }
+
+ ptr[6] = 0;
+ ptr[7] = 0;
+
+ return USB_STOR_TRANSPORT_GOOD;
+ }
+
+ for (; srb->cmd_len<12; srb->cmd_len++)
+ srb->cmnd[srb->cmd_len] = 0;
+
+ srb->cmnd[1] = 0x20;
+
+ string[0] = 0;
+ for (i=0; i<12; i++)
+ sprintf(string+strlen(string), "%02X ", srb->cmnd[i]);
+
+ US_DEBUGP("SDDR09: Send control for command %s\n",
+ string);
+
+ if ( (result = sddr09_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0,
+ 0x41,
+ 0,
+ 0,
+ srb->cmnd,
+ 12)) != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("SDDR09: Control for command OK\n");
+
+ if (srb->request_bufflen == 0)
+ return USB_STOR_TRANSPORT_GOOD;
+
+ if (srb->sc_data_direction == SCSI_DATA_WRITE ||
+ srb->sc_data_direction == SCSI_DATA_READ) {
+
+ US_DEBUGP("SDDR09: %s %d bytes\n",
+ srb->sc_data_direction==SCSI_DATA_WRITE ?
+ "sending" : "receiving",
+ srb->request_bufflen);
+
+ result = sddr09_bulk_transport(us,
+ NULL, 0, srb->sc_data_direction,
+ srb->request_buffer,
+ srb->request_bufflen, srb->use_sg);
+
+ return result;
+
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
--- /dev/null
+/* Driver for SanDisk SDDR-09 SmartMedia reader
+ * Header File
+ *
+ * Current development and maintainance by:
+ * (c) 2000 Robert Baruch (autophile@dol.net)
+ *
+ * See sddr09.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_SHUTTLE_EUSB_SDDR09_H
+#define _USB_SHUTTLE_EUSB_SDDR09_H
+
+/* Sandisk SDDR-09 stuff */
+
+extern int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us);
+
+#endif
--- /dev/null
+/* Driver for SCM Microsystems USB-ATAPI cable
+ *
+ * SCM driver v0.2:
+ *
+ * Removed any reference to maxlen for bulk transfers.
+ * Changed scm_bulk_transport to allow for transfers without commands.
+ * Changed hp8200e transport to use the request_bufflen field in the
+ * SCSI command for the length of the transfer, rather than calculating
+ * it ourselves based on the command.
+ *
+ * SCM driver v0.1:
+ *
+ * First release - hp8200e.
+ *
+ * Current development and maintainance by:
+ * (c) 2000 Robert Baruch (autophile@dol.net)
+ *
+ * Many originally ATAPI devices were slightly modified to meet the USB
+ * market by using some kind of translation from ATAPI to USB on the host,
+ * and the peripheral would translate from USB back to ATAPI.
+ *
+ * SCM Microsystems (www.scmmicro.com) makes a device, sold to OEM's only,
+ * which does the USB-to-ATAPI conversion. By obtaining the data sheet on
+ * their device under nondisclosure agreement, I have been able to write
+ * this driver for Linux.
+ *
+ * The chip used in the device can also be used for EPP and ISA translation
+ * as well. This driver is only guaranteed to work with the ATAPI
+ * translation.
+ *
+ * The only peripherals that I know of (as of 14 Jul 2000) that uses this
+ * device is the Hewlett-Packard 8200e CD-Writer Plus.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "transport.h"
+#include "protocol.h"
+#include "usb.h"
+#include "debug.h"
+#include "shuttle_usbat.h"
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+
+extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ void *data, u16 size);
+extern int usb_stor_bulk_msg(struct us_data *us, void *data, int pipe,
+ unsigned int len, unsigned int *act_len);
+
+#define short_pack(b1,b2) ( ((u16)(b1)) | ( ((u16)(b2))<<8 ) )
+#define LSB_of(s) ((s)&0xFF)
+#define MSB_of(s) ((s)>>8)
+
+/*
+ * Send a control message and wait for the response.
+ *
+ * us - the pointer to the us_data structure for the device to use
+ *
+ * request - the URB Setup Packet's first 6 bytes. The first byte always
+ * corresponds to the request type, and the second byte always corresponds
+ * to the request. The other 4 bytes do not correspond to value and index,
+ * since they are used in a custom way by the SCM protocol.
+ *
+ * xfer_data - a buffer from which to get, or to which to store, any data
+ * that gets send or received, respectively, with the URB. Even though
+ * it looks like we allocate a buffer in this code for the data, xfer_data
+ * must contain enough allocated space.
+ *
+ * xfer_len - the number of bytes to send or receive with the URB.
+ *
+ */
+
+static int usbat_send_control(struct us_data *us,
+ int pipe,
+ unsigned char request,
+ unsigned char requesttype,
+ unsigned short value,
+ unsigned short index,
+ unsigned char *xfer_data,
+ unsigned int xfer_len) {
+
+ int result;
+
+ // If data is going to be sent or received with the URB,
+ // then allocate a buffer for it. If data is to be sent,
+ // copy the data into the buffer.
+/*
+ if (xfer_len > 0) {
+ buffer = kmalloc(xfer_len, GFP_KERNEL);
+ if (!(command[0] & USB_DIR_IN))
+ memcpy(buffer, xfer_data, xfer_len);
+ }
+*/
+ // Send the URB to the device and wait for a response.
+
+ /* Why are request and request type reversed in this call? */
+
+ result = usb_stor_control_msg(us, pipe,
+ request, requesttype, value, index,
+ xfer_data, xfer_len);
+
+
+ // If data was sent or received with the URB, free the buffer we
+ // allocated earlier, but not before reading the data out of the
+ // buffer if we wanted to receive data.
+/*
+ if (xfer_len > 0) {
+ if (command[0] & USB_DIR_IN)
+ memcpy(xfer_data, buffer, xfer_len);
+ kfree(buffer);
+ }
+*/
+ // Check the return code for the command.
+
+ if (result < 0) {
+ /* if the command was aborted, indicate that */
+ if (result == -ENOENT)
+ return USB_STOR_TRANSPORT_ABORTED;
+
+ /* a stall is a fatal condition from the device */
+ if (result == -EPIPE) {
+ US_DEBUGP("-- Stall on control pipe. Clearing\n");
+ result = usb_clear_halt(us->pusb_dev, pipe);
+ US_DEBUGP("-- usb_clear_halt() returns %d\n", result);
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* Uh oh... serious problem here */
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+static int usbat_raw_bulk(struct us_data *us,
+ int direction,
+ unsigned char *data,
+ unsigned short len) {
+
+ int result;
+ int act_len;
+ int pipe;
+
+ if (direction == SCSI_DATA_READ)
+ pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
+ else
+ pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
+
+ result = usb_stor_bulk_msg(us, data, pipe, len, &act_len);
+
+ /* if we stall, we need to clear it before we go on */
+ if (result == -EPIPE) {
+ US_DEBUGP("EPIPE: clearing endpoint halt for"
+ " pipe 0x%x, stalled at %d bytes\n",
+ pipe, act_len);
+ usb_clear_halt(us->pusb_dev, pipe);
+ }
+
+ if (result) {
+
+ /* NAK - that means we've retried a few times already */
+ if (result == -ETIMEDOUT) {
+ US_DEBUGP("usbat_raw_bulk():"
+ " device NAKed\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ /* -ENOENT -- we canceled this transfer */
+ if (result == -ENOENT) {
+ US_DEBUGP("usbat_raw_bulk():"
+ " transfer aborted\n");
+ return US_BULK_TRANSFER_ABORTED;
+ }
+
+ if (result == -EPIPE) {
+ US_DEBUGP("usbat_raw_bulk():"
+ " output pipe stalled\n");
+ return USB_STOR_TRANSPORT_FAILED;
+ }
+
+ /* the catch-all case */
+ US_DEBUGP("us_transfer_partial(): unknown error\n");
+ return US_BULK_TRANSFER_FAILED;
+ }
+
+ if (act_len != len) {
+ US_DEBUGP("Warning: Transferred only %d bytes\n",
+ act_len);
+ return US_BULK_TRANSFER_SHORT;
+ }
+
+ US_DEBUGP("Transfered %d of %d bytes\n", act_len, len);
+
+ return US_BULK_TRANSFER_GOOD;
+}
+
+/*
+ * Note: direction must be set if command_len == 0.
+ */
+
+static int usbat_bulk_transport(struct us_data *us,
+ unsigned char *command,
+ unsigned short command_len,
+ int direction,
+ unsigned char *data,
+ unsigned short len,
+ int use_sg) {
+
+ int result = USB_STOR_TRANSPORT_GOOD;
+ int transferred = 0;
+ unsigned char execute[8] = {
+ 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int i;
+ struct scatterlist *sg;
+ char string[64];
+ int pipe;
+
+/*
+ if (command_len != 0) {
+
+ // Fix up the command's data length
+
+ command[6] = len&0xFF;
+ command[7] = (len>>8)&0xFF;
+
+
+
+ result = usbat_send_control(us,
+ execute,
+ command,
+ command_len);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+ }
+*/
+ if (len==0)
+ return USB_STOR_TRANSPORT_GOOD;
+
+
+ /* transfer the data payload for the command, if there is any */
+
+
+ if (command_len != 0)
+ direction = (command[0]&0x80) ? SCSI_DATA_READ :
+ SCSI_DATA_WRITE;
+
+ if (direction == SCSI_DATA_WRITE) {
+
+ /* Debug-print the first 48 bytes of the write transfer */
+
+ if (!use_sg) {
+ string[0] = 0;
+ for (i=0; i<len && i<48; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ data[i]);
+ if ((i%16)==15) {
+ US_DEBUGP("%s\n", string);
+ string[0] = 0;
+ }
+ }
+ if (string[0]!=0)
+ US_DEBUGP("%s\n", string);
+ }
+ }
+
+
+ US_DEBUGP("SCM data %s transfer %d sg buffers %d\n",
+ ( direction==SCSI_DATA_READ ? "in" : "out"),
+ len, use_sg);
+
+ if (!use_sg)
+ result = usbat_raw_bulk(us, direction, data, len);
+ else {
+ sg = (struct scatterlist *)data;
+ for (i=0; i<use_sg && transferred<len; i++) {
+ result = usbat_raw_bulk(us, direction,
+ sg[i].address,
+ len-transferred > sg[i].length ?
+ sg[i].length : len-transferred);
+ if (result!=US_BULK_TRANSFER_GOOD)
+ break;
+ transferred += sg[i].length;
+ }
+ }
+
+ return result;
+}
+
+int usbat_read(struct us_data *us,
+ unsigned char access,
+ unsigned char reg,
+ unsigned char *content) {
+
+ int result;
+ unsigned char command[8] = {
+ 0xC0, access, reg, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ result = usbat_send_control(us,
+ usb_rcvctrlpipe(us->pusb_dev,0),
+ access,
+ 0xC0,
+ (u16)reg,
+ 0,
+ content,
+ 1);
+
+ // result = usbat_send_control(us, command, content, 1);
+
+ return result;
+}
+
+int usbat_write(struct us_data *us,
+ unsigned char access,
+ unsigned char reg,
+ unsigned char content) {
+
+ int result;
+ unsigned char command[8] = {
+ 0x40, access|0x01, reg, content, 0x00, 0x00, 0x00, 0x00
+ };
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ access|0x01,
+ 0x40,
+ short_pack(reg, content),
+ 0,
+ NULL,
+ 0);
+
+ // result = usbat_send_control(us, command, NULL, 0);
+
+ return result;
+}
+
+int usbat_set_shuttle_features(struct us_data *us,
+ unsigned char external_trigger,
+ unsigned char epp_control,
+ unsigned char mask_byte,
+ unsigned char test_pattern,
+ unsigned char subcountH,
+ unsigned char subcountL) {
+
+ int result;
+ unsigned char command[8] = {
+ 0x40, 0x81, epp_control, external_trigger,
+ test_pattern, mask_byte, subcountL, subcountH
+ };
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0x80,
+ 0x40,
+ 0,
+ 0,
+ command,
+ 8);
+
+ // result = usbat_bulk_transport(us, command, 8, 0, NULL, 0, 0);
+
+ return result;
+}
+
+int usbat_read_block(struct us_data *us,
+ unsigned char access,
+ unsigned char reg,
+ unsigned char *content,
+ unsigned short len,
+ int use_sg) {
+
+ int result;
+ unsigned char command[8] = {
+ 0xC0, access|0x02, reg, 0x00, 0x00, 0x00,
+ LSB_of(len), MSB_of(len)
+ };
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0x80,
+ 0x40,
+ 0,
+ 0,
+ command,
+ 8);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = usbat_bulk_transport(us,
+ NULL, 0, SCSI_DATA_READ, content, len, use_sg);
+
+ // result = usbat_bulk_transport(us,
+ // command, 8, 0, content, len, use_sg);
+
+ return result;
+}
+
+/*
+ * Block, waiting for an ATA device to become not busy or to report
+ * an error condition.
+ */
+
+int usbat_wait_not_busy(struct us_data *us) {
+
+ int i;
+ int result;
+ unsigned char status;
+
+ /* Synchronizing cache on a CDR could take a heck of a long time,
+ but probably not more than 15 minutes or so */
+
+ for (i=0; i<500; i++) {
+ result = usbat_read(us, USBAT_ATA, 0x17, &status);
+ US_DEBUGP("SCM: Write ATA data status is %02X\n", status);
+ if (result!=USB_STOR_TRANSPORT_GOOD)
+ return result;
+ if (status&0x01) // check condition
+ return USB_STOR_TRANSPORT_FAILED;
+ if (status&0x20) // device fault
+ return USB_STOR_TRANSPORT_FAILED;
+ if ((status&0x80)!=0x80) // not busy
+ break;
+ if (i<5)
+ wait_ms(100);
+ else if (i<20)
+ wait_ms(500);
+ else if (i<49)
+ wait_ms(1000);
+ else if (i<499)
+ wait_ms(2000);
+ }
+
+ if (i==500)
+ return USB_STOR_TRANSPORT_FAILED;
+
+ return USB_STOR_TRANSPORT_GOOD;
+}
+
+int usbat_write_block(struct us_data *us,
+ unsigned char access,
+ unsigned char reg,
+ unsigned char *content,
+ unsigned short len,
+ int use_sg) {
+
+ int result;
+ unsigned char command[8] = {
+ 0x40, access|0x03, reg, 0x00, 0x00, 0x00,
+ LSB_of(len), MSB_of(len)
+ };
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0x80,
+ 0x40,
+ 0,
+ 0,
+ command,
+ 8);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = usbat_bulk_transport(us,
+ NULL, 0, SCSI_DATA_WRITE, content, len, use_sg);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ // result = usbat_bulk_transport(us,
+ // command, 8, 0, content, len, use_sg);
+
+ return usbat_wait_not_busy(us);
+}
+
+int usbat_write_block_test(struct us_data *us,
+ unsigned char access,
+ unsigned char *registers,
+ unsigned char *data_out,
+ unsigned short num_registers,
+ unsigned char data_reg,
+ unsigned char status_reg,
+ unsigned char qualifier,
+ unsigned char timeout,
+ unsigned char *content,
+ unsigned short len,
+ int use_sg) {
+
+ int result;
+
+ // Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
+ // but that's what came out of the trace.
+
+ unsigned char command[16] = {
+ 0x40, access|0x07, 0x07, 0x17, 0xfc, 0xe7,
+ LSB_of(num_registers*2), MSB_of(num_registers*2),
+ 0x40, access|0x05, data_reg, status_reg,
+ qualifier, timeout, LSB_of(len), MSB_of(len)
+ };
+ int i;
+ unsigned char data[num_registers*2];
+ int transferred;
+ struct scatterlist *sg;
+ char string[64];
+
+ for (i=0; i<num_registers; i++) {
+ data[i<<1] = registers[i];
+ data[1+(i<<1)] = data_out[i];
+ }
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0x80,
+ 0x40,
+ 0,
+ 0,
+ command,
+ 16);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = usbat_bulk_transport(us,
+ NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0);
+
+ // result = usbat_bulk_transport(us,
+ // command, 16, 0, data, num_registers*2, 0);
+
+ if (result!=USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ // transferred = 0;
+
+ US_DEBUGP("Transfer out %d bytes, sg buffers %d\n",
+ len, use_sg);
+
+ result = usbat_bulk_transport(us,
+ NULL, 0, SCSI_DATA_WRITE, content, len, use_sg);
+
+/*
+ if (!use_sg) {
+
+ // Debug-print the first 48 bytes of the transfer
+
+ string[0] = 0;
+ for (i=0; i<len && i<48; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ content[i]);
+ if ((i%16)==15) {
+ US_DEBUGP("%s\n", string);
+ string[0] = 0;
+ }
+ }
+ if (string[0]!=0)
+ US_DEBUGP("%s\n", string);
+
+ result = usbat_raw_bulk(us, SCSI_DATA_WRITE, content, len);
+
+ } else {
+
+ sg = (struct scatterlist *)content;
+ for (i=0; i<use_sg && transferred<len; i++) {
+ result = usbat_raw_bulk(us, SCSI_DATA_WRITE,
+ sg[i].address,
+ len-transferred > sg[i].length ?
+ sg[i].length : len-transferred);
+ if (result!=US_BULK_TRANSFER_GOOD)
+ break;
+ transferred += sg[i].length;
+ }
+ }
+*/
+ if (result!=USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ return usbat_wait_not_busy(us);
+}
+
+int usbat_multiple_write(struct us_data *us,
+ unsigned char access,
+ unsigned char *registers,
+ unsigned char *data_out,
+ unsigned short num_registers) {
+
+ int result;
+ unsigned char data[num_registers*2];
+ int i;
+ unsigned char command[8] = {
+ 0x40, access|0x07, 0x00, 0x00, 0x00, 0x00,
+ LSB_of(num_registers*2), MSB_of(num_registers*2)
+ };
+
+ for (i=0; i<num_registers; i++) {
+ data[i<<1] = registers[i];
+ data[1+(i<<1)] = data_out[i];
+ }
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0x80,
+ 0x40,
+ 0,
+ 0,
+ command,
+ 8);
+
+ if (result != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ result = usbat_bulk_transport(us,
+ NULL, 0, SCSI_DATA_WRITE, data, num_registers*2, 0);
+
+ // result = usbat_bulk_transport(us, cmd, 8, 0,
+ // data, num_registers*2, 0);
+
+ if (result!=USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ return usbat_wait_not_busy(us);
+}
+
+int usbat_read_user_io(struct us_data *us,
+ unsigned char *data_flags) {
+
+ unsigned char command[8] = {
+ 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int result;
+
+ result = usbat_send_control(us,
+ usb_rcvctrlpipe(us->pusb_dev,0),
+ 0x82,
+ 0xC0,
+ 0,
+ 0,
+ data_flags,
+ 1);
+
+ // result = usbat_send_control(us, command, data_flags, 1);
+
+ return result;
+}
+
+int usbat_write_user_io(struct us_data *us,
+ unsigned char enable_flags,
+ unsigned char data_flags) {
+
+ unsigned char command[8] = {
+ 0x40, 0x82, enable_flags, data_flags, 0x00, 0x00, 0x00, 0x00
+ };
+ int result;
+
+ result = usbat_send_control(us,
+ usb_sndctrlpipe(us->pusb_dev,0),
+ 0x82,
+ 0x40,
+ short_pack(enable_flags, data_flags),
+ 0,
+ NULL,
+ 0);
+
+ // result = usbat_send_control(us, command, NULL, 0);
+
+ return result;
+}
+
+static int hp_8200e_select_and_test_registers(struct us_data *us) {
+
+ int result;
+ int selector;
+ unsigned char status;
+
+ // try device = master, then device = slave.
+
+ for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
+
+ if ( (result = usbat_write(us, USBAT_ATA, 0x16, selector)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x17, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x16, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_write(us, USBAT_ATA, 0x14, 0x55)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_write(us, USBAT_ATA, 0x15, 0xAA)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x15, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+ }
+
+ return result;
+}
+
+static int init_8200e(struct us_data *us) {
+
+ int result;
+ unsigned char status;
+
+ // Enable peripheral control signals
+
+ if ( (result = usbat_write_user_io(us,
+ USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 1\n");
+
+ wait_ms(2000);
+
+ if ( (result = usbat_read_user_io(us, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 2\n");
+
+ if ( (result = usbat_read_user_io(us, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 3\n");
+
+ // Reset peripheral, enable periph control signals
+ // (bring reset signal up)
+
+ if ( (result = usbat_write_user_io(us,
+ USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 4\n");
+
+ // Enable periph control signals
+ // (bring reset signal down)
+
+ if ( (result = usbat_write_user_io(us,
+ USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 5\n");
+
+ wait_ms(250);
+
+ // Write 0x80 to ISA port 0x3F
+
+ if ( (result = usbat_write(us, USBAT_ISA, 0x3F, 0x80)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 6\n");
+
+ // Read ISA port 0x27
+
+ if ( (result = usbat_read(us, USBAT_ISA, 0x27, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 7\n");
+
+ if ( (result = usbat_read_user_io(us, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 8\n");
+
+ if ( (result = hp_8200e_select_and_test_registers(us)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 9\n");
+
+ if ( (result = usbat_read_user_io(us, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 10\n");
+
+ // Enable periph control signals and card detect
+
+ if ( (result = usbat_write_user_io(us,
+ USBAT_UIO_ACKD |USBAT_UIO_OE1 | USBAT_UIO_OE0,
+ USBAT_UIO_EPAD | USBAT_UIO_1)) != USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 11\n");
+
+ if ( (result = usbat_read_user_io(us, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 12\n");
+
+ wait_ms(1400);
+
+ if ( (result = usbat_read_user_io(us, &status)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 13\n");
+
+ if ( (result = hp_8200e_select_and_test_registers(us)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 14\n");
+
+ if ( (result = usbat_set_shuttle_features(us,
+ 0x83, 0x00, 0x88, 0x08, 0x15, 0x14)) !=
+ USB_STOR_TRANSPORT_GOOD)
+ return result;
+
+ US_DEBUGP("INIT 15\n");
+
+ return result;
+}
+
+/*
+ * Transport for the HP 8200e
+ */
+int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us)
+{
+ int result;
+ unsigned char status;
+ unsigned char registers[32];
+ unsigned char data[32];
+ unsigned int len;
+ int i;
+ char string[64];
+
+ /* This table tells us:
+ X = command not supported
+ L = return length in cmnd[4] (8 bits).
+ H = return length in cmnd[7] and cmnd[8] (16 bits).
+ D = return length in cmnd[6] to cmnd[9] (32 bits).
+ B = return length/blocksize in cmnd[6] to cmnd[8].
+ T = return length in cmnd[6] to cmnd[8] (24 bits).
+ 0-9 = fixed return length
+ W = 24 bytes
+ h = return length/2048 in cmnd[7-8].
+ */
+
+ static char *lengths =
+
+ /* 0123456789ABCDEF 0123456789ABCDEF */
+
+ "0XXL0XXXXXXXXXXX" "XXLXXXXXXXX0XX0X" /* 00-1F */
+ "XXXXX8XXhXH0XXX0" "XXXXX0XXXXXXXXXX" /* 20-3F */
+ "XXHHL0X0XXH0XX0X" "XHH00HXX0TH0H0XX" /* 40-5F */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 60-7F */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* 80-9F */
+ "X0XXX0XXDXDXXXXX" "XXXXXXXXX000XHBX" /* A0-BF */
+ "XXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXX" /* C0-DF */
+ "XDXXXXXXXXXXXXXX" "XXW00HXXXXXXXXXX"; /* E0-FF */
+
+ if (us->flags & US_FL_NEED_INIT) {
+ US_DEBUGP("8200e: initializing\n");
+ init_8200e(us);
+ us->flags &= ~US_FL_NEED_INIT;
+ }
+
+ len = srb->request_bufflen;
+
+/* if (srb->sc_data_direction == SCSI_DATA_WRITE)
+ len = srb->request_bufflen;
+ else {
+
+ switch (lengths[srb->cmnd[0]]) {
+
+ case 'L':
+ len = srb->cmnd[4];
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ len = lengths[srb->cmnd[0]]-'0';
+ break;
+ case 'H':
+ len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
+ break;
+ case 'h':
+ len = (((unsigned int)srb->cmnd[7])<<8) | srb->cmnd[8];
+ len <<= 11; // *2048
+ break;
+ case 'T':
+ len = (((unsigned int)srb->cmnd[6])<<16) |
+ (((unsigned int)srb->cmnd[7])<<8) |
+ srb->cmnd[8];
+ break;
+ case 'D':
+ len = (((unsigned int)srb->cmnd[6])<<24) |
+ (((unsigned int)srb->cmnd[7])<<16) |
+ (((unsigned int)srb->cmnd[8])<<8) |
+ srb->cmnd[9];
+ break;
+ case 'W':
+ len = 24;
+ break;
+ case 'B':
+ // Let's try using the command structure's
+ // request_bufflen here
+ len = srb->request_bufflen;
+ break;
+ default:
+ US_DEBUGP("Error: UNSUPPORTED COMMAND %02X\n",
+ srb->cmnd[0]);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+ } */
+
+ if (len > 0xFFFF) {
+ US_DEBUGP("Error: len = %08X... what do I do now?\n",
+ len);
+ return USB_STOR_TRANSPORT_ERROR;
+ }
+
+ // US_DEBUGP("XXXXXXXXXXXXXXXX req_bufflen %d, len %d, bufflen %d\n",
+ // srb->request_bufflen, len, srb->bufflen);
+
+ /* Send A0 (ATA PACKET COMMAND).
+ Note: I guess we're never going to get any of the ATA
+ commands... just ATA Packet Commands.
+ */
+
+ registers[0] = 0x11;
+ registers[1] = 0x12;
+ registers[2] = 0x13;
+ registers[3] = 0x14;
+ registers[4] = 0x15;
+ registers[5] = 0x16;
+ registers[6] = 0x17;
+ data[0] = 0x00;
+ data[1] = 0x00;
+ data[2] = 0x00;
+ data[3] = len&0xFF; // (cylL) = expected length (L)
+ data[4] = (len>>8)&0xFF; // (cylH) = expected length (H)
+ data[5] = 0xB0; // (device sel) = slave
+ data[6] = 0xA0; // (command) = ATA PACKET COMMAND
+
+ if (srb->sc_data_direction == SCSI_DATA_WRITE) {
+
+ for (i=7; i<19; i++) {
+ registers[i] = 0x10;
+ data[i] = (i-7 >= srb->cmd_len) ? 0 : srb->cmnd[i-7];
+ }
+
+ result = usbat_write_block_test(us, USBAT_ATA,
+ registers, data, 19,
+ 0x10, 0x17, 0xFD, 0x30,
+ srb->request_buffer,
+ len, srb->use_sg);
+
+ return result;
+ }
+
+ if ( (result = usbat_multiple_write(us,
+ USBAT_ATA,
+ registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
+ return result;
+ }
+
+ // Write the 12-byte command header.
+
+ if ( (result = usbat_write_block(us,
+ USBAT_ATA, 0x10, srb->cmnd, 12, 0)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ return result;
+ }
+
+ // If there is response data to be read in
+ // then do it here.
+
+ if (len != 0 && (srb->sc_data_direction == SCSI_DATA_READ)) {
+
+ // How many bytes to read in? Check cylL register
+
+ if ( (result = usbat_read(us, USBAT_ATA, 0x14, &status)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ return result;
+ }
+
+ if (len>0xFF) { // need to read cylH also
+ len = status;
+ if ( (result = usbat_read(us, USBAT_ATA, 0x15,
+ &status)) !=
+ USB_STOR_TRANSPORT_GOOD) {
+ return result;
+ }
+ len += ((unsigned int)status)<<8;
+ }
+ else
+ len = status;
+
+
+ result = usbat_read_block(us, USBAT_ATA, 0x10,
+ srb->request_buffer, len, srb->use_sg);
+
+ /* Debug-print the first 32 bytes of the transfer */
+
+ if (!srb->use_sg) {
+ string[0] = 0;
+ for (i=0; i<len && i<32; i++) {
+ sprintf(string+strlen(string), "%02X ",
+ ((unsigned char *)srb->request_buffer)[i]);
+ if ((i%16)==15) {
+ US_DEBUGP("%s\n", string);
+ string[0] = 0;
+ }
+ }
+ if (string[0]!=0)
+ US_DEBUGP("%s\n", string);
+ }
+ }
+
+ // US_DEBUGP("Command result %d\n", result);
+
+ return result;
+}
+
+
--- /dev/null
+/* Driver for SCM Microsystems USB-ATAPI cable
+ * Header File
+ *
+ * Current development and maintainance by:
+ * (c) 2000 Robert Baruch (autophile@dol.net)
+ *
+ * See scm.c for more explanation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _USB_SHUTTLE_USBAT_H
+#define _USB_SHUTTLE_USBAT_H
+
+#define USBAT_EPP_PORT 0x10
+#define USBAT_EPP_REGISTER 0x30
+#define USBAT_ATA 0x40
+#define USBAT_ISA 0x50
+
+/* SCM User I/O Data registers */
+
+#define USBAT_UIO_EPAD 0x80 // Enable Peripheral Control Signals
+#define USBAT_UIO_CDT 0x40 // Card Detect (Read Only)
+ // CDT = ACKD & !UI1 & !UI0
+#define USBAT_UIO_1 0x20 // I/O 1
+#define USBAT_UIO_0 0x10 // I/O 0
+#define USBAT_UIO_EPP_ATA 0x08 // 1=EPP mode, 0=ATA mode
+#define USBAT_UIO_UI1 0x04 // Input 1
+#define USBAT_UIO_UI0 0x02 // Input 0
+#define USBAT_UIO_INTR_ACK 0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP)
+
+/* SCM User I/O Enable registers */
+
+#define USBAT_UIO_DRVRST 0x80 // Reset Peripheral
+#define USBAT_UIO_ACKD 0x40 // Enable Card Detect
+#define USBAT_UIO_OE1 0x20 // I/O 1 set=output/clr=input
+ // If ACKD=1, set OE1 to 1 also.
+#define USBAT_UIO_OE0 0x10 // I/O 0 set=output/clr=input
+#define USBAT_UIO_ADPRST 0x01 // Reset SCM chip
+
+/* USBAT-specific commands */
+
+extern int usbat_read(struct us_data *us, unsigned char access,
+ unsigned char reg, unsigned char *content);
+extern int usbat_write(struct us_data *us, unsigned char access,
+ unsigned char reg, unsigned char content);
+extern int usbat_read_block(struct us_data *us, unsigned char access,
+ unsigned char reg, unsigned char *content, unsigned short len,
+ int use_sg);
+extern int usbat_write_block(struct us_data *us, unsigned char access,
+ unsigned char reg, unsigned char *content, unsigned short len,
+ int use_sg);
+extern int usbat_multiple_write(struct us_data *us, unsigned char access,
+ unsigned char *registers, unsigned char *data_out,
+ unsigned short num_registers);
+extern int usbat_read_user_io(struct us_data *us, unsigned char *data_flags);
+extern int usbat_write_user_io(struct us_data *us,
+ unsigned char enable_flags, unsigned char data_flags);
+
+/* HP 8200e stuff */
+
+extern int hp8200e_transport(Scsi_Cmnd *srb, struct us_data *us);
+
+#endif
/* Driver for USB Mass Storage compliant devices
*
- * $Id: transport.c,v 1.3 2000/07/20 01:06:40 mdharm Exp $
+ * $Id: transport.c,v 1.4 2000/07/25 23:04:47 mdharm Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
int pipe;
/* calculate the appropriate pipe information */
- if (US_DIRECTION(us->srb->cmnd[0]))
+ if (us->srb->sc_data_direction == SCSI_DATA_READ)
pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
else
pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
* function simply determines if we're going to use scatter-gather or not,
* and acts appropriately. For now, it also re-interprets the error codes.
*/
-static void us_transfer(Scsi_Cmnd *srb, struct us_data* us, int dir_in)
+static void us_transfer(Scsi_Cmnd *srb, struct us_data* us)
{
int i;
int result = -1;
if (need_auto_sense) {
int temp_result;
void* old_request_buffer;
- int old_sg;
- int old_request_bufflen;
+ unsigned short old_sg;
+ unsigned old_request_bufflen;
+ unsigned char old_sc_data_direction;
unsigned char old_cmnd[MAX_COMMAND_SIZE];
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
srb->cmnd[4] = 18;
srb->cmnd[5] = 0;
- /* set the buffer length for transfer */
+ /* set the transfer direction */
+ old_sc_data_direction = srb->sc_data_direction;
+ srb->sc_data_direction = SCSI_DATA_READ;
+
+ /* use the new buffer we have */
old_request_buffer = srb->request_buffer;
+ srb->request_buffer = srb->sense_buffer;
+
+ /* set the buffer length for transfer */
old_request_bufflen = srb->request_bufflen;
+ srb->request_bufflen = 18;
+
+ /* set up for no scatter-gather use */
old_sg = srb->use_sg;
srb->use_sg = 0;
- srb->request_bufflen = 18;
- srb->request_buffer = srb->sense_buffer;
/* issue the auto-sense command */
temp_result = us->transport(us->srb, us);
srb->request_buffer = old_request_buffer;
srb->request_bufflen = old_request_bufflen;
srb->use_sg = old_sg;
+ srb->sc_data_direction = old_sc_data_direction;
memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
/* If things are really okay, then let's show that */
/* DATA STAGE */
/* transfer the data payload for this command, if one exists*/
if (us_transfer_length(srb, us)) {
- us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
+ us_transfer(srb, us);
US_DEBUGP("CBI data stage result is 0x%x\n", srb->result);
/* if it was aborted, we need to indicate that */
/* DATA STAGE */
/* transfer the data payload for this command, if one exists*/
if (us_transfer_length(srb, us)) {
- us_transfer(srb, us, US_DIRECTION(srb->cmnd[0]));
+ us_transfer(srb, us);
US_DEBUGP("CB data stage result is 0x%x\n", srb->result);
/* if it was aborted, we need to indicate that */
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb.DataTransferLength = cpu_to_le32(us_transfer_length(srb, us));
- bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
+ bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
bcb.Tag = srb->serial_number;
bcb.Lun = srb->cmnd[1] >> 5;
bcb.Length = srb->cmd_len;
if (result == 0) {
/* send/receive data payload, if there is any */
if (bcb.DataTransferLength) {
- us_transfer(srb, us, bcb.Flags);
+ us_transfer(srb, us);
US_DEBUGP("Bulk data transfer result 0x%x\n",
srb->result);
/* Driver for USB Mass Storage compliant devices
* Transport Functions Header File
*
- * $Id: transport.h,v 1.4 2000/07/23 18:40:38 groovyjava Exp $
+ * $Id: transport.h,v 1.6 2000/07/27 14:42:43 groovyjava Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
#include "usb.h"
#include "scsi.h"
-/* bit set if input */
-extern unsigned char us_direction[256/8];
-#define US_DIRECTION(x) ((us_direction[x>>3] >> (x & 7)) & 1)
-
/* Protocols */
#define US_PR_CBI 0x00 /* Control/Bulk/Interrupt */
#define US_PR_SCM_ATAPI 0x80 /* SCM-ATAPI bridge */
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
-#define US_PR_SCM_SCSI 0x81 /* SCM-SCSI bridge */
+#define US_PR_EUSB_SDDR09 0x81 /* SCM-SCSI bridge for
+ SDDR-09 */
#endif
/*
/* Driver for USB Mass Storage compliant devices
*
- * $Id: usb.c,v 1.11 2000/07/24 20:37:24 mdharm Exp $
+ * $Id: usb.c,v 1.14 2000/07/27 14:42:43 groovyjava Exp $
*
* Current development and maintainance by:
* (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
#include "transport.h"
#include "protocol.h"
#include "debug.h"
-#if defined(CONFIG_USB_STORAGE_HP8200e) || defined(CONFIG_USB_STORAGE_SDDR09)
-#include "scm.h"
+#ifdef CONFIG_USB_STORAGE_HP8200e
+#include "shuttle_usbat.h"
+#endif
+#ifdef CONFIG_USB_STORAGE_SDDR09
+#include "sddr09.h"
#endif
#include <linux/module.h>
/* signal that we've started the thread */
up(&(us->notify));
+ set_current_state(TASK_INTERRUPTIBLE);
for(;;) {
- set_current_state(TASK_INTERRUPTIBLE);
US_DEBUGP("*** thread sleeping.\n");
schedule();
US_DEBUGP("*** thread awakened.\n");
switch (action) {
case US_ACT_COMMAND:
+ /* reject the command if the direction indicator
+ * is UNKNOWN
+ */
+ if (us->srb->sc_data_direction == SCSI_DATA_UNKNOWN) {
+ US_DEBUGP("UNKNOWN data direction\n");
+ us->srb->result = DID_ERROR;
+ set_current_state(TASK_INTERRUPTIBLE);
+ us->srb->scsi_done(us->srb);
+ us->srb = NULL;
+ break;
+ }
+
/* reject if target != 0 or if LUN is higher than
* the maximum known LUN
*/
if (us->srb->target || (us->srb->lun > us->max_lun)) {
US_DEBUGP("Bad device number (%d/%d)\n",
us->srb->target, us->srb->lun);
-
us->srb->result = DID_BAD_TARGET << 16;
+ set_current_state(TASK_INTERRUPTIBLE);
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
if ((us->srb->cmnd[0] == START_STOP) &&
(us->flags & US_FL_START_STOP)) {
us->srb->result = GOOD;
+
+ set_current_state(TASK_INTERRUPTIBLE);
us->srb->scsi_done(us->srb);
us->srb = NULL;
break;
if (us->srb->result != DID_ABORT << 16) {
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
+ set_current_state(TASK_INTERRUPTIBLE);
us->srb->scsi_done(us->srb);
} else {
US_DEBUGP("scsi command aborted\n");
+ set_current_state(TASK_INTERRUPTIBLE);
up(&(us->notify));
}
us->srb = NULL;
US_SC_UFI, US_PR_CBI, US_FL_SINGLE_LUN},
{ 0x0693, 0x0002, 0x0100, 0x0100, "Hagiwara FlashGate SmartMedia",
US_SC_SCSI, US_PR_BULK, US_FL_ALT_LENGTH},
- { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-01)",
+ { 0x0781, 0x0001, 0x0200, 0x0200, "Sandisk ImageMate (SDDR-05a)",
US_SC_SCSI, US_PR_CB, US_FL_SINGLE_LUN | US_FL_START_STOP},
#ifdef CONFIG_USB_STORAGE_SDDR09
{ 0x0781, 0x0200, 0x0100, 0x0100, "Sandisk ImageMate (SDDR-09)",
- US_SC_SCSI, US_PR_SCM_SCSI,
- US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_NEED_INIT},
+ US_SC_SCSI, US_PR_EUSB_SDDR09,
+ US_FL_SINGLE_LUN | US_FL_START_STOP},
#endif
{ 0x0781, 0x0002, 0x0009, 0x0009, "Sandisk Imagemate (SDDR-31)",
US_SC_SCSI, US_PR_BULK, US_FL_IGNORE_SER},
/* set the interface -- STALL is an acceptable response here */
#ifdef CONFIG_USB_STORAGE_SDDR09
- if (protocol != US_PR_SCM_SCSI)
+ if (protocol != US_PR_EUSB_SDDR09)
result = usb_set_interface(dev,
altsetting->bInterfaceNumber, 0);
else
#endif
#ifdef CONFIG_USB_STORAGE_SDDR09
- case US_PR_SCM_SCSI:
- ss->transport_name = "SCM/SCSI";
+ case US_PR_EUSB_SDDR09:
+ ss->transport_name = "EUSB/SDDR09";
ss->transport = sddr09_transport;
ss->transport_reset = usb_stor_CB_reset;
ss->max_lun = 1;
module_init(usb_stor_init) ;
module_exit(usb_stor_exit) ;
+
+MODULE_AUTHOR("Michael Gee <michael@linuxspecific.com>, David L. Brown, Jr. <usb-storage@davidb.org>, Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
+MODULE_DESCRIPTION("USB Mass Storage driver");
static int debug = 1;
MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
static kmem_cache_t *uhci_td_cachep;
static kmem_cache_t *uhci_qh_cachep;
pm_unregister_all(handle_pm_event);
uhci_cleanup();
}
+
+MODULE_AUTHOR("Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber");
+MODULE_DESCRIPTION("USB Universal Host Controller Interface driver");
#endif //MODULE
*/
#include <linux/adb.h>
#include <linux/pmu.h>
+#ifndef CONFIG_PM
+#define CONFIG_PM
+#endif
#endif
int i, size = 0;
unsigned long flags;
- if (!urb->dev || !urb->dev->bus) return -EINVAL;
+ if (!urb->dev || !urb->dev->bus)
+ return -EINVAL;
- if (urb->hcpriv) return -EINVAL; /* urb already in use */
+ if (urb->hcpriv) /* urb already in use */
+ return -EINVAL;
// if(usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe)))
// return -EPIPE;
/* when controller's hung, permit only roothub cleanup attempts
* such as powering down ports */
- if (ohci->disabled)
+ if (ohci->disabled) {
+ usb_dec_dev_use (urb->dev);
return -ESHUTDOWN;
+ }
/* every endpoint has a ed, locate and fill it */
if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
#endif
- if (urb->complete) urb->complete (urb);
+ if (urb->complete)
+ urb->complete (urb);
+ usb_dec_dev_use (urb->dev);
return 0;
}
ohci->ohci_dev->slot_name);
// e.g. due to PCI Master/Target Abort
-#ifndef DEBUG
+#ifdef DEBUG
+ ohci_dump (ohci, 1);
+#else
// FIXME: be optimistic, hope that bug won't repeat often.
// Make some non-interrupt context restart the controller.
// Count and limit the retries though; either hardware or
}
writel (ints, ®s->intrstatus);
writel (OHCI_INTR_MIE, ®s->intrenable);
+
+ /* FIXME: check URB timeouts */
}
/*-------------------------------------------------------------------------*/
ohci_t * ohci;
struct usb_bus * bus;
- ohci = (ohci_t *) __get_free_pages (GFP_KERNEL, 1);
+ ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
if (!ohci)
return NULL;
bus = usb_alloc_bus (&sohci_device_operations);
if (!bus) {
- free_pages ((unsigned long) ohci, 1);
+ kfree (ohci);
return NULL;
}
/* unmap the IO address space */
iounmap (ohci->regs);
- free_pages ((unsigned long) ohci, 1);
+ kfree (ohci);
}
/*-------------------------------------------------------------------------*/
static int __devinit
ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
{
- unsigned long mem_resource;
+ unsigned long mem_resource, mem_len;
u8 latency, limit;
void *mem_base;
if (pci_enable_device(dev) < 0)
return -ENODEV;
+ /* we read its hardware registers as memory */
+ mem_resource = pci_resource_start(dev, 0);
+ mem_len = pci_resource_len(dev, 0);
+ if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
+ dbg ("controller already in use");
+ return -EBUSY;
+ }
+
+ mem_base = ioremap_nocache (mem_resource, mem_len);
+ if (!mem_base) {
+ err("Error mapping OHCI memory");
+ return -EFAULT;
+ }
+
/* controller writes into our memory */
pci_set_master (dev);
pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
}
}
- /* we read its hardware registers as memory */
- mem_resource = pci_resource_start(dev, 0);
- /* request_mem_region ... */
- mem_base = ioremap_nocache (mem_resource, 4096);
- if (!mem_base) {
- err("Error mapping OHCI memory");
- return -EFAULT;
- }
-
return hc_found_ohci (dev, dev->irq, mem_base);
}
&ohci->regs->control);
hc_release_ohci (ohci);
+
+ release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
}
/*-------------------------------------------------------------------------*/
-static const struct __devinitdata pci_device_id ohci_pci_ids [] = { {
+static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
/* handle any USB OHCI controller */
class: ((PCI_CLASS_SERIAL_USB << 8) | 0x10),
#endif /* MODULE */
+MODULE_AUTHOR ("Roman Weissgaerber <weissg@vienna.at>");
MODULE_DESCRIPTION ("USB OHCI Host Controller Driver");
uhci_cleanup ();
}
+MODULE_AUTHOR("Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber");
+MODULE_DESCRIPTION("USB Universal Host Controller Interface driver");
#endif //MODULE
#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("USB HID Boot Protocol keyboard driver");
static unsigned char usb_kbd_keycode[256] = {
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("USB HID Boot Protocol mouse driver");
struct usb_mouse {
signed char data[8];
#include <linux/usb.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("USB Wacom Graphire and Wacom Intuos tablet driver");
/*
* Wacom Graphire packet:
v.blue.offset = 0;
#endif
v.red.length = 5;
- v.green.length = 5;
+ v.green.length = 6;
v.blue.length = 5;
break;
#endif
((green & 0xf800) << 2) | ((blue & 0xf800) >> 3);
#else
rivainfo->con_cmap.cfb16[regno] =
- ((red & 0xf800) >> 1) |
- ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
+ ((red & 0xf800) >> 0) |
+ ((green & 0xf800) >> 5) | ((blue & 0xf800) >> 11);
#endif
break;
#endif /* FBCON_HAS_CFB16 */
retval = PTR_ERR(interpreter);
if (IS_ERR(interpreter))
goto out_free_interp;
- retval = kernel_read(interpreter, 0, bprm->buf, 128);
+ retval = kernel_read(interpreter, 0, bprm->buf, BINPRM_BUF_SIZE);
if (retval < 0)
goto out_free_dentry;
{
struct binfmt_entry *fmt;
struct file * file;
- char iname[128];
+ char iname[BINPRM_BUF_SIZE];
char *iname_addr = iname;
int retval;
read_lock(&entries_lock);
fmt = check_file(bprm);
if (fmt) {
- strncpy(iname, fmt->interpreter, 127);
- iname[127] = '\0';
+ strncpy(iname, fmt->interpreter, BINPRM_BUF_SIZE - 1);
+ iname[BINPRM_BUF_SIZE - 1] = '\0';
}
read_unlock(&entries_lock);
if (!fmt)
/* more sanity checks */
if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
- (e->size < 1) || ((e->size + e->offset) > 127) ||
+ (e->size < 1) || ((e->size + e->offset) > (BINPRM_BUF_SIZE - 1)) ||
!(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
goto free_err;
{
char *cp, *i_name, *i_arg;
struct file *file;
- char interp[128];
+ char interp[BINPRM_BUF_SIZE];
int retval;
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang))
fput(bprm->file);
bprm->file = NULL;
- bprm->buf[127] = '\0';
+ bprm->buf[BINPRM_BUF_SIZE - 1] = '\0';
if ((cp = strchr(bprm->buf, '\n')) == NULL)
- cp = bprm->buf+127;
+ cp = bprm->buf+BINPRM_BUF_SIZE-1;
*cp = '\0';
while (cp > bprm->buf) {
cp--;
page_cache_get(page);
}
+/*
+ * We are taking a block for data and we don't want any output from any
+ * buffer-cache aliases starting from return from that function and
+ * until the moment when something will explicitly mark the buffer
+ * dirty (hopefully that will not happen until we will free that block ;-)
+ * We don't even need to mark it not-uptodate - nobody can expect
+ * anything from a newly allocated buffer anyway. We used to used
+ * unmap_buffer() for such invalidation, but that was wrong. We definitely
+ * don't want to mark the alias unmapped, for example - it would confuse
+ * anyone who might pick it with bread() afterwards...
+ */
+
static void unmap_underlying_metadata(struct buffer_head * bh)
{
struct buffer_head *old_bh;
old_bh = get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size);
if (old_bh) {
- unmap_buffer(old_bh);
+ mark_buffer_clean(old_bh);
+ wait_on_buffer(old_bh);
+ clear_bit(BH_Req, &old_bh->b_state);
/* Here we could run brelse or bforget. We use
bforget because it will try to put the buffer
in the freelist. */
* the dcache entry is deleted or garbage collected.
*/
+#include <linux/config.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/fs.h>
char name[20];
sprintf(name, "char-major-%d", major);
request_module(name);
- }
- read_lock(&chrdevs_lock);
- ret = fops_get(chrdevs[major].fops);
- read_unlock(&chrdevs_lock);
+ read_lock(&chrdevs_lock);
+ ret = fops_get(chrdevs[major].fops);
+ read_unlock(&chrdevs_lock);
+ }
#endif
return ret;
}
/*
* Fill the binprm structure from the inode.
- * Check permissions, then read the first 512 bytes
+ * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
*/
int prepare_binprm(struct linux_binprm *bprm)
{
}
}
- memset(bprm->buf,0,sizeof(bprm->buf));
- return kernel_read(bprm->file,0,bprm->buf,128);
+ memset(bprm->buf,0,BINPRM_BUF_SIZE);
+ return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
}
/*
int retval;
int i;
- bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
- memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
-
file = open_exec(filename);
retval = PTR_ERR(file);
if (IS_ERR(file))
return retval;
+ bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+ memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
+
bprm.file = file;
bprm.filename = filename;
bprm.sh_bang = 0;
#include <linux/locks.h>
#include <linux/quotaops.h>
-
/*
* balloc.c contains the blocks allocation and deallocation routines
*/
((sb->u.ext2_sb.s_resuid != current->fsuid) &&
(sb->u.ext2_sb.s_resgid == 0 ||
!in_group_p (sb->u.ext2_sb.s_resgid)) &&
- !capable(CAP_SYS_RESOURCE))) {
- unlock_super (sb);
- return 0;
- }
+ !capable(CAP_SYS_RESOURCE)))
+ goto out;
ext2_debug ("goal=%lu.\n", goal);
gdp = ext2_get_group_desc (sb, i, &bh2);
if (!gdp) {
*err = -EIO;
- unlock_super (sb);
- return 0;
+ goto out;
}
if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
break;
}
- if (k >= sb->u.ext2_sb.s_groups_count) {
- unlock_super (sb);
- return 0;
- }
+ if (k >= sb->u.ext2_sb.s_groups_count)
+ goto out;
bitmap_nr = load_block_bitmap (sb, i);
if (bitmap_nr < 0)
goto io_error;
if (j >= EXT2_BLOCKS_PER_GROUP(sb)) {
ext2_error (sb, "ext2_new_block",
"Free blocks count corrupted for block group %d", i);
- unlock_super (sb);
- return 0;
+ goto out;
}
search_back:
* Check quota for allocation of this block.
*/
if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) {
- unlock_super(sb);
*err = -EDQUOT;
- return 0;
+ goto out;
}
tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block);
#ifdef EXT2_PREALLOCATE
if (prealloc_block) {
int prealloc_goal;
+ unsigned long next_block = tmp + 1;
prealloc_goal = es->s_prealloc_blocks ?
es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS;
+ /* Writer: ->i_prealloc* */
+ /*
+ * Can't happen right now, will need handling if we go for
+ * per-group spinlocks. Handling == skipping preallocation if
+ * condition below will be true. For now there is no legitimate
+ * way it could happen, thus the BUG().
+ */
+ if (*prealloc_count)
+ BUG();
*prealloc_count = 0;
- *prealloc_block = tmp + 1;
+ *prealloc_block = next_block;
+ /* Writer: end */
for (k = 1;
k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb);
- k++) {
+ k++, next_block++) {
if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
break;
- if (ext2_set_bit (j + k, bh->b_data)) {
+ /* Writer: ->i_prealloc* */
+ if (*prealloc_block + *prealloc_count != next_block ||
+ ext2_set_bit (j + k, bh->b_data)) {
+ /* Writer: end */
DQUOT_FREE_BLOCK(sb, inode, 1);
break;
}
(*prealloc_count)++;
+ /* Writer: end */
}
+ /*
+ * As soon as we go for per-group spinlocks we'll need these
+ * done inside the loop above.
+ */
gdp->bg_free_blocks_count =
cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
- *prealloc_count);
+ (k - 1));
es->s_free_blocks_count =
cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
- *prealloc_count);
+ (k - 1));
ext2_debug ("Preallocated a further %lu bits.\n",
- *prealloc_count);
+ (k - 1));
}
#endif
"block(%d) >= blocks count(%d) - "
"block_group = %d, es == %p ",j,
le32_to_cpu(es->s_blocks_count), i, es);
- unlock_super (sb);
- return 0;
+ goto out;
}
ext2_debug ("allocating block %d. "
io_error:
*err = -EIO;
+out:
unlock_super (sb);
return 0;
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
static loff_t ext2_file_lseek(struct file *, loff_t, int);
static int ext2_open_file (struct inode *, struct file *);
*/
static int ext2_release_file (struct inode * inode, struct file * filp)
{
- if (filp->f_mode & FMODE_WRITE) {
- lock_kernel();
+ if (filp->f_mode & FMODE_WRITE)
ext2_discard_prealloc (inode);
- unlock_kernel();
- }
return 0;
}
*/
void ext2_put_inode (struct inode * inode)
{
- lock_kernel();
ext2_discard_prealloc (inode);
- unlock_kernel();
}
/*
clear_inode(inode); /* We must guarantee clearing of inode... */
}
-#define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)]))
-
-static inline int block_bmap (struct buffer_head * bh, int nr)
-{
- int tmp;
-
- if (!bh)
- return 0;
- tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]);
- brelse (bh);
- return tmp;
-}
-
/*
* ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the
* superblock in the same manner as are ext2_free_blocks and
#ifdef EXT2_PREALLOCATE
unsigned short total;
+ lock_kernel();
if (inode->u.ext2_i.i_prealloc_count) {
total = inode->u.ext2_i.i_prealloc_count;
inode->u.ext2_i.i_prealloc_count = 0;
ext2_free_blocks (inode, inode->u.ext2_i.i_prealloc_block, total);
}
+ unlock_kernel();
#endif
}
return result;
}
-static inline long ext2_block_map (struct inode * inode, long block)
+typedef struct {
+ u32 *p;
+ u32 key;
+ struct buffer_head *bh;
+} Indirect;
+
+static inline void add_chain(Indirect *p, struct buffer_head *bh, u32 *v)
+{
+ p->key = *(p->p = v);
+ p->bh = bh;
+}
+
+static inline int verify_chain(Indirect *from, Indirect *to)
+{
+ while (from <= to && from->key == *from->p)
+ from++;
+ return (from > to);
+}
+
+/**
+ * ext2_block_to_path - parse the block number into array of offsets
+ * @inode: inode in question (we are only interested in its superblock)
+ * @i_block: block number to be parsed
+ * @offsets: array to store the offsets in
+ *
+ * To store the locations of file's data ext2 uses a data structure common
+ * for UNIX filesystems - tree of pointers anchored in the inode, with
+ * data blocks at leaves and indirect blocks in intermediate nodes.
+ * This function translates the block number into path in that tree -
+ * return value is the path length and @offsets[n] is the offset of
+ * pointer to (n+1)th node in the nth one. If @block is out of range
+ * (negative or too large) warning is printed and zero returned.
+ *
+ * Note: function doesn't find node addresses, so no IO is needed. All
+ * we need to know is the capacity of indirect blocks (taken from the
+ * inode->i_sb).
+ */
+
+/*
+ * Portability note: the last comparison (check that we fit into triple
+ * indirect block) is spelled differently, because otherwise on an
+ * architecture with 32-bit longs and 8Kb pages we might get into trouble
+ * if our filesystem had 8Kb blocks. We might use long long, but that would
+ * kill us on x86. Oh, well, at least the sign propagation does not matter -
+ * i_block would have to be negative in the very beginning, so we would not
+ * get there at all.
+ */
+
+static int ext2_block_to_path(struct inode *inode, long i_block, int offsets[4])
{
- int i, ret;
int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
- ret = 0;
- lock_kernel();
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_block_map", "block < 0");
- goto out;
- }
- if (block >= EXT2_NDIR_BLOCKS + ptrs +
- (1 << (ptrs_bits * 2)) +
- ((1 << (ptrs_bits * 2)) << ptrs_bits)) {
- ext2_warning (inode->i_sb, "ext2_block_map", "block > big");
- goto out;
- }
- if (block < EXT2_NDIR_BLOCKS) {
- ret = inode_bmap (inode, block);
- goto out;
- }
- block -= EXT2_NDIR_BLOCKS;
- if (block < ptrs) {
- i = inode_bmap (inode, EXT2_IND_BLOCK);
- if (!i)
- goto out;
- ret = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize), block);
- goto out;
+ const long direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = ptrs,
+ double_blocks = (1 << (ptrs_bits * 2));
+ int n = 0;
+
+ if (i_block < 0) {
+ ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0");
+ } else if (i_block < direct_blocks) {
+ offsets[n++] = i_block;
+ } else if ( (i_block -= direct_blocks) < indirect_blocks) {
+ offsets[n++] = EXT2_IND_BLOCK;
+ offsets[n++] = i_block;
+ } else if ((i_block -= indirect_blocks) < double_blocks) {
+ offsets[n++] = EXT2_DIND_BLOCK;
+ offsets[n++] = i_block >> ptrs_bits;
+ offsets[n++] = i_block & (ptrs - 1);
+ } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
+ offsets[n++] = EXT2_TIND_BLOCK;
+ offsets[n++] = i_block >> (ptrs_bits * 2);
+ offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
+ offsets[n++] = i_block & (ptrs - 1);
+ } else {
+ ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big");
}
- block -= ptrs;
- if (block < (1 << (ptrs_bits * 2))) {
- i = inode_bmap (inode, EXT2_DIND_BLOCK);
- if (!i)
- goto out;
- i = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block >> ptrs_bits);
- if (!i)
- goto out;
- ret = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block & (ptrs - 1));
- goto out;
+ return n;
+}
+
+/**
+ * ext2_get_branch - read the chain of indirect blocks leading to data
+ * @inode: inode in question
+ * @depth: depth of the chain (1 - direct pointer, etc.)
+ * @offsets: offsets of pointers in inode/indirect blocks
+ * @chain: place to store the result
+ * @err: here we store the error value
+ *
+ * Function fills the array of triples <key, p, bh> and returns %NULL
+ * if everything went OK or the pointer to the last filled triple
+ * (incomplete one) otherwise. Upon the return chain[i].key contains
+ * the number of (i+1)-th block in the chain (as it is stored in memory,
+ * i.e. little-endian 32-bit), chain[i].p contains the address of that
+ * number (it points into struct inode for i==0 and into the bh->b_data
+ * for i>0) and chain[i].bh points to the buffer_head of i-th indirect
+ * block for i>0 and NULL for i==0. In other words, it holds the block
+ * numbers of the chain, addresses they were taken from (and where we can
+ * verify that chain did not change) and buffer_heads hosting these
+ * numbers.
+ *
+ * Function stops when it stumbles upon zero pointer (absent block)
+ * (pointer to last triple returned, *@err == 0)
+ * or when it gets an IO error reading an indirect block
+ * (ditto, *@err == -EIO)
+ * or when it notices that chain had been changed while it was reading
+ * (ditto, *@err == -EAGAIN)
+ * or when it reads all @depth-1 indirect blocks successfully and finds
+ * the whole chain, all way to the data (returns %NULL, *err == 0).
+ */
+static inline Indirect *ext2_get_branch(struct inode *inode,
+ int depth,
+ int *offsets,
+ Indirect chain[4],
+ int *err)
+{
+ kdev_t dev = inode->i_dev;
+ int size = inode->i_sb->s_blocksize;
+ Indirect *p = chain;
+ struct buffer_head *bh;
+
+ *err = 0;
+ /* i_data is not going away, no lock needed */
+ add_chain (chain, NULL, inode->u.ext2_i.i_data + *offsets);
+ if (!p->key)
+ goto no_block;
+ /*
+ * switch below is merely an unrolled loop - body should be
+ * repeated depth-1 times. Maybe loop would be actually better,
+ * but that way we get straight execution path in normal cases.
+ * Easy to change, anyway - all cases in switch are literally
+ * identical.
+ */
+ switch (depth) {
+ case 4:
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
+ case 3:
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
+ case 2:
+ bh = bread(dev, le32_to_cpu(p->key), size);
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (u32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
}
- block -= (1 << (ptrs_bits * 2));
- i = inode_bmap (inode, EXT2_TIND_BLOCK);
- if (!i)
- goto out;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (ptrs_bits * 2));
- if (!i)
- goto out;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> ptrs_bits) & (ptrs - 1));
- if (!i)
- goto out;
- ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (ptrs - 1));
-out:
- unlock_kernel();
- return ret;
+ return NULL;
+
+changed:
+ *err = -EAGAIN;
+ goto no_block;
+failure:
+ *err = -EIO;
+no_block:
+ return p;
}
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
{
int ret, err, new;
struct buffer_head *bh;
- unsigned long ptr, phys;
- /*
- * block pointers per block
- */
- unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
- const int direct_blocks = EXT2_NDIR_BLOCKS,
- indirect_blocks = ptrs,
- double_blocks = (1 << (ptrs_bits * 2)),
- triple_blocks = (1 << (ptrs_bits * 3));
+ unsigned long phys;
+ int offsets[4];
+ int *p;
+ Indirect chain[4];
+ Indirect *partial;
+ int depth;
+
+ depth = ext2_block_to_path(inode, iblock, offsets);
+ if (depth == 0)
+ goto abort;
+
+ lock_kernel();
+ partial = ext2_get_branch(inode, depth, offsets, chain, &err);
+
+ if (!partial) {
+ unlock_kernel();
+ for (partial = chain + depth - 1; partial > chain; partial--)
+ brelse(partial->bh);
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key);
+ bh_result->b_state |= (1UL << BH_Mapped);
+ return 0;
+ }
+
+ while (partial > chain) {
+ brelse(partial->bh);
+ partial--;
+ }
if (!create) {
- /*
- * Will clean this up further, ext2_block_map() should use the
- * bh instead of an integer block-number interface.
- */
- phys = ext2_block_map(inode, iblock);
- if (phys) {
- bh_result->b_dev = inode->i_dev;
- bh_result->b_blocknr = phys;
- bh_result->b_state |= (1UL << BH_Mapped);
- }
+ unlock_kernel();
return 0;
}
ret = 0;
bh = NULL;
- lock_kernel();
-
- if (iblock < 0)
- goto abort_negative;
- if (iblock > direct_blocks + indirect_blocks +
- double_blocks + triple_blocks)
- goto abort_too_big;
-
/*
* If this is a sequential block allocation, set the next_alloc_block
* to this block now so that all the indblock and data block
}
err = 0;
- ptr = iblock;
/*
* ok, these macros clean the logic up a bit and make
#define GET_INDIRECT_PTR(x) \
block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
- if (ptr < direct_blocks) {
- bh = GET_INODE_DATABLOCK(ptr);
+ p = offsets;
+ if (depth == 1) {
+ bh = GET_INODE_DATABLOCK(*p);
goto out;
}
- ptr -= direct_blocks;
- if (ptr < indirect_blocks) {
- bh = GET_INODE_PTR(EXT2_IND_BLOCK);
- goto get_indirect;
+ bh = GET_INODE_PTR(*p);
+ switch (depth) {
+ default: /* case 4: */
+ bh = GET_INDIRECT_PTR(*++p);
+ case 3:
+ bh = GET_INDIRECT_PTR(*++p);
+ case 2:
+ bh = GET_INDIRECT_DATABLOCK(*++p);
}
- ptr -= indirect_blocks;
- if (ptr < double_blocks) {
- bh = GET_INODE_PTR(EXT2_DIND_BLOCK);
- goto get_double;
- }
- ptr -= double_blocks;
- bh = GET_INODE_PTR(EXT2_TIND_BLOCK);
- bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2));
-get_double:
- bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1));
-get_indirect:
- bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1));
#undef GET_INODE_DATABLOCK
#undef GET_INODE_PTR
bh_result->b_state |= (1UL << BH_Mapped); /* safe */
if (new)
bh_result->b_state |= (1UL << BH_New);
-abort:
unlock_kernel();
+abort:
return err;
-
-abort_negative:
- ext2_warning (inode->i_sb, "ext2_get_block", "block < 0");
- goto abort;
-
-abort_too_big:
- ext2_warning (inode->i_sb, "ext2_get_block", "block > big");
- goto abort;
}
struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
return 1;
}
-static void ext2_setup_super (struct super_block * sb,
- struct ext2_super_block * es)
+static int ext2_setup_super (struct super_block * sb,
+ struct ext2_super_block * es,
+ int read_only)
{
+ int res = 0;
if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) {
printk ("EXT2-fs warning: revision level too high, "
"forcing read/only mode\n");
- sb->s_flags |= MS_RDONLY;
+ res = MS_RDONLY;
}
- if (!(sb->s_flags & MS_RDONLY)) {
- if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
- printk ("EXT2-fs warning: mounting unchecked fs, "
- "running e2fsck is recommended\n");
- else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
- printk ("EXT2-fs warning: mounting fs with errors, "
- "running e2fsck is recommended\n");
- else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
- le16_to_cpu(es->s_mnt_count) >=
- (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
- printk ("EXT2-fs warning: maximal mount count reached, "
- "running e2fsck is recommended\n");
- else if (le32_to_cpu(es->s_checkinterval) &&
- (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
- printk ("EXT2-fs warning: checktime reached, "
- "running e2fsck is recommended\n");
- es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
- if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
- es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
- es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
- es->s_mtime = cpu_to_le32(CURRENT_TIME);
- mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
- sb->s_dirt = 1;
- if (test_opt (sb, DEBUG))
- printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
- "bpg=%lu, ipg=%lu, mo=%04lx]\n",
- EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
- sb->u.ext2_sb.s_frag_size,
- sb->u.ext2_sb.s_groups_count,
- EXT2_BLOCKS_PER_GROUP(sb),
- EXT2_INODES_PER_GROUP(sb),
- sb->u.ext2_sb.s_mount_opt);
+ if (read_only)
+ return res;
+ if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS))
+ printk ("EXT2-fs warning: mounting unchecked fs, "
+ "running e2fsck is recommended\n");
+ else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS))
+ printk ("EXT2-fs warning: mounting fs with errors, "
+ "running e2fsck is recommended\n");
+ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+ le16_to_cpu(es->s_mnt_count) >=
+ (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
+ printk ("EXT2-fs warning: maximal mount count reached, "
+ "running e2fsck is recommended\n");
+ else if (le32_to_cpu(es->s_checkinterval) &&
+ (le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
+ printk ("EXT2-fs warning: checktime reached, "
+ "running e2fsck is recommended\n");
+ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT2_VALID_FS);
+ if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+ es->s_max_mnt_count = (__s16) cpu_to_le16(EXT2_DFL_MAX_MNT_COUNT);
+ es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+ es->s_mtime = cpu_to_le32(CURRENT_TIME);
+ mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
+ sb->s_dirt = 1;
+ if (test_opt (sb, DEBUG))
+ printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
+ "bpg=%lu, ipg=%lu, mo=%04lx]\n",
+ EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize,
+ sb->u.ext2_sb.s_frag_size,
+ sb->u.ext2_sb.s_groups_count,
+ EXT2_BLOCKS_PER_GROUP(sb),
+ EXT2_INODES_PER_GROUP(sb),
+ sb->u.ext2_sb.s_mount_opt);
#ifdef CONFIG_EXT2_CHECK
- if (test_opt (sb, CHECK)) {
- ext2_check_blocks_bitmap (sb);
- ext2_check_inodes_bitmap (sb);
- }
-#endif
+ if (test_opt (sb, CHECK)) {
+ ext2_check_blocks_bitmap (sb);
+ ext2_check_inodes_bitmap (sb);
}
+#endif
+ return res;
}
static int ext2_check_descriptors (struct super_block * sb)
printk ("EXT2-fs: get root inode failed\n");
return NULL;
}
- ext2_setup_super (sb, es);
+ ext2_setup_super (sb, es, sb->s_flags & MS_RDONLY);
return sb;
}
* by e2fsck since we originally mounted the partition.)
*/
sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
- sb->s_flags &= ~MS_RDONLY;
- ext2_setup_super (sb, es);
+ if (!ext2_setup_super (sb, es, 0))
+ sb->s_flags &= ~MS_RDONLY;
}
return 0;
}
* VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
* Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
* Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
- * Short name translation 1999 by Wolfram Pienkoss <wp@bsz.shk.th.schule.de>
+ * Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
*/
#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
* what file operation caused you trouble and if you can duplicate
* the problem, send a script that demonstrates it.
*
- * Short name translation 1999 by Wolfram Pienkoss <wp@bsz.shk.th.schule.de>
+ * Short name translation 1999 by Wolfram Pienkoss <wp@bszh.de>
*/
#define __NO_VERSION__
/* Bytes per L1 (data) cache line. */
#if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EV6)
-# define L1_CACHE_BYTES 32 /* should be 64, but networking dies */
+# define L1_CACHE_BYTES 64
+# define L1_CACHE_SHIFT 6
#else
/* Both EV4 and EV5 are write-through, read-allocate,
direct-mapped, physical.
*/
# define L1_CACHE_BYTES 32
+# define L1_CACHE_SHIFT 5
#endif
#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
/*
- * $Id: elf.h,v 1.6 1999/02/15 02:22:10 ralf Exp $
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
*/
-#ifndef __ASM_MIPS_ELF_H
-#define __ASM_MIPS_ELF_H
+#ifndef __ASM_ELF_H
+#define __ASM_ELF_H
/* ELF register definitions */
#define ELF_NGREG 45
*/
#define elf_check_arch(hdr) \
({ \
- int __res = 0; \
+ int __res = 1; \
struct elfhdr *__h = (hdr); \
\
- if ((__h->e_machine != EM_MIPS) && (__h->e_machine != EM_MIPS)) \
- __res = -ENOEXEC; \
+ if ((__h->e_machine != EM_MIPS) && \
+ (__h->e_machine != EM_MIPS_RS4_BE)) \
+ __res = 0; \
if (__h->e_flags & EF_MIPS_ARCH) \
- __res = -ENOEXEC; \
+ __res = 0; \
\
__res; \
})
/* This one accepts IRIX binaries. */
#define irix_elf_check_arch(hdr) \
({ \
- int __res = 0; \
+ int __res = 1; \
struct elfhdr *__h = (hdr); \
\
- if ((__h->e_machine != EM_MIPS) && (__h->e_machine != EM_MIPS)) \
- __res = -ENOEXEC; \
+ if ((__h->e_machine != EM_MIPS) && \
+ (__h->e_machine != EM_MIPS_RS4_BE)) \
+ __res = 0; \
\
__res; \
})
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
#endif
-#endif /* __ASM_MIPS_ELF_H */
+#endif /* __ASM_ELF_H */
-/* $Id: mc146818rtc.h,v 1.2 1998/06/30 00:23:10 ralf Exp $
- *
+/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Machine dependent access functions for RTC registers.
*
- * Copyright (C) 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1996, 1997, 1998, 2000 Ralf Baechle
*/
#ifndef _ASM_MC146818RTC_H
#define _ASM_MC146818RTC_H
extern struct rtc_ops *rtc_ops;
+#ifdef CONFIG_DECSTATION
+#define RTC_IRQ 0
+#else
+#define RTC_IRQ 8
+#endif
+
#endif /* _ASM_MC146818RTC_H */
*/
#define elf_check_arch(hdr) \
({ \
- int __res = 0; \
+ int __res = 1; \
struct elfhdr *__h = (hdr); \
\
- if ((__h->e_machine != EM_MIPS) && (__h->e_machine != EM_MIPS)) \
- __res = -ENOEXEC; \
+ if ((__h->e_machine != EM_MIPS) && \
+ (__h->e_machine != EM_MIPS_RS4_BE)) \
+ __res = 0; \
if (sizeof(elf_caddr_t) == 8 && \
__h->e_ident[EI_CLASS] == ELFCLASS32) \
- __res = -ENOEXEC; \
+ __res = 0; \
\
__res; \
})
extern struct rtc_ops *rtc_ops;
+#define RTC_IRQ 8
+
#endif /* _ASM_MC146818RTC_H */
* - flush_cache_range(mm, start, end) flushes a range of pages
* - flush_page_to_ram(page) write back kernel page to ram
*/
-extern void (*_flush_cache_all)(void);
extern void (*_flush_cache_mm)(struct mm_struct *mm);
extern void (*_flush_cache_range)(struct mm_struct *mm, unsigned long start,
unsigned long end);
extern void (*_flush_cache_page)(struct vm_area_struct *vma, unsigned long page);
-extern void (*_flush_cache_sigtramp)(unsigned long addr);
extern void (*_flush_page_to_ram)(struct page * page);
-#define flush_cache_all() _flush_cache_all()
+#define flush_cache_all() do { } while(0)
+
+#ifndef CONFIG_CPU_R10000
#define flush_cache_mm(mm) _flush_cache_mm(mm)
#define flush_cache_range(mm,start,end) _flush_cache_range(mm,start,end)
#define flush_cache_page(vma,page) _flush_cache_page(vma, page)
-#define flush_cache_sigtramp(addr) _flush_cache_sigtramp(addr)
#define flush_page_to_ram(page) _flush_page_to_ram(page)
-#define flush_icache_range(start, end) flush_cache_all()
+#define flush_icache_range(start, end) _flush_cache_l1()
#define flush_icache_page(vma, page) \
do { \
addr = page_address(page); \
_flush_cache_page(vma, addr); \
} while (0)
+#else /* !CONFIG_CPU_R10000 */
+/*
+ * Since the r10k handles VCEs in hardware, most of the flush cache
+ * routines are not needed. Only the icache on a processor is not
+ * coherent with the dcache of the _same_ processor, so we must flush
+ * the icache so that it does not contain stale contents of physical
+ * memory. No flushes are needed for dma coherency, since the o200s
+ * are io coherent. The only place where we might be overoptimizing
+ * out icache flushes are from mprotect (when PROT_EXEC is added).
+ */
+extern void andes_flush_icache_page(unsigned long);
+#define flush_cache_mm(mm) do { } while(0)
+#define flush_cache_range(mm,start,end) do { } while(0)
+#define flush_cache_page(vma,page) do { } while(0)
+#define flush_page_to_ram(page) do { } while(0)
+#define flush_icache_range(start, end) _flush_cache_l1()
+#define flush_icache_page(vma, page) \
+do { \
+ if ((vma)->vm_flags & VM_EXEC) \
+ andes_flush_icache_page(page_address(page)); \
+} while (0)
+#endif /* !CONFIG_CPU_R10000 */
+
+/*
+ * The foll cache flushing routines are MIPS specific.
+ * flush_cache_l2 is needed only during initialization.
+ */
+extern void (*_flush_cache_sigtramp)(unsigned long addr);
+extern void (*_flush_cache_l2)(void);
+extern void (*_flush_cache_l1)(void);
+
+#define flush_cache_sigtramp(addr) _flush_cache_sigtramp(addr)
+#define flush_cache_l2() _flush_cache_l2()
+#define flush_cache_l1() _flush_cache_l1()
/*
* Each address space has 2 4K pages as its page directory, giving 1024
#define sti() __global_sti()
#define save_flags(x) ((x)=__global_save_flags())
#define restore_flags(x) __global_restore_flags(x)
-#define save_and_cli(x) do { save_flags(flags); cli(); } while(0)
+#define save_and_cli(x) do { save_flags(x); cli(); } while(0)
#else
#define D_TIMING 4096 /* show time needed to copy buffers to card */
#ifndef ARCNET_DEBUG_MAX
-#define ARCNET_DEBUG_MAX (~0) /* enable ALL debug messages */
+#define ARCNET_DEBUG_MAX (127) /* change to ~0 if you want detailed debugging */
#endif
#ifndef ARCNET_DEBUG
*/
#define MAX_ARG_PAGES 32
+/* sizeof(linux_binprm->buf) */
+#define BINPRM_BUF_SIZE 128
+
#ifdef __KERNEL__
/*
* This structure is used to hold the arguments that are used when loading binaries.
*/
struct linux_binprm{
- char buf[128];
+ char buf[BINPRM_BUF_SIZE];
struct page *page[MAX_ARG_PAGES];
unsigned long p; /* current top of mem */
int sh_bang;
#define __MODULE_STRING(x) __MODULE_STRING_1(x)
/* Find a symbol exported by the kernel or another module */
+#ifdef CONFIG_MODULES
extern unsigned long get_module_symbol(char *, char *);
extern void put_module_symbol(unsigned long);
+#else
+static inline unsigned long get_module_symbol(char *unused1, char *unused2) { return 0; };
+static inline void put_module_symbol(unsigned long unused) { };
+#endif
extern int try_inc_mod_count(struct module *mod);
/*
* Some day this will be a full-fledged user tracking system..
- * Right now it is only used to track how many processes a
- * user has, but it has the potential to track memory usage etc.
*/
-struct user_struct;
+struct user_struct {
+ atomic_t __count; /* reference count */
+ atomic_t processes; /* How many processes does this user have? */
+ atomic_t files; /* How many open files does this user have? */
+
+ /* Hash table maintenance information */
+ struct user_struct *next, **pprev;
+ unsigned int uid;
+};
+
+#define get_current_user() ({ \
+ struct user_struct *__user = current->user; \
+ atomic_inc(&__user->__count); \
+ __user; })
+
+extern struct user_struct root_user;
+#define INIT_USER (&root_user)
struct task_struct {
/*
cap_permitted: CAP_FULL_SET, \
keep_capabilities: 0, \
rlim: INIT_RLIMITS, \
+ user: INIT_USER, \
comm: "swapper", \
thread: INIT_THREAD, \
fs: &init_fs, \
}
/* per-UID process charging. */
-extern int alloc_uid(struct task_struct *);
-void free_uid(struct task_struct *);
+extern struct user_struct * alloc_uid(uid_t);
+extern void free_uid(struct user_struct *);
#include <asm/current.h>
#define RW_LOCK_UNLOCKED (rwlock_t) { 0 }
#endif
+#define rwlock_init(lock) do { } while(0)
#define read_lock(lock) (void)(lock) /* Not "unused variable". */
#define read_unlock(lock) do { } while(0)
#define write_lock(lock) (void)(lock) /* Not "unused variable". */
Version 2 and 3 extensions to driver:
* Copyright (C) 1998 - 2000 Douglas Gilbert
- Version: 3.1.15 (20000528)
+ Version: 3.1.16 (20000716)
This version is for 2.3/2.4 series kernels.
+ Changes since 3.1.15 (20000528)
+ - further (scatter gather) buffer length changes
Changes since 3.1.14 (20000503)
- fix aha1542 odd length buffer problem
- make multiple readers on same fd safe
O_TARGET := kernel.o
O_OBJS = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
module.o exit.o itimer.o info.o time.o softirq.o resource.o \
- sysctl.o acct.o capability.o ptrace.o timer.o
+ sysctl.o acct.o capability.o ptrace.o timer.o user.o
OX_OBJS += signal.o sys.o
spin_unlock_irq(&runqueue_lock);
} while (has_cpu);
#endif
- free_uid(p);
+ atomic_dec(&p->user->processes);
+ free_uid(p->user);
unhash_process(p);
release_thread(p);
struct task_struct *pidhash[PIDHASH_SZ];
-/* UID task count cache, to prevent walking entire process list every
- * single fork() operation.
- */
-#define UIDHASH_SZ (PIDHASH_SZ >> 2)
-
-static struct user_struct {
- atomic_t count;
- struct user_struct *next, **pprev;
- unsigned int uid;
-} *uidhash[UIDHASH_SZ];
-
-spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
-
-kmem_cache_t *uid_cachep;
-
-#define uidhashfn(uid) (((uid >> 8) ^ uid) & (UIDHASH_SZ - 1))
-
-/*
- * These routines must be called with the uidhash spinlock held!
- */
-static inline void uid_hash_insert(struct user_struct *up, unsigned int hashent)
-{
- if((up->next = uidhash[hashent]) != NULL)
- uidhash[hashent]->pprev = &up->next;
- up->pprev = &uidhash[hashent];
- uidhash[hashent] = up;
-}
-
-static inline void uid_hash_remove(struct user_struct *up)
-{
- if(up->next)
- up->next->pprev = up->pprev;
- *up->pprev = up->next;
-}
-
-static inline struct user_struct *uid_hash_find(unsigned short uid, unsigned int hashent)
-{
- struct user_struct *up, *next;
-
- next = uidhash[hashent];
- for (;;) {
- up = next;
- if (next) {
- next = up->next;
- if (up->uid != uid)
- continue;
- atomic_inc(&up->count);
- }
- break;
- }
- return up;
-}
-
-/*
- * For SMP, we need to re-test the user struct counter
- * after having aquired the spinlock. This allows us to do
- * the common case (not freeing anything) without having
- * any locking.
- */
-#ifdef CONFIG_SMP
- #define uid_hash_free(up) (!atomic_read(&(up)->count))
-#else
- #define uid_hash_free(up) (1)
-#endif
-
-void free_uid(struct task_struct *p)
-{
- struct user_struct *up = p->user;
-
- if (up) {
- p->user = NULL;
- if (atomic_dec_and_test(&up->count)) {
- spin_lock(&uidhash_lock);
- if (uid_hash_free(up)) {
- uid_hash_remove(up);
- kmem_cache_free(uid_cachep, up);
- }
- spin_unlock(&uidhash_lock);
- }
- }
-}
-
-int alloc_uid(struct task_struct *p)
-{
- unsigned int hashent = uidhashfn(p->uid);
- struct user_struct *up;
-
- spin_lock(&uidhash_lock);
- up = uid_hash_find(p->uid, hashent);
- spin_unlock(&uidhash_lock);
-
- if (!up) {
- struct user_struct *new;
-
- new = kmem_cache_alloc(uid_cachep, SLAB_KERNEL);
- if (!new)
- return -EAGAIN;
- new->uid = p->uid;
- atomic_set(&new->count, 1);
-
- /*
- * Before adding this, check whether we raced
- * on adding the same user already..
- */
- spin_lock(&uidhash_lock);
- up = uid_hash_find(p->uid, hashent);
- if (up) {
- kmem_cache_free(uid_cachep, new);
- } else {
- uid_hash_insert(new, hashent);
- up = new;
- }
- spin_unlock(&uidhash_lock);
-
- }
- p->user = up;
- return 0;
-}
-
void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
{
unsigned long flags;
void __init fork_init(unsigned long mempages)
{
- int i;
-
- uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
- 0,
- SLAB_HWCACHE_ALIGN, NULL, NULL);
- if(!uid_cachep)
- panic("Cannot create uid taskcount SLAB cache\n");
-
- for(i = 0; i < UIDHASH_SZ; i++)
- uidhash[i] = 0;
-
/*
* The default maximum number of threads is set to a safe
* value: the thread structures can take up at most half
lock_kernel();
retval = -EAGAIN;
- if (p->user) {
- if (atomic_read(&p->user->count) >= p->rlim[RLIMIT_NPROC].rlim_cur)
- goto bad_fork_free;
- atomic_inc(&p->user->count);
- }
+ if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur)
+ goto bad_fork_free;
+ atomic_inc(&p->user->__count);
+ atomic_inc(&p->user->processes);
/*
* Counter increases are protected by
if (p->binfmt && p->binfmt->module)
__MOD_DEC_USE_COUNT(p->binfmt->module);
bad_fork_cleanup_count:
- if (p->user)
- free_uid(p);
+ atomic_dec(&p->user->processes);
+ free_uid(p->user);
bad_fork_free:
free_task_struct(p);
goto bad_fork;
}
}
+static int set_user(uid_t new_ruid)
+{
+ struct user_struct *new_user, *old_user;
+
+ /* What if a process setreuid()'s and this brings the
+ * new uid over his NPROC rlimit? We can check this now
+ * cheaply with the new uid cache, so if it matters
+ * we should be checking for it. -DaveM
+ */
+ new_user = alloc_uid(new_ruid);
+ if (!new_user)
+ return -EAGAIN;
+ old_user = current->user;
+ atomic_dec(&old_user->processes);
+ atomic_inc(&new_user->processes);
+
+ current->uid = new_ruid;
+ current->user = new_user;
+ free_uid(old_user);
+ return 0;
+}
+
/*
* Unprivileged users may change the real uid to the effective uid
* or vice versa. (BSD-style)
*/
asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
{
- int old_ruid, old_euid, old_suid, new_ruid;
+ int old_ruid, old_euid, old_suid, new_ruid, new_euid;
new_ruid = old_ruid = current->uid;
- old_euid = current->euid;
+ new_euid = old_euid = current->euid;
old_suid = current->suid;
+
if (ruid != (uid_t) -1) {
- if ((old_ruid == ruid) ||
- (current->euid==ruid) ||
- capable(CAP_SETUID))
- new_ruid = ruid;
- else
+ new_ruid = ruid;
+ if ((old_ruid != ruid) &&
+ (current->euid != ruid) &&
+ !capable(CAP_SETUID))
return -EPERM;
}
+
if (euid != (uid_t) -1) {
- if ((old_ruid == euid) ||
- (current->euid == euid) ||
- (current->suid == euid) ||
- capable(CAP_SETUID))
- current->fsuid = current->euid = euid;
- else
+ new_euid = euid;
+ if ((old_ruid != euid) &&
+ (current->euid != euid) &&
+ (current->suid != euid) &&
+ !capable(CAP_SETUID))
return -EPERM;
}
+
+ if (new_ruid != old_ruid && set_user(new_ruid) < 0)
+ return -EAGAIN;
+
+ current->fsuid = current->euid = new_euid;
if (ruid != (uid_t) -1 ||
(euid != (uid_t) -1 && euid != old_ruid))
current->suid = current->euid;
if (current->euid != old_euid)
current->dumpable = 0;
- if(new_ruid != old_ruid) {
- /* What if a process setreuid()'s and this brings the
- * new uid over his NPROC rlimit? We can check this now
- * cheaply with the new uid cache, so if it matters
- * we should be checking for it. -DaveM
- */
- free_uid(current);
- current->uid = new_ruid;
- alloc_uid(current);
- }
-
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
cap_emulate_setxuid(old_ruid, old_euid, old_suid);
}
old_ruid = new_ruid = current->uid;
old_suid = current->suid;
- if (capable(CAP_SETUID))
- new_ruid = current->euid = current->suid = current->fsuid = uid;
- else if ((uid == current->uid) || (uid == current->suid))
- current->fsuid = current->euid = uid;
- else
+ if (capable(CAP_SETUID)) {
+ if (uid != old_ruid && set_user(uid) < 0)
+ return -EAGAIN;
+ current->suid = uid;
+ } else if (uid == current->uid) {
+ /* Nothing - just set fsuid/euid */
+ } else if (uid == current->suid) {
+ if (set_user(uid) < 0)
+ return -EAGAIN;
+ } else
return -EPERM;
- if (current->euid != old_euid)
- current->dumpable = 0;
+ current->fsuid = current->euid = uid;
- if (new_ruid != old_ruid) {
- /* See comment above about NPROC rlimit issues... */
- free_uid(current);
- current->uid = new_ruid;
- alloc_uid(current);
- }
+ if (old_euid != uid)
+ current->dumpable = 0;
if (!issecure(SECURE_NO_SETUID_FIXUP)) {
cap_emulate_setxuid(old_ruid, old_euid, old_suid);
return -EPERM;
}
if (ruid != (uid_t) -1) {
- /* See above commentary about NPROC rlimit issues here. */
- free_uid(current);
- current->uid = ruid;
- alloc_uid(current);
+ if (ruid != current->uid && set_user(ruid) < 0)
+ return -EAGAIN;
}
if (euid != (uid_t) -1) {
if (euid != current->euid)
--- /dev/null
+/*
+ * The "user cache".
+ *
+ * (C) Copyright 1991-2000 Linus Torvalds
+ *
+ * We have a per-user structure to keep track of how many
+ * processes, files etc the user has claimed, in order to be
+ * able to have per-user limits for system resources.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+/*
+ * UID task count cache, to get fast user lookup in "alloc_uid"
+ * when changing user ID's (ie setuid() and friends).
+ */
+#define UIDHASH_SZ (256)
+
+static struct user_struct *uidhash[UIDHASH_SZ];
+
+spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
+
+struct user_struct root_user = {
+ __count: ATOMIC_INIT(1),
+ processes: ATOMIC_INIT(1),
+ files: ATOMIC_INIT(0)
+};
+
+static kmem_cache_t *uid_cachep;
+
+#define uidhashfn(uid) (((uid >> 8) ^ uid) & (UIDHASH_SZ - 1))
+
+/*
+ * These routines must be called with the uidhash spinlock held!
+ */
+static inline void uid_hash_insert(struct user_struct *up, unsigned int hashent)
+{
+ if((up->next = uidhash[hashent]) != NULL)
+ uidhash[hashent]->pprev = &up->next;
+ up->pprev = &uidhash[hashent];
+ uidhash[hashent] = up;
+}
+
+static inline void uid_hash_remove(struct user_struct *up)
+{
+ if(up->next)
+ up->next->pprev = up->pprev;
+ *up->pprev = up->next;
+}
+
+static inline struct user_struct *uid_hash_find(unsigned short uid, unsigned int hashent)
+{
+ struct user_struct *up, *next;
+
+ next = uidhash[hashent];
+ for (;;) {
+ up = next;
+ if (next) {
+ next = up->next;
+ if (up->uid != uid)
+ continue;
+ atomic_inc(&up->__count);
+ }
+ break;
+ }
+ return up;
+}
+
+/*
+ * For SMP, we need to re-test the user struct counter
+ * after having aquired the spinlock. This allows us to do
+ * the common case (not freeing anything) without having
+ * any locking.
+ */
+#ifdef CONFIG_SMP
+ #define uid_hash_free(up) (!atomic_read(&(up)->__count))
+#else
+ #define uid_hash_free(up) (1)
+#endif
+
+void free_uid(struct user_struct *up)
+{
+ if (up) {
+ if (atomic_dec_and_test(&up->__count)) {
+ spin_lock(&uidhash_lock);
+ if (uid_hash_free(up)) {
+ uid_hash_remove(up);
+ kmem_cache_free(uid_cachep, up);
+ }
+ spin_unlock(&uidhash_lock);
+ }
+ }
+}
+
+struct user_struct * alloc_uid(uid_t uid)
+{
+ unsigned int hashent = uidhashfn(uid);
+ struct user_struct *up;
+
+ spin_lock(&uidhash_lock);
+ up = uid_hash_find(uid, hashent);
+ spin_unlock(&uidhash_lock);
+
+ if (!up) {
+ struct user_struct *new;
+
+ new = kmem_cache_alloc(uid_cachep, SLAB_KERNEL);
+ if (!new)
+ return NULL;
+ new->uid = uid;
+ atomic_set(&new->__count, 1);
+ atomic_set(&new->processes, 0);
+ atomic_set(&new->files, 0);
+
+ /*
+ * Before adding this, check whether we raced
+ * on adding the same user already..
+ */
+ spin_lock(&uidhash_lock);
+ up = uid_hash_find(uid, hashent);
+ if (up) {
+ kmem_cache_free(uid_cachep, new);
+ } else {
+ uid_hash_insert(new, hashent);
+ up = new;
+ }
+ spin_unlock(&uidhash_lock);
+
+ }
+ return up;
+}
+
+
+static int __init uid_cache_init(void)
+{
+ int i;
+
+ uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct),
+ 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if(!uid_cachep)
+ panic("Cannot create uid taskcount SLAB cache\n");
+
+ for(i = 0; i < UIDHASH_SZ; i++)
+ uidhash[i] = 0;
+
+ /* Insert the root user immediately - init already runs with this */
+ uid_hash_insert(&root_user, uidhashfn(0));
+ return 0;
+}
+
+module_init(uid_cache_init);
struct page * alloc_pages(int gfp_mask, unsigned long order)
{
struct page *ret = 0;
- unsigned long flags;
int startnode, tnode;
+#ifndef CONFIG_NUMA
+ unsigned long flags;
static int nextnid = 0;
+#endif
if (order >= MAX_ORDER)
return NULL;
+#ifdef CONFIG_NUMA
+ tnode = numa_node_id();
+#else
spin_lock_irqsave(&node_lock, flags);
tnode = nextnid;
nextnid++;
if (nextnid == numnodes)
nextnid = 0;
spin_unlock_irqrestore(&node_lock, flags);
+#endif
startnode = tnode;
while (tnode < numnodes) {
if ((ret = alloc_pages_node(tnode++, gfp_mask, order)))
0, NULL, { } },
{
/* LOCAL_IN */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* FORWARD */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
{ { { { IP6T_ALIGN(sizeof(struct ip6t_standard_target)), "" } }, { } },
-NF_ACCEPT - 1 } },
/* LOCAL_OUT */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_standard),
-NF_ACCEPT - 1 } }
},
/* ERROR */
- { { { { 0 }, { 0 }, { 0 }, { 0 }, "", "", { 0 }, { 0 }, 0, 0, 0 },
+ { { { { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, { { { 0 } } }, "", "", { 0 }, { 0 }, 0, 0, 0 },
0,
sizeof(struct ip6t_entry),
sizeof(struct ip6t_error),
{
int i;
- printk(KERN_INFO "Linux NET4.0 for Linux 2.3\n");
+ printk(KERN_INFO "Linux NET4.0 for Linux 2.4\n");
printk(KERN_INFO "Based upon Swansea University Computer Society NET3.039\n");
/*