Allow chipset drivers to specify the direct-mapped DMA window's mask in
preparation for tsunami support. Previous chipsets' direct-mapped DMA
mask was always 1024*1024*1024. The Tsunami chipset needs it to be
2*1024*1024*1024
Reviewed by: Doug Rabson <dfr@nlsystems.com>
preparation for tsunami support. Previous chipsets' direct-mapped DMA
mask was always 1024*1024*1024. The Tsunami chipset needs it to be
2*1024*1024*1024
These changes should not affect the i386 port
Reviewed by: Doug Rabson <dfr@nlsystems.com>
only support 'mirroring' the vendor and device ids, so we don't
lose any information. Certain revisions of the aic7880 will not
perform the mirroring so to match all possiblities would double
the number of table entries. This change also allows us to match
things like the 2944B which I missed in the original table.
commands are outstanding. You'd think they'd just clear the IDLE bit,
but alas, no. Delay until all pending mailbox commands have completed
in aha_cmd to work around this.
Report sync rates correctly on Fast Adaptec cards. Clones may still be
reported incorrectly since there is no documenation on how they report
extended sync values.
Clean up some unused fields in the aha softc.
SIS/VIA/ OPTi chipset PCI bus workarounds.
These make the Bt878/879 chips stabler on certain
older and non-intel motherboards.
Use options BKTR_430_FX_MODE
or options BKTR_SIS_VIA_MODE
to enable these modes.
Also rename 849 to 849A
in the transmit code: the TX descriptor ring, and a 'shadow' ring of mbuf
pointers, one for each TX descriptor. When transmitting a packet that
consists of several fragments in an mbuf chain, we link each fragment
to a descriptor in the TX ring, but we only save a pointer to the mbuf
chain. This pointer is saved in the shadow ring entry which corresponds
to the first fragment in the packet. Later, ti_txeof() can release the
whole chain with a single m_freem() call. (We need the second ring to
keep track of the virtual addresses of the mbuf chains.)
The problem with this is that the Tigon isn't actually through with the
mbuf chain until it reaches the last fragment (which has the TI_BDFLAG_END
bit set), however the current scheme releases the mbuf chain as soon as
the first fragment is consumed. This is wrong, since the mbufs can then
be yanked out from under the Tigon and modified before the other fragments
can be transmitted.
The fix is to make a one line change to ti_encap() so that it saves the
mbuf chain pointer in the shadow ring entry that corresponds to the last
fragment in TX ring instead of the first. This prevents the mbufs from
being released until the last fragment is transmitted.
Painstakingly diagnosed and fixed by: Robert Picco <picco@mail.wevinc.com>
Brought to my attention by: dg
manager and prevented IOPort allocation beyond the first EISA slot from
working. subr_rman.c should have trapped this on the way into the system
rather than tripping over the wreckage.
Head banged into wall repeatedly by: "Matthew N. Dodd" <winter@jurai.net>
Honor the 'bus reset at startup' option now that the XPT properly
handles transfer negotiation in this scenario.
Honor the sync rate settings on Ultra2 controllers. We would
always negotiate at the fastest speed. Oops.
aic7xxx.h:
Whitespace.
aic7xxx.seq:
Fix a minor nit that would cause the controller to miss the update
of the negotiation required bitmask causing the negotiation to
be delayed by a command.
driver lacks error recovery and still needs more testing, but it's
about time I got it under revision control.
Submitted by: Tekram Inc.
Bus Space/DMA and cleanup: gibbs
- Mention that the 6Mbps turbo adapters are supported in HARDWARE.TXT
and RELNOTES.TXT and the wi.4 man page
- Mention turbo adapters in the wicontrol.8 man page and provide a
complete table of available transmit speed settings
Implement priorities.
GENERIC, LINT, files:
Remove remarks about ordering of device names.
GENERIC, LINT:
Sort the devices alphabetically in LINT and GENERIC.
The specific intent of this commit is to pave the way for importing
Compaq XP1000 support. These changes should not affect the i386 port.
Reviewed by: Doug Rabson <dfr@nlsystems.com>
(actually, he walked me through most of it & deserves more than reviewd-by
credit )
Fixed problems:
LS120/ZIP drives still currupted data.
Reworked once again, buffered I/O is just ignoring any sizehints
it is given :(
Now the atapifd driver splits up requests for devices that has
limitted transfer size.
ISA only configs fails on boot with interrupt timeouts.
The new-bus integration introduced a bug where the softc ptr
was lost during the probe.
Some minor cleanups and rearrangements as well.
As usual USE AT YOUR OWN RISK!!, this is still pre alpha level code.
Especially the DMA support can hose your disk real bad if anything
goes wrong, again you have been warned :)
Notebook owners should be carefull that their machines dont suspend
as this might cause trouble...
But please tell me how it works for you!
Enjoy!
motherboard will have a card for the "motherboard" on slot 0.
eisa0: <EISA bus> on motherboard
mainboard0: <ASU5101 (System Board)> at slot 0 on eisa0
This should stop the probe "detecting" an EISA bus everywhere that has
a 'controller eisa0' line regardless of whether it's really there.
Change Intel GPIO mask to hopefully stop turning the Intel Camera off
Fixed tuner selection on Hauppauge card with tuner 0x0a
Replaced none tuner with no tuner for Theo de Raadt <deraadt@openbsd.org>.
Ivan Brawley <brawley@internode.com.au> added
the Australian channel frequencies.
Clean up the handling of failure modes in our attach so we don't free
resources twice. ahc_free() will do all of the work for us (as would
be required by an unload event) so we only need to handle resources that
the softc has not taken ownership of.
Fixed problems:
LS120 drives currupted data.
The workaround for drives not supporting upto 64K transfers
has been reworked. It works now both on LS120 & ZIP drives.
ISA only configs wont compile.
Fixed.
The ATA driver wont share interrupts.
Fixed.
The "unwanted interrupt" warning gave wrong controller.
Another lun<>unit messup from the newbus integration.
Some minor cleanups and rearrangements as well.
As usual USE AT YOUR OWN RISK!!, this is still pre alpha level code.
Especially the DMA support can hose your disk real bad if anything
goes wrong, again you have been warned :)
Notebook owners should be carefull that their machines dont suspend
as this might cause trouble...
But please tell me how it works for you!
Enjoy!
-Søren
docs don't seem to shed light on why this is needed, but reports from
the field indicate this helps prevent problems in this area. Ken's
changes seem to have exposed this bug, rather than caused it, as far
as I can tell.
Thanks to Jack O'Neill for tracking this down.
Submitted by: jack@germanium.xtalwind.net
Very strong 3.2 merge candidate.
Sync up device Ids with the master Adaptec list.
Add probe support for the 2940 Pro although it isn't obvious that
all of the termination support is correct for this adapter yet.
tell the sequencer to pause itself for a target msg variable update. This
avoids the pause race entirely as HS_MAILBOX can be accessed without
pausing the chip.
3.2 Merge candidate.
v1.19 (1999/04/15) updates the CEM56/REM56 support.
Current bugs & misfeatures
--------------------------
* CE2 cards still not working reliably. Unclear if this is related to
packet I/O code or interrupt handling.
* Autonegotiation support remains flaky. We're now OK with 10Mbit auto
hubs, but certain combination of hardware will fail to connect.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.19 (1999/04/15) updates the CEM56/REM56 support.
Current bugs & misfeatures
--------------------------
* CE2 cards still not working reliably. Unclear if this is related to
packet I/O code or interrupt handling.
* Autonegotiation support remains flaky. We're now OK with 10Mbit auto
hubs, but certain combination of hardware will fail to connect.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.18 (1999/04/08) adds support for CEM56 and REM56 multifunction cards.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.18 (1999/04/08) adds support for CEM56 and REM56 multifunction cards.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.17 (1999/03/28) has xperimental fixes to 10Mbit autonegotiation and
CE2 input lockup.
KNOWN BUGS
==========
* Media auto-negotiation is definitely not right. It will work in most
circumstances and seems to connect OK to most 100Mbit networks, however some
pathological combinations of hubs/networks/peers seem to confuse it.
* CE2 support is somewhat flakey (ranging from 'works perfectly' to 'hangs the
machine' so far). I've fixed the probe routine and a potential lockup in
the output routine, but a lot of people still report that they can't receive
or transmit.
* You won't be able to use the modem and Ethenet parts of a multifunction card
simultaneously. This is limitation the current FreeBSD PCMCIA support.
Likewise, there is no support for CardBus devices.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.17 (1999/03/28) has xperimental fixes to 10Mbit autonegotiation and
CE2 input lockup.
KNOWN BUGS
==========
* Media auto-negotiation is definitely not right. It will work in most
circumstances and seems to connect OK to most 100Mbit networks, however some
pathological combinations of hubs/networks/peers seem to confuse it.
* CE2 support is somewhat flakey (ranging from 'works perfectly' to 'hangs the
machine' so far). I've fixed the probe routine and a potential lockup in
the output routine, but a lot of people still report that they can't receive
or transmit.
* You won't be able to use the modem and Ethenet parts of a multifunction card
simultaneously. This is limitation the current FreeBSD PCMCIA support.
Likewise, there is no support for CardBus devices.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.16 (1999/03/08) fixed BPF input hang and infinite loop on CE2
short-packet output.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
v1.16 (1999/03/08) fixed BPF input hang and infinite loop on CE2
short-packet output.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
This driver is mostly based on the `xirc2ps' driver for Linux by Werner
Koch. Werner has even allowed his code to be distributed under a BSD licence,
making our life considerably easier -- thanks Werner!
This driver supports:
* Intel EtherExpress(TM) PRO/100 PCCARD (16-bit version)
* Xircom CreditCard CE2 / CEM28 / CEM33 / CE3 / CEM56 Ethernet adapters.
* Toshiba Advanced Network 10/100 PCCARD
* Certain Compaq Netelligent 10/100 branded cards
v1.14 has major changes to media selection code, and bugfixes in the
probe routine.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
This driver is mostly based on the `xirc2ps' driver for Linux by Werner
Koch. Werner has even allowed his code to be distributed under a BSD licence,
making our life considerably easier -- thanks Werner!
This driver supports:
* Intel EtherExpress(TM) PRO/100 PCCARD (16-bit version)
* Xircom CreditCard CE2 / CEM28 / CEM33 / CE3 / CEM56 Ethernet adapters.
* Toshiba Advanced Network 10/100 PCCARD
* Certain Compaq Netelligent 10/100 branded cards
v1.14 has major changes to media selection code, and bugfixes in the
probe routine.
Developed by: Scott Mitchell <scott@uk.freebsd.org>
Obtained from: http://www.freebsd-uk.eu.org/~scott/xe_drv/
udev_t in the kernel but still called dev_t in userland.
Provide functions to manipulate both types:
major() umajor()
minor() uminor()
makedev() umakedev()
dev2udev() udev2dev()
For now they're functions, they will become in-line functions
after one of the next two steps in this process.
Return major/minor/makedev to macro-hood for userland.
Register a name in cdevsw[] for the "filedescriptor" driver.
In the kernel the udev_t appears in places where we have the
major/minor number combination, (ie: a potential device: we
may not have the driver nor the device), like in inodes, vattr,
cdevsw registration and so on, whereas the dev_t appears where
we carry around a reference to a actual device.
In the future the cdevsw and the aliased-from vnode will be hung
directly from the dev_t, along with up to two softc pointers for
the device driver and a few houskeeping bits. This will essentially
replace the current "alias" check code (same buck, bigger bang).
A little stunt has been provided to try to catch places where the
wrong type is being used (dev_t vs udev_t), if you see something
not working, #undef DEVT_FASCIST in kern/kern_conf.c and see if
it makes a difference. If it does, please try to track it down
(many hands make light work) or at least try to reproduce it
as simply as possible, and describe how to do that.
Without DEVT_FASCIST I belive this patch is a no-op.
Stylistic/posixoid comments about the userland view of the <sys/*.h>
files welcome now, from userland they now contain the end result.
Next planned step: make all dev_t's refer to the same devsw[] which
means convert BLK's to CHR's at the perimeter of the vnodes and
other places where they enter the game (bootdev, mknod, sysctl).
bad math: it does not handle page-boundary conditions, and will not
end up mapping all of the requested addresses. This will cause a panic:
page fault during probe on some systems. I have a machine that will
panic every time (when using the dpt driver) on kernel probe when there
are 5 drives installed. When there are 4 drives, it is fine.
Fix is to always allocate/deallocate an extra page.
There is also a bonus splx() fix on an early error return.
Submitted by: Mark J. Taylor <mtaylor@cybernet.com>
PR: 9367
some aha 1542B cards will return 0x7f for the unimplemented GEOMETRY
register.
This is a good 3.2 candidate.
PR: 11469
Submitted by: Thomas David Rivers
displace a real driver.
Revert rev 1.109.
Pick up a few things from elsewhere (a couple of SiS id's).
As an *experiment*, have the chip* driver claim (for reporting purposes)
IDE controllers if there isn't another PCI-aware ide or ata driver to
grab them. I've exported the match function since it could be used from
the ata-all.c code replacing ata_pcimatch() - but I have not touched the
ata code. I'd like to catch a few more devices this way, including USB
and other bridges etc.
massive thwunking to include an XS_CHANNEL value. Some changes of how
parameters are reported to outer layers (including bus, e.g.). Yet more
stirring around in isp_mboxcmd to try and get it right. Decode of 1080/1240
NVRAM.
with other reset handling in rev.1.83 but broke it in rev.1.120. The
breakage didn't seem to cause any problems even on the system which had
problems ("extra" interrupts and botched handling thereof) before rev.1.83.
It only affects multi-floppy systems anyway.
after some of the previous commits). Add in support for the 1240
dual channel ISP card. Try the dance of unmapping a PCI interrupt
if we don't configure (if that ever works it'll be helpful).
bttv's audio mux values.
Automatically locate the EEPROM i2c address and read the subsystem_vendor_id
from EEPROM and not the PCI registers.
Add NSMBUS checks around smbus/iicbus i2c bus code
Add GPIO mask for the audio mux to each card type.
Add CARD_ZOLTRIX and CARD_KISS from mailing list searches.
Tested by: Paul Reece <paul@fastlane.net.au>,
Ivan Brawley <brawley@internode.com.au> and
Gilad Rom <rom_glsa@ein-hashofet.co.il>
#define COMPAT_PCI_DRIVER(name,data) DATA_SET(pcidevice_set,data)
.. to 2.2.x and 3.x if people think it's worth it. Driver writers can do
this if it's not defined. (The reason for this is that I'm trying to
progressively eliminate use of linker_sets where it hurts modularity and
runtime load capability, and these DATA_SET's keep getting in the way.)
although this is pretty trivial. devclass_get_softc() is a tad more
expensive than the old com_addr() implementation. If Bruce is really
worried about the cost of this, it could always be changed so that the
softc pointer is stored in a local array again.
I'm not too happy about the result either, but at least it has less
chance of backfiring.
This particular feature could be called "a mess" without offending
anybody.
o fix DDB support
- include "opt_ddb.h"
- fix Debugger() arg
pointed out by bde
o back out pvc shadow interface support
- it is currently not used
- to make it easier to merge another implementation
o misc minor cleanup
Made a new (inline) function devsw(dev_t dev) and substituted it.
Changed to the BDEV variant to this format as well: bdevsw(dev_t dev)
DEVFS will eventually benefit from this change too.
Virtualize bdevsw[] from cdevsw. bdevsw() is now an (inline)
function.
Join CDEV_MODULE and BDEV_MODULE to DEV_MODULE (please pay attention
to the order of the cmaj/bmaj arguments!)
Join CDEV_DRIVER_MODULE and BDEV_DRIVER_MODULE to DEV_DRIVER_MODULE
(ditto!)
(Next step will be to convert all bdev dev_t's to cdev dev_t's
before they get to do any damage^H^H^H^H^H^Hwork in the kernel.)
Mark the GDB port in the config file with flags 0x80. Currently
only the sio driver checks these flags and sets up a GDB port,
but adding similar code to other serial drivers would be easy.
For backward compatibility, if an sio port is marked as the console
and no port is marked as the gdb port, the GDB port will be mapped
to the console port. This hack should go away at some point.
power management. This will only work on newer firmware revisions; older
firmware will silently ignore the attempts to turn power management on.
Patches supplied by: Brad Karp <karp@eecs.harvard.edu>
NOTE: These changes will require recompilation of any userland
applications, like cdrecord, xmcd, etc., that use the CAM passthrough
interface. A make world is recommended.
camcontrol.[c8]:
- We now support two new commands, "tags" and "negotiate".
- The tags commands allows users to view the number of tagged
openings for a device as well as a number of other related
parameters, and it allows users to set tagged openings for
a device.
- The negotiate command allows users to enable and disable
disconnection and tagged queueing, set sync rates, offsets
and bus width. Note that not all of those features are
available for all controllers. Only the adv, ahc, and ncr
drivers fully support all of the features at this point.
Some cards do not allow the setting of sync rates, offsets and
the like, and some of the drivers don't have any facilities to
do so. Some drivers, like the adw driver, only support enabling
or disabling sync negotiation, but do not support setting sync
rates.
- new description in the camcontrol man page of how to format a disk
- cleanup of the camcontrol inquiry command
- add support in the 'devlist' command for skipping unconfigured devices if
-v was not specified on the command line.
- make use of the new base_transfer_speed in the path inquiry CCB.
- fix CCB bzero cases
cam_xpt.c, cam_sim.[ch], cam_ccb.h:
- new flags on many CCB function codes to designate whether they're
non-immediate, use a user-supplied CCB, and can only be passed from
userland programs via the xpt device. Use these flags in the transport
layer and pass driver to categorize CCBs.
- new flag in the transport layer device matching code for device nodes
that indicates whether a device is unconfigured
- bump the CAM version from 0x10 to 0x11
- Change the CAM ioctls to use the version as their group code, so we can
force users to recompile code even when the CCB size doesn't change.
- add + fill in a new value in the path inquiry CCB, base_transfer_speed.
Remove a corresponding field from the cam_sim structure, and add code to
every SIM to set this field to the proper value.
- Fix the set transfer settings code in the transport layer.
scsi_cd.c:
- make some variables volatile instead of just casting them in various
places
- fix a race condition in the changer code
- attach unless we get a "logical unit not supported" error. This should
fix all of the cases where people have devices that return weird errors
when they don't have media in the drive.
scsi_da.c:
- attach unless we get a "logical unit not supported" error
scsi_pass.c:
- for immediate CCBs, just malloc a CCB to send the user request in. This
gets rid of the 'held' count problem in camcontrol tags.
scsi_pass.h:
- change the CAM ioctls to use the CAM version as their group code.
adv driver:
- Allow changing the sync rate and offset separately.
adw driver
- Allow changing the sync rate and offset separately.
aha driver:
- Don't return CAM_REQ_CMP for SET_TRAN_SETTINGS CCBs.
ahc driver:
- Allow setting offset and sync rate separately
bt driver:
- Don't return CAM_REQ_CMP for SET_TRAN_SETTINGS CCBs.
NCR driver:
- Fix the ultra/ultra 2 negotiation bug
- allow setting both the sync rate and offset separately
Other HBA drivers:
- Put code in to set the base_transfer_speed field for
XPT_GET_TRAN_SETTINGS CCBs.
Reviewed by: gibbs, mjacob (isp), imp (aha)
WaveLAN's radio modem. The default is whatever the NIC uses since NICs
sold in different countries may default to different frequencies. (The
Lose95/LoseNT software doesn't let you select the channel so it's probably
not really meant to be changed.)
- Change to the same transmit scheme as the PNIC driver.
- Dynamically set the cache alignment, and set burst size the same as
the PNIC driver in mx_init().
- Enable 'store and forward' mode by default. This is the slowest option
and it does reduce 100Mbps performance somewhat, but it's the most
reliable setting I can find. I'm more interested in having the driver
work reliably than trying to squeeze the best performance out of it.
The reason I'm doing this is that on *some* systems you may see a lot
of transmit underruns (which I can't explain: these are *fast* test
systems) and these errors seem to cause unusual and decidedly
non-tulip-like behavior. In normal 10Mbps mode, performance is fine
(you can easily saturate a 10Mbps link).
Also tweak some of the other drivers:
- Increase the size of the TX ring for the Winbond, ASIX, VIA Rhine
and PNIC drivers.
- Set a larger value for ifq_maxlen in the ThunderLAN driver. The setting
of TL_TX_LIST_CNT - 1 is too low (the ThunderLAN driver only allocates
20 transmit descriptors, and I don't want to fiddle with that now
because the ThunderLAN's descriptor structure is an oddball size
compared to the others).
adapter (and some workalikes). Also add man pages and a wicontrol
utility to manipulate some of the card parameters.
This driver was written using information gleaned from the Lucent HCF Light
library, though it does not use any of the HCF Light code itself, mainly
because it's contaminated by the GPL (but also because it's pretty gross).
The HCF Light lacks certain featurs from the full (but proprietary) HCF
library, including 802.11 frame encapsulation support, however it has
just enough register information about the Hermes chip to allow someone
with enough spare time and energy to implement a proper driver. (I would
have prefered getting my hands on the Hermes manual, but that's proprietary
too. For those who are wondering, the Linux driver uses the proprietary
HCF library, but it's provided in object code form only.)
Note that I do not have access to a WavePOINT access point, so I have
only been able to test ad-hoc mode. The wicontrol utility can turn on
BSS mode, but I don't know for certain that the NIC will associate with
an access point correctly. Testers are encouraged to send their results
to me so that I can find out if I screwed up or not.
network adapters. These are all PCMCIA devices (the ISA version is a
PCMCIA to ISA bridge with a PCMCIA card plugged into it). Also add a
wicontrol utility to read and write some of the card's parameters.
Note: I do not have access to a WavePOINT access point, so I have only
been able to test this driver in ad-hoc (point to point) mode. The
wicontrol utility allows programming the desired service set name (SSID)
and enabling BSS mode, but I can't tell for sure if it works (I know the
card switches modes, but I can't verify that it joins a service set
correctly).
This driver was written using information gleaned from the Lucent HCF Light
library, which is an API library designed to simplify driver development
for devices based on the Lucent Hermes chip. Unfortunately, the HCF Light
is missing certain features (like 802.11 frame encapsulation!) which are
available only in the proprietary complete HCF code, which is not available
to the public. This driver uses none of the HCF Light code: it's very ugly
and contaminated by the GPL. IP and ARP packets are encapsulated as 802.11
frames, everything else is encapsulated as 802.3.
(It would be easier to just get the Hermes programming manual, but that's
not publically available either. For those who are wondering, the Linux
WaveLAN/IEEE driver uses the proprietary HCF code, which is provided in
object code form only. So much for supporting open source sofware.)
Multicast filter support is implemented, however it appears that the
filter doesn't work: programming in one IP mutlicast group enables them
all.
bug in the stats accounting (nicSendBDs counter was bogus when TX ring was
configured to be in host memory).
Update if_tireg.h to look for new firmware fix level.
* Make the network code in the bootstrap more chatty (helps debugging)
* Add nfs root stuff to cpu_rootconf(). I also added a check to make sure
it really was netbooting which allows the use of the same kernel for local
and network boots.
* Tweak the de driver so that it takes the speed setting from the console
for the alpha (some PWSs have broken de chipsets). This is the same
behaviour as NetBSD/alpha.
Submitted by: Andrew Gallatin <gallatin@cs.duke.edu>
if there's benefit to setting it to the exact amount, it appears the
card has 32K of ram, and 8K is used for outgoing packets, that would
be something like a queue limit of 5 packets. I don't think that's
useful...)
PR: 11456
Submitted by: Stephen J. Roznowski <sjr@home.net>