VGA driver is used. Note that, at this time, there is no X server
for these systems. If unsure, try N.
-PCI bios support
+PCI support
CONFIG_PCI
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
- VESA. If you have PCI, say Y, otherwise N. Note: some old PCI
- motherboards have BIOS bugs and may crash if "PCI bios support" is
- enabled (but they run fine without this option). The PCI-HOWTO,
- available via ftp (user: anonymous) in
- sunsite.unc.edu:/pub/Linux/docs/HOWTO, contains valuable information
- about which PCI hardware does work under Linux and which doesn't.
+ VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available
+ via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO,
+ contains valuable information about which PCI hardware does work
+ under Linux and which doesn't.
If some of your PCI devices don't work and you get a warning during
boot time ("man dmesg"), please follow the instructions at the top
of include/linux/pci.h.
+PCI BIOS support
+CONFIG_PCI_BIOS
+ If you have enabled PCI bus support above, you probably want to allow
+ Linux to use your PCI BIOS to detect the PCI devices and determine
+ their configuration. Note: some old PCI motherboards have BIOS bugs
+ and may crash if this switch is enabled -- for such motherboards,
+ you should disable PCI BIOS support and use direct PCI access instead.
+ Except for some special cases (embedded systems with no BIOS), you
+ probably should say Y here.
+
+PCI direct access support
+CONFIG_PCI_DIRECT
+ If you don't want to use the PCI BIOS (e.g., because you run some
+ embedded system with no BIOS at all) or Linux says it cannot use
+ your PCI BIOS, you can enable direct PCI hardware here. It might fail
+ if your machine is based on some unusual chipset, but it usually
+ works. If both PCI BIOS and direct PCI access are enabled, the use
+ of BIOS is preferred. If unsure, say Y.
+
PCI bridge optimization (experimental)
CONFIG_PCI_OPTIMIZE
This can improve access times for some hardware devices under
can only use one protocol at a time, depending on what the other end
can understand).
+Shortwave radio modem driver
+CONFIG_HFMODEM
+ This experimental driver is used by a package (to be released)
+ that implements the shortwave radio protocols RTTY, Sitor (Amtor),
+ Pactor 1 and GTOR using a standard PC soundcard. If unsure,
+ say N.
+
+Shortwave radio modem driver support for SoundBlaster and compatible cards
+CONFIG_HFMODEM_SBC
+ This option enables the hfmodem driver to use SoundBlaster and
+ compatible cards. It requires a 16bit capable card, i.e.
+ SB16 or better, or ESS1688 or newer.
+
+Shortwave radio modem driver support for WSS and Crystal cards
+CONFIG_HFMODEM_WSS
+ This option enables the hfmodem driver to use WindowsSoundSystem
+ compatible cards. These cards feature a codec chip from either
+ Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
+ Semiconductors (such as CS4248, CS423x).
+
Serial port KISS driver for AX.25
CONFIG_MKISS
KISS is the protocol used to send IP traffic over AX.25 radio
linux, read the Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-ARCnet support
+Generic ARCnet support
CONFIG_ARCNET
If you have a network card of this type, say Y and check out the
(arguably) beautiful poetry in Documentation/networking/arcnet.txt.
+ You need both this driver, and the driver for the particular ARCnet
+ chipset of your card. If you don't know, then it's probably a
+ COM90xx type card, so say Y (or M) to ARCnet COM90xx chipset support
+ below.
You might also want to have a look at the Ethernet-HOWTO, available
via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO
(even though ARCnet is not really ethernet). This driver is also
documentation in Documentation/networking/arcnet.txt for more
information about using arc0e and arc0s.
+ARCnet COM90xx chipset support
+CONFIG_ARCNET_COM90xx
+ This is the chipset driver for the standard COM90xx cards. If you always
+ used the old arcnet driver without knowing what type of card you had,
+ this is probably the one for you.
+
+ARCnet COM90xx IO mapped mode chipset support
+CONFIG_ARCNET_COM90xxIO
+ This is the chipset driver for the COM90xx cards, using them in IO-mapped
+ mode instead of memory-mapped mode. This is slower than the normal driver.
+ Only use it if your card doesn't support shared memory.
+
+ARCnet RIM I chipset support
+CONFIG_ARCNET_RIM_I
+ This is yet another chipset driver for the COM90xx cards, but this time
+ only using memory-mapped mode, and no IO ports at all. This driver is
+ completely untested, so if you have one of these cards, please mail
+ dwmw2@cam.ac.uk, especially if it works!
+
+ARCnet COM20020 chipset support
+CONFIG_ARCNET_COM20020
+ This is the driver for the new COM20020 chipset. It supports such things
+ as promiscuous mode, so packet sniffing is possible, and extra diagnostic
+ information.
+
Cabletron E21xx support
CONFIG_E2100
If you have a network (ethernet) card of this type, say Y and read
linux, read the Multiple-Ethernet-mini-HOWTO, available from
sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+NI5010 support
+CONFIG_NI5010
+ If you have a network (ethernet) card of this type, say Y and read
+ the Ethernet-HOWTO, available via ftp (user: anonymous) in
+ sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
+ one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+ available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+ Note that this is still experimental code. If you use this driver,
+ please contact the authors to join the development team.
+
NI5210 support
CONFIG_NI52
If you have a network (ethernet) card of this type, say Y and read
other console device, in which case you probably want to say Y to
"Console on serial port", below. If unsure, say N.
+Software generated cursor
+CONFIG_SOFTCURSOR
+ If you enable this option, you'll be able to do lots of nice things
+ with your cursor -- for example to turn it into a non-blinking one.
+ See Documentation/VGA-softcursor.txt for more information.
+
Standard/generic serial support
CONFIG_SERIAL
This selects whether you want to include the driver for the standard
module is called pcwd.o. If you want to compile it as a module, say
M here and read Documentation/modules.txt. Most people will say N.
+Acquire SBC Watchdog Timer
+CONFIG_ACQUIRE_WDT
+ This is the driver for the hardware watchdog on the PSC-6x86 Single
+ Board Computer produced by Acquire Inc (and others). This watchdog
+ simply watches your kernel to make sure it doesn't freeze, and if
+ it does, it resets your computer after a certain amount of time.
+ This driver is like the WDT501 driver but for different hardware.
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called pscwdt.o. If you want to compile it as a module,
+ say M here and read Documentation/modules.txt. Most people will say N.
+
Enhanced Real Time Clock Support
CONFIG_RTC
If you say Y here and create a character special file /dev/rtc with
Say Y if you need this feature; users who are only using their
system-native partitioning scheme can say N here.
+Build PowerMac Kernel (not PReP)
+CONFIG_PMAC
+ There are currently two different kinds of PowerPC-based machines
+ available: Apple Power Macintoshes and clones (such as the Motorola
+ Starmax series, and PReP (PowerPC Reference Platform) machines such
+ as the Motorola PowerStack range. Currently, a single kernel binary
+ only supports one type or the other. Say Y here to compile a kernel
+ which will run on Power Macintoshes and clones.
+
+Build PReP Kernel (not PowerMac)
+CONFIG_PREP
+ Say Y here to compile a kernel which will run on PReP (PowerPC
+ Reference Platform) machines such as the Motorola PowerStack range.
+ For Power Macintosh clones, including the Motorola Starmaxes, you
+ should say N (and Y to the previous question).
+
+Processor type
+CONFIG_MCOMMON
+ If you are compiling a kernel to run on a specific machine, you can
+ indicate which type of PowerPC processor it has. Currently this
+ option does very little.
+
+Support for Open Firmware device tree in /proc
+CONFIG_PROC_DEVICETREE
+ This option adds a device-tree directory under /proc which contains
+ an image of the device tree that the kernel copies from Open
+ Firmware. If unsure, say Y here.
+
+Support for ATI Mach64 display cards
+CONFIG_ATY_VIDEO
+ Several of the newer Power Macintoshes and clones have a video
+ display interface based on the ATI Mach64 chipset. Say N here if
+ you are sure you don't need this functionality, otherwise Y.
+
+Support for IMS Twin Turbo display card
+CONFIG_IMSTT_VIDEO
+ Some Power Macintosh clones have an IMS Twin Turbo video display
+ interface. Say Y to include support for this.
+
+MESH (Power Mac internal SCSI) support
+CONFIG_SCSI_MESH
+ Many Power Macintoshes and clones have a MESH (Macintosh Enhanced
+ SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the
+ other Power Macintoshes do). Say Y to include support for this SCSI
+ adaptor.
+
+Maximum synchronous transfer rate
+CONFIG_SCSI_MESH_SYNC_RATE
+ On Power Macintoshes (and clones) where the MESH SCSI bus adaptor
+ drives a bus which is entirely internal to the machine (such as the
+ 7500, 7600, 8500, etc.), the MESH is capable of synchronous
+ operation at up to 10MB/s. On machines where the SCSI bus
+ controlled by the MESH can have external devices connected, it is
+ usually rated at 5MB/s. 5 is a safe value here unless you know the
+ MESH SCSI bus is internal only; in that case you can say 10. Say 0
+ to disable synchronous operation.
+
+53C94 (Power Mac external SCSI) support
+CONFIG_SCSI_MAC53C94
+ On Power Macintoshes (and clones) with two SCSI buses, the external
+ SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older
+ machines which only have one SCSI bus, such as the 7200, also use
+ the 53C94. Say Y to include support for the 53C94.
+
+MACE (Power Mac ethernet) support
+CONFIG_MACE
+ Power Macintoshes and clones with ethernet built-in on the
+ motherboard will usually use a MACE (Medium Access Control for
+ Ethernet) interface. Say Y to include support for the MACE chip.
+
# need an empty line after last entry, for sed script in Configure.
#
%
\title{{\bf Linux Allocated Devices}}
\author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$}
-\date{Last revised: July 28, 1997}
+\date{Last revised: September 5, 1997}
\maketitle
%
\noindent
\major{85}{}{char }{Linux/SGI shared memory input queue}
\major{86}{}{char }{SCSI media changer}
\major{87}{}{char }{Sony Control-A1 stereo control bus}
-\major{88}{--119}{}{Unallocated}
+\major{88}{}{char }{COMX synchronous serial card}
+\major{89}{}{char }{I$^2$C bus interface}
+\major{90}{--119}{}{Unallocated}
\major{120}{--127}{}{Local/experimental use}
\major{128}{--239}{}{Unallocated}
\major{240}{--254}{}{Local/experimental use}
\minor{148}{/dev/gfx}{Linux/SGI graphics effects device}
\minor{149}{/dev/input/mouse}{Linux/SGI Irix emulation mouse}
\minor{150}{/dev/input/keyboard}{Linux/SGI Irix emulation keyboard}
+ \minor{151}{/dev/led}{Front panel LEDs}
\end{devicelist}
\begin{devicelist}
\begin{devicelist}
\major{82}{}{char }{WiNRADiO communications receiver card}
- \major{0}{/dev/winradio0}{First WiNRADiO card}
- \major{1}{/dev/winradio1}{Second WiNRADiO card}
+ \minor{0}{/dev/winradio0}{First WiNRADiO card}
+ \minor{1}{/dev/winradio1}{Second WiNRADiO card}
\minordots
\end{devicelist}
\end{devicelist}
\begin{devicelist}
-\major{88}{--119}{}{Unallocated}
+\major{88}{}{char }{COMX synchronous serial card}
+ \minor{0}{/dev/comx0}{Channel 0}
+ \minor{1}{/dev/comx1}{Channel 1}
+ \minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{89}{}{char }{I$^2$C bus interface}
+ \minor{0}{/dev/i2c0}{First I$^2$C adapter}
+ \minor{1}{/dev/i2c1}{Second I$^2$C adapter}
+ \minordots
+\end{devicelist}
+
+\begin{devicelist}
+\major{90}{--119}{}{Unallocated}
\end{devicelist}
\begin{devicelist}
LINUX ALLOCATED DEVICES
Maintained by H. Peter Anvin <hpa@zytor.com>
- Last revised: July 28, 1997
+ Last revised: September 5, 1997
This list is the successor to Rick Miller's Linux Device List, which
he stopped maintaining when he got busy with other things in 1993. It
148 = /dev/gfx Linux/SGI graphics effects device
149 = /dev/input/mouse Linux/SGI Irix emulation mouse
150 = /dev/input/keyboard Linux/SGI Irix emulation keyboard
+ 151 = /dev/led Front panel LEDs
11 char Raw keyboard device
0 = /dev/kbd Raw keyboard device
1 = /dev/controla1 Second device on chain
...
- 88-119 UNALLOCATED
+ 88 char COMX synchronous serial card
+ 0 = /dev/comx0 COMX channel 0
+ 1 = /dev/comx1 COMX channel 1
+ ...
+
+ 89 char I2C bus interface
+ 0 = /dev/i2c0 First I2C adapter
+ 1 = /dev/i2c1 Second I2C adapter
+ ...
+
+ 90-119 UNALLOCATED
120-127 LOCAL/EXPERIMENTAL USE
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 53
+SUBLEVEL = 54
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
pcibios_read_config_dword(bus->number, dev->devfn, reg, &base);
if (!base) {
/* this base-address register is unused */
+ dev->base_address[(reg - PCI_BASE_ADDRESS_0)>>2] = 0;
continue;
}
bool 'Kernel math emulation' CONFIG_MATH_EMULATION
bool 'Networking support' CONFIG_NET
-bool 'PCI bios support' CONFIG_PCI
+bool 'PCI support' CONFIG_PCI
if [ "$CONFIG_PCI" = "y" ]; then
+ bool ' PCI BIOS support' CONFIG_PCI_BIOS
+ bool ' PCI direct access support' CONFIG_PCI_DIRECT
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
bool ' PCI bridge optimization (experimental)' CONFIG_PCI_OPTIMIZE
fi
# CONFIG_MATH_EMULATION is not set
CONFIG_NET=y
CONFIG_PCI=y
+CONFIG_PCI_BIOS=y
+# CONFIG_PCI_DIRECT is not set
# CONFIG_MCA is not set
CONFIG_SYSVIPC=y
CONFIG_SYSCTL=y
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_NCR53C8XX is not set
-# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_ISP is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_LANCE is not set
# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
# CONFIG_NET_ISA is not set
CONFIG_NET_EISA=y
# CONFIG_PCNET32 is not set
# CONFIG_NET_POCKET is not set
# CONFIG_FDDI is not set
# CONFIG_DLCI is not set
-# CONFIG_PLIP is not set
# CONFIG_PPP is not set
# CONFIG_NET_RADIO is not set
# CONFIG_SLIP is not set
# CONFIG_APM is not set
# CONFIG_WATCHDOG is not set
# CONFIG_RTC is not set
+# CONFIG_H8 is not set
# CONFIG_NVRAM is not set
# CONFIG_JOYSTICK is not set
/*
* bios32.c - BIOS32, PCI BIOS functions.
*
- * $Id: bios32.c,v 1.12 1997/06/26 13:33:46 mj Exp $
+ * $Id: bios32.c,v 1.14 1997/08/02 22:20:57 mj Exp $
*
* Sponsored by
* iX Multiuser Multitasking Magazine
*
* Jun 20, 1997 : Corrected problems in "conf1" type accesses.
* (paubert@iram.es)
+ *
+ * Aug 2, 1997 : Split to PCI BIOS handling and direct PCI access parts
+ * and cleaned it up... Martin Mares <mj@atrey.karlin.mff.cuni.cz>
*/
#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
-#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
-#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
-#define PCIBIOS_FIND_PCI_DEVICE 0xb102
-#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
-#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
-#define PCIBIOS_READ_CONFIG_BYTE 0xb108
-#define PCIBIOS_READ_CONFIG_WORD 0xb109
-#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
-#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
-#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
-#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
-
-
-/* BIOS32 signature: "_32_" */
-#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
-
-/* PCI signature: "PCI " */
-#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
-
-/* PCI service signature: "$PCI" */
-#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
-
/*
- * This is the standard structure used to identify the entry point
- * to the BIOS32 Service Directory, as documented in
- * Standard BIOS 32-bit Service Directory Proposal
- * Revision 0.4 May 24, 1993
- * Phoenix Technologies Ltd.
- * Norwood, MA
- * and the PCI BIOS specification.
+ * Generic PCI access -- indirect calls according to detected HW.
*/
-union bios32 {
- struct {
- unsigned long signature; /* _32_ */
- unsigned long entry; /* 32 bit physical address */
- unsigned char revision; /* Revision level, 0 */
- unsigned char length; /* Length in paragraphs should be 01 */
- unsigned char checksum; /* All bytes must add up to zero */
- unsigned char reserved[5]; /* Must be zero */
- } fields;
- char chars[16];
-};
-
-#ifdef CONFIG_PCI
-/*
- * Physical address of the service directory. I don't know if we're
- * allowed to have more than one of these or not, so just in case
- * we'll make pcibios_present() take a memory start parameter and store
- * the array there.
- */
-
-static unsigned long bios32_entry = 0;
-static struct {
- unsigned long address;
- unsigned short segment;
-} bios32_indirect = { 0, KERNEL_CS };
-
-
-/*
- * function table for accessing PCI configuration space
- */
struct pci_access {
+ int pci_present;
int (*find_device)(unsigned short, unsigned short, unsigned short, unsigned char *, unsigned char *);
int (*find_class)(unsigned int, unsigned short, unsigned char *, unsigned char *);
int (*read_config_byte)(unsigned char, unsigned char, unsigned char, unsigned char *);
int (*write_config_dword)(unsigned char, unsigned char, unsigned char, unsigned int);
};
-/*
- * pointer to selected PCI access function table
- */
-static struct pci_access *access_pci = NULL;
-
-
-
-/*
- * Returns the entry point for the given service, NULL on error
- */
-
-static unsigned long bios32_service(unsigned long service)
+static int pci_stub(void)
{
- unsigned char return_code; /* %al */
- unsigned long address; /* %ebx */
- unsigned long length; /* %ecx */
- unsigned long entry; /* %edx */
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%edi)"
- : "=a" (return_code),
- "=b" (address),
- "=c" (length),
- "=d" (entry)
- : "0" (service),
- "1" (0),
- "D" (&bios32_indirect));
- restore_flags(flags);
-
- switch (return_code) {
- case 0:
- return address + entry;
- case 0x80: /* Not present */
- printk("bios32_service(0x%lx) : not present\n", service);
- return 0;
- default: /* Shouldn't happen */
- printk("bios32_service(0x%lx) : returned 0x%x, mail drew@colorado.edu\n",
- service, return_code);
- return 0;
- }
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
}
-static long pcibios_entry = 0;
-static struct {
- unsigned long address;
- unsigned short segment;
-} pci_indirect = { 0, KERNEL_CS };
+static struct pci_access pci_access_none = {
+ 0, /* No PCI present */
+ (void *) pci_stub, /* No functions implemented */
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub,
+ (void *) pci_stub
+};
+static struct pci_access *access_pci = &pci_access_none;
-__initfunc(static int check_pcibios(void))
+int pcibios_present(void)
{
- unsigned long signature;
- unsigned char present_status;
- unsigned char major_revision;
- unsigned char minor_revision;
- unsigned long flags;
- int pack;
-
- if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
- pci_indirect.address = pcibios_entry | PAGE_OFFSET;
-
- save_flags(flags); cli();
- __asm__("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:\tshl $8, %%eax\n\t"
- "movw %%bx, %%ax"
- : "=d" (signature),
- "=a" (pack)
- : "1" (PCIBIOS_PCI_BIOS_PRESENT),
- "D" (&pci_indirect)
- : "bx", "cx");
- restore_flags(flags);
-
- present_status = (pack >> 16) & 0xff;
- major_revision = (pack >> 8) & 0xff;
- minor_revision = pack & 0xff;
- if (present_status || (signature != PCI_SIGNATURE)) {
- printk ("pcibios_init : %s : BIOS32 Service Directory says PCI BIOS is present,\n"
- " but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
- " and signature of 0x%08lx (%c%c%c%c). mail drew@Colorado.EDU\n",
- (signature == PCI_SIGNATURE) ? "WARNING" : "ERROR",
- present_status, signature,
- (char) (signature >> 0), (char) (signature >> 8),
- (char) (signature >> 16), (char) (signature >> 24));
-
- if (signature != PCI_SIGNATURE)
- pcibios_entry = 0;
- }
- if (pcibios_entry) {
- printk ("pcibios_init : PCI BIOS revision %x.%02x entry at 0x%lx\n",
- major_revision, minor_revision, pcibios_entry);
- return 1;
- }
- }
- return 0;
+ return access_pci->pci_present;
}
-
-static int pci_bios_find_class (unsigned int class_code, unsigned short index,
+int pcibios_find_class (unsigned int class_code, unsigned short index,
unsigned char *bus, unsigned char *device_fn)
{
- unsigned long bx;
- unsigned long ret;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__ ("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=b" (bx),
- "=a" (ret)
- : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
- "c" (class_code),
- "S" ((int) index),
- "D" (&pci_indirect));
- restore_flags(flags);
- *bus = (bx >> 8) & 0xff;
- *device_fn = bx & 0xff;
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->find_class(class_code, index, bus, device_fn);
}
-
-static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
+int pcibios_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus, unsigned char *device_fn)
{
- unsigned short bx;
- unsigned short ret;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%edi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=b" (bx),
- "=a" (ret)
- : "1" (PCIBIOS_FIND_PCI_DEVICE),
- "c" (device_id),
- "d" (vendor),
- "S" ((int) index),
- "D" (&pci_indirect));
- restore_flags(flags);
- *bus = (bx >> 8) & 0xff;
- *device_fn = bx & 0xff;
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->find_device(vendor, device_id, index, bus, device_fn);
}
-static int pci_bios_read_config_byte(unsigned char bus,
+int pcibios_read_config_byte (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char *value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_BYTE),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->read_config_byte(bus, device_fn, where, value);
}
-static int pci_bios_read_config_word (unsigned char bus,
+int pcibios_read_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short *value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_WORD),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->read_config_word(bus, device_fn, where, value);
}
-static int pci_bios_read_config_dword (unsigned char bus,
+int pcibios_read_config_dword (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned int *value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=c" (*value),
- "=a" (ret)
- : "1" (PCIBIOS_READ_CONFIG_DWORD),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->read_config_dword(bus, device_fn, where, value);
}
-static int pci_bios_write_config_byte (unsigned char bus,
+int pcibios_write_config_byte (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->write_config_byte(bus, device_fn, where, value);
}
-static int pci_bios_write_config_word (unsigned char bus,
+int pcibios_write_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_WORD),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->write_config_word(bus, device_fn, where, value);
}
-static int pci_bios_write_config_dword (unsigned char bus,
+int pcibios_write_config_dword (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned int value)
{
- unsigned long ret;
- unsigned long bx = (bus << 8) | device_fn;
- unsigned long flags;
-
- save_flags(flags); cli();
- __asm__("lcall (%%esi)\n\t"
- "jc 1f\n\t"
- "xor %%ah, %%ah\n"
- "1:"
- : "=a" (ret)
- : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
- "c" (value),
- "b" (bx),
- "D" ((long) where),
- "S" (&pci_indirect));
- restore_flags(flags);
- return (int) (ret & 0xff00) >> 8;
+ return access_pci->write_config_dword(bus, device_fn, where, value);
}
/*
- * function table for BIOS32 access
+ * Direct access to PCI hardware...
*/
-static struct pci_access pci_bios_access = {
- pci_bios_find_device,
- pci_bios_find_class,
- pci_bios_read_config_byte,
- pci_bios_read_config_word,
- pci_bios_read_config_dword,
- pci_bios_write_config_byte,
- pci_bios_write_config_word,
- pci_bios_write_config_dword
-};
-
-
/*
* Given the vendor and device ids, find the n'th instance of that device
* in the system.
*/
+
+#ifdef CONFIG_PCI_DIRECT
+
static int pci_direct_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus,
unsigned char *devfn)
{
unsigned int curr = 0;
struct pci_dev *dev;
- unsigned long flags;
- save_flags(flags);
for (dev = pci_devices; dev; dev = dev->next) {
if (dev->vendor == vendor && dev->device == device_id) {
if (curr == index) {
*devfn = dev->devfn;
*bus = dev->bus->number;
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
++curr;
}
}
- restore_flags(flags);
return PCIBIOS_DEVICE_NOT_FOUND;
}
-
/*
* Given the class, find the n'th instance of that device
* in the system.
*/
+
static int pci_direct_find_class (unsigned int class_code, unsigned short index,
unsigned char *bus, unsigned char *devfn)
{
unsigned int curr = 0;
struct pci_dev *dev;
- unsigned long flags;
- save_flags(flags); cli();
for (dev = pci_devices; dev; dev = dev->next) {
if (dev->class == class_code) {
if (curr == index) {
*devfn = dev->devfn;
*bus = dev->bus->number;
- restore_flags(flags);
return PCIBIOS_SUCCESSFUL;
}
++curr;
}
}
- restore_flags(flags);
return PCIBIOS_DEVICE_NOT_FOUND;
}
/*
* Functions for accessing PCI configuration space with type 1 accesses
*/
+
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn,
#undef CONFIG_CMD
-/*
- * functiontable for type 1
- */
static struct pci_access pci_direct_conf1 = {
+ 1,
pci_direct_find_device,
pci_direct_find_class,
pci_conf1_read_config_byte,
/*
* Functions for accessing PCI configuration space with type 2 accesses
*/
+
#define IOADDR(devfn, where) ((0xC000 | ((devfn & 0x78) << 5)) + where)
#define FUNC(devfn) (((devfn & 7) << 1) | 0xf0)
#undef IOADDR
#undef FUNC
-/*
- * functiontable for type 2
- */
static struct pci_access pci_direct_conf2 = {
+ 1,
pci_direct_find_device,
pci_direct_find_class,
pci_conf2_read_config_byte,
pci_conf2_write_config_dword
};
-
-__initfunc(static struct pci_access *check_direct_pci(void))
+__initfunc(static struct pci_access *pci_check_direct(void))
{
unsigned int tmp;
unsigned long flags;
save_flags(flags); cli();
/*
- * check if configuration type 1 works
+ * Check if configuration type 1 works.
*/
outb (0x01, 0xCFB);
tmp = inl (0xCF8);
if (inl (0xCF8) == 0x80000000) {
outl (tmp, 0xCF8);
restore_flags(flags);
- printk("pcibios_init: Using configuration type 1\n");
+ printk("PCI: Using configuration type 1\n");
return &pci_direct_conf1;
}
outl (tmp, 0xCF8);
/*
- * check if configuration type 2 works
+ * Check if configuration type 2 works.
*/
outb (0x00, 0xCFB);
outb (0x00, 0xCF8);
outb (0x00, 0xCFA);
if (inb (0xCF8) == 0x00 && inb (0xCFB) == 0x00) {
restore_flags(flags);
- printk("pcibios_init: Using configuration type 2\n");
+ printk("PCI: Using configuration type 2\n");
return &pci_direct_conf2;
}
restore_flags(flags);
- printk("pcibios_init: Not supported chipset for direct PCI access !\n");
+ printk("PCI: PCI hardware not found (i.e., not present or not supported).\n");
return NULL;
}
+#endif
+
+/*
+ * BIOS32 and PCI BIOS handling.
+ */
+
+#ifdef CONFIG_PCI_BIOS
+
+#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX
+#define PCIBIOS_PCI_BIOS_PRESENT 0xb101
+#define PCIBIOS_FIND_PCI_DEVICE 0xb102
+#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103
+#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106
+#define PCIBIOS_READ_CONFIG_BYTE 0xb108
+#define PCIBIOS_READ_CONFIG_WORD 0xb109
+#define PCIBIOS_READ_CONFIG_DWORD 0xb10a
+#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b
+#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c
+#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d
+
+/* BIOS32 signature: "_32_" */
+#define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24))
+
+/* PCI signature: "PCI " */
+#define PCI_SIGNATURE (('P' << 0) + ('C' << 8) + ('I' << 16) + (' ' << 24))
+
+/* PCI service signature: "$PCI" */
+#define PCI_SERVICE (('$' << 0) + ('P' << 8) + ('C' << 16) + ('I' << 24))
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the BIOS32 Service Directory, as documented in
+ * Standard BIOS 32-bit Service Directory Proposal
+ * Revision 0.4 May 24, 1993
+ * Phoenix Technologies Ltd.
+ * Norwood, MA
+ * and the PCI BIOS specification.
+ */
+
+union bios32 {
+ struct {
+ unsigned long signature; /* _32_ */
+ unsigned long entry; /* 32 bit physical address */
+ unsigned char revision; /* Revision level, 0 */
+ unsigned char length; /* Length in paragraphs should be 01 */
+ unsigned char checksum; /* All bytes must add up to zero */
+ unsigned char reserved[5]; /* Must be zero */
+ } fields;
+ char chars[16];
+};
+
+/*
+ * Physical address of the service directory. I don't know if we're
+ * allowed to have more than one of these or not, so just in case
+ * we'll make pcibios_present() take a memory start parameter and store
+ * the array there.
+ */
+
+static unsigned long bios32_entry = 0;
+static struct {
+ unsigned long address;
+ unsigned short segment;
+} bios32_indirect = { 0, KERNEL_CS };
+
+/*
+ * Returns the entry point for the given service, NULL on error
+ */
+
+static unsigned long bios32_service(unsigned long service)
+{
+ unsigned char return_code; /* %al */
+ unsigned long address; /* %ebx */
+ unsigned long length; /* %ecx */
+ unsigned long entry; /* %edx */
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%edi)"
+ : "=a" (return_code),
+ "=b" (address),
+ "=c" (length),
+ "=d" (entry)
+ : "0" (service),
+ "1" (0),
+ "D" (&bios32_indirect));
+ restore_flags(flags);
+
+ switch (return_code) {
+ case 0:
+ return address + entry;
+ case 0x80: /* Not present */
+ printk("bios32_service(0x%lx): not present\n", service);
+ return 0;
+ default: /* Shouldn't happen */
+ printk("bios32_service(0x%lx): returned 0x%x, mail drew@colorado.edu\n",
+ service, return_code);
+ return 0;
+ }
+}
+
+static long pcibios_entry = 0;
+static struct {
+ unsigned long address;
+ unsigned short segment;
+} pci_indirect = { 0, KERNEL_CS };
+
+__initfunc(static int check_pcibios(void))
+{
+ unsigned long signature;
+ unsigned char present_status;
+ unsigned char major_revision;
+ unsigned char minor_revision;
+ unsigned long flags;
+ int pack;
-/*
- * access defined pcibios functions via
- * the function table
- */
+ if ((pcibios_entry = bios32_service(PCI_SERVICE))) {
+ pci_indirect.address = pcibios_entry | PAGE_OFFSET;
-int pcibios_present(void)
-{
- return access_pci ? 1 : 0;
+ save_flags(flags); cli();
+ __asm__("lcall (%%edi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:\tshl $8, %%eax\n\t"
+ "movw %%bx, %%ax"
+ : "=d" (signature),
+ "=a" (pack)
+ : "1" (PCIBIOS_PCI_BIOS_PRESENT),
+ "D" (&pci_indirect)
+ : "bx", "cx");
+ restore_flags(flags);
+
+ present_status = (pack >> 16) & 0xff;
+ major_revision = (pack >> 8) & 0xff;
+ minor_revision = pack & 0xff;
+ if (present_status || (signature != PCI_SIGNATURE)) {
+ printk ("PCI: %s: BIOS32 Service Directory says PCI BIOS is present,\n"
+ " but PCI_BIOS_PRESENT subfunction fails with present status of 0x%x\n"
+ " and signature of 0x%08lx (%c%c%c%c). Mail drew@Colorado.EDU\n",
+ (signature == PCI_SIGNATURE) ? "WARNING" : "ERROR",
+ present_status, signature,
+ (char) (signature >> 0), (char) (signature >> 8),
+ (char) (signature >> 16), (char) (signature >> 24));
+
+ if (signature != PCI_SIGNATURE)
+ pcibios_entry = 0;
+ }
+ if (pcibios_entry) {
+ printk ("PCI: PCI BIOS revision %x.%02x entry at 0x%lx\n",
+ major_revision, minor_revision, pcibios_entry);
+ return 1;
+ }
+ }
+ return 0;
}
-int pcibios_find_class (unsigned int class_code, unsigned short index,
+static int pci_bios_find_class (unsigned int class_code, unsigned short index,
unsigned char *bus, unsigned char *device_fn)
{
- if (access_pci && access_pci->find_class)
- return access_pci->find_class(class_code, index, bus, device_fn);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long bx;
+ unsigned long ret;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__ ("lcall (%%edi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=b" (bx),
+ "=a" (ret)
+ : "1" (PCIBIOS_FIND_PCI_CLASS_CODE),
+ "c" (class_code),
+ "S" ((int) index),
+ "D" (&pci_indirect));
+ restore_flags(flags);
+ *bus = (bx >> 8) & 0xff;
+ *device_fn = bx & 0xff;
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_find_device (unsigned short vendor, unsigned short device_id,
+static int pci_bios_find_device (unsigned short vendor, unsigned short device_id,
unsigned short index, unsigned char *bus, unsigned char *device_fn)
{
- if (access_pci && access_pci->find_device)
- return access_pci->find_device(vendor, device_id, index, bus, device_fn);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned short bx;
+ unsigned short ret;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%edi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=b" (bx),
+ "=a" (ret)
+ : "1" (PCIBIOS_FIND_PCI_DEVICE),
+ "c" (device_id),
+ "d" (vendor),
+ "S" ((int) index),
+ "D" (&pci_indirect));
+ restore_flags(flags);
+ *bus = (bx >> 8) & 0xff;
+ *device_fn = bx & 0xff;
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_read_config_byte (unsigned char bus,
+static int pci_bios_read_config_byte(unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char *value)
{
- if (access_pci && access_pci->read_config_byte)
- return access_pci->read_config_byte(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=c" (*value),
+ "=a" (ret)
+ : "1" (PCIBIOS_READ_CONFIG_BYTE),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_read_config_word (unsigned char bus,
+static int pci_bios_read_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short *value)
{
- if (access_pci && access_pci->read_config_word)
- return access_pci->read_config_word(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=c" (*value),
+ "=a" (ret)
+ : "1" (PCIBIOS_READ_CONFIG_WORD),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_read_config_dword (unsigned char bus,
+static int pci_bios_read_config_dword (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned int *value)
{
- if (access_pci && access_pci->read_config_dword)
- return access_pci->read_config_dword(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=c" (*value),
+ "=a" (ret)
+ : "1" (PCIBIOS_READ_CONFIG_DWORD),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_write_config_byte (unsigned char bus,
+static int pci_bios_write_config_byte (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned char value)
{
- if (access_pci && access_pci->write_config_byte)
- return access_pci->write_config_byte(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=a" (ret)
+ : "0" (PCIBIOS_WRITE_CONFIG_BYTE),
+ "c" (value),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-int pcibios_write_config_word (unsigned char bus,
+static int pci_bios_write_config_word (unsigned char bus,
unsigned char device_fn, unsigned char where, unsigned short value)
{
- if (access_pci && access_pci->write_config_word)
- return access_pci->write_config_word(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
-}
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
-int pcibios_write_config_dword (unsigned char bus,
- unsigned char device_fn, unsigned char where, unsigned int value)
-{
- if (access_pci && access_pci->write_config_dword)
- return access_pci->write_config_dword(bus, device_fn, where, value);
-
- return PCIBIOS_FUNC_NOT_SUPPORTED;
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=a" (ret)
+ : "0" (PCIBIOS_WRITE_CONFIG_WORD),
+ "c" (value),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
-const char *pcibios_strerror (int error)
+static int pci_bios_write_config_dword (unsigned char bus,
+ unsigned char device_fn, unsigned char where, unsigned int value)
{
- static char buf[80];
-
- switch (error) {
- case PCIBIOS_SUCCESSFUL:
- return "SUCCESSFUL";
-
- case PCIBIOS_FUNC_NOT_SUPPORTED:
- return "FUNC_NOT_SUPPORTED";
-
- case PCIBIOS_BAD_VENDOR_ID:
- return "SUCCESSFUL";
-
- case PCIBIOS_DEVICE_NOT_FOUND:
- return "DEVICE_NOT_FOUND";
-
- case PCIBIOS_BAD_REGISTER_NUMBER:
- return "BAD_REGISTER_NUMBER";
-
- case PCIBIOS_SET_FAILED:
- return "SET_FAILED";
-
- case PCIBIOS_BUFFER_TOO_SMALL:
- return "BUFFER_TOO_SMALL";
+ unsigned long ret;
+ unsigned long bx = (bus << 8) | device_fn;
+ unsigned long flags;
- default:
- sprintf (buf, "UNKNOWN RETURN 0x%x", error);
- return buf;
- }
+ save_flags(flags); cli();
+ __asm__("lcall (%%esi)\n\t"
+ "jc 1f\n\t"
+ "xor %%ah, %%ah\n"
+ "1:"
+ : "=a" (ret)
+ : "0" (PCIBIOS_WRITE_CONFIG_DWORD),
+ "c" (value),
+ "b" (bx),
+ "D" ((long) where),
+ "S" (&pci_indirect));
+ restore_flags(flags);
+ return (int) (ret & 0xff00) >> 8;
}
+/*
+ * Function table for BIOS32 access
+ */
-__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
-{
- return mem_start;
-}
+static struct pci_access pci_bios_access = {
+ 1,
+ pci_bios_find_device,
+ pci_bios_find_class,
+ pci_bios_read_config_byte,
+ pci_bios_read_config_word,
+ pci_bios_read_config_dword,
+ pci_bios_write_config_byte,
+ pci_bios_write_config_word,
+ pci_bios_write_config_dword
+};
-#endif
+/*
+ * Try to find PCI BIOS.
+ */
-__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+__initfunc(static struct pci_access *pci_find_bios(void))
{
-#ifdef CONFIG_PCI
union bios32 *check;
unsigned char sum;
int i, length;
* Follow the standard procedure for locating the BIOS32 Service
* directory by scanning the permissible address range from
* 0xe0000 through 0xfffff for a valid BIOS32 structure.
- *
*/
for (check = (union bios32 *) __va(0xe0000);
if (sum != 0)
continue;
if (check->fields.revision != 0) {
- printk("pcibios_init : unsupported revision %d at 0x%p, mail drew@colorado.edu\n",
+ printk("PCI: unsupported BIOS32 revision %d at 0x%p, mail drew@colorado.edu\n",
check->fields.revision, check);
continue;
}
- printk ("pcibios_init : BIOS32 Service Directory structure at 0x%p\n", check);
- if (!bios32_entry) {
- if (check->fields.entry >= 0x100000) {
- printk("pcibios_init: entry in high memory, trying direct PCI access\n");
- access_pci = check_direct_pci();
- } else {
- bios32_entry = check->fields.entry;
- printk ("pcibios_init : BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
- bios32_indirect.address = bios32_entry + PAGE_OFFSET;
- }
+ printk ("PCI: BIOS32 Service Directory structure at 0x%p\n", check);
+ if (check->fields.entry >= 0x100000) {
+#ifdef CONFIG_PCI_DIRECT
+ printk("PCI: BIOS32 entry in high memory, trying direct PCI access.\n");
+ return pci_check_direct();
+#else
+ printk("PCI: BIOS32 entry in high memory, cannot use.\n");
+#endif
+ } else {
+ bios32_entry = check->fields.entry;
+ printk ("PCI: BIOS32 Service Directory entry at 0x%lx\n", bios32_entry);
+ bios32_indirect.address = bios32_entry + PAGE_OFFSET;
+ if (check_pcibios())
+ return &pci_bios_access;
}
+ break; /* Hopefully more than one BIOS32 cannot happen... */
}
- if (bios32_entry && check_pcibios())
- access_pci = &pci_bios_access;
+
+ return NULL;
+}
+
+#endif
+
+/*
+ * No fixup function used.
+ */
+
+__initfunc(unsigned long pcibios_fixup(unsigned long mem_start, unsigned long mem_end))
+{
+ return mem_start;
+}
+
+/*
+ * Initialization. Try all known PCI access methods.
+ */
+
+__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end))
+{
+ struct pci_access *a = NULL;
+
+#ifdef CONFIG_PCI_BIOS
+ a = pci_find_bios();
+#else
+#ifdef CONFIG_PCI_DIRECT
+ a = pci_check_direct();
#endif
+#endif
+ if (a)
+ access_pci = a;
+
return memory_start;
}
extern volatile unsigned long smp_local_timer_ticks[1+NR_CPUS];
#endif
-#define CR0_NE 32
-
unsigned int local_irq_count[NR_CPUS];
#ifdef __SMP__
atomic_t __intel_bh_counter;
static unsigned int int_count[NR_CPUS][NR_IRQS] = {{0},};
#endif
+atomic_t nmi_counter;
+
/*
* This contains the irq mask for both irq controllers
*/
* be shot.
*/
-
static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
{
outb(0,0xF0);
int get_irq_list(char *buf)
{
- int i, len = 0;
+ int i;
struct irqaction * action;
+ char *p = buf;
for (i = 0 ; i < NR_IRQS ; i++) {
action = irq_action[i];
if (!action)
continue;
- len += sprintf(buf+len, "%2d: %10u %s",
+ p += sprintf(p, "%3d: %10u %s",
i, kstat.interrupts[i], action->name);
for (action=action->next; action; action = action->next) {
- len += sprintf(buf+len, ", %s", action->name);
+ p += sprintf(p, ", %s", action->name);
}
- len += sprintf(buf+len, "\n");
+ *p++ = '\n';
}
-/*
- * Linus - should you add NMI counts here ?????
- */
+ p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
#ifdef __SMP_PROF__
- len+=sprintf(buf+len, "IPI: %8lu received\n",
- ipi_count);
+ p += sprintf(p, "IPI: %10lu\n", ipi_count);
#endif
- return len;
+ return p - buf;
}
#ifdef __SMP_PROF__
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/spinlock.h>
+#include <asm/atomic.h>
asmlinkage int system_call(void);
asmlinkage void lcall7(void);
asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
unsigned char reason = inb(0x61);
+ extern atomic_t nmi_counter;
+ atomic_inc(&nmi_counter);
if (reason & 0x80)
mem_parity_error(reason, regs);
if (reason & 0x40)
asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs,
long error_code)
{
+#if 0
+ /* No need to warn about this any longer. */
printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
+#endif
}
/*
return free_area_init(start_mem, end_mem);
}
+/*
+ * Test if the WP bit works in supervisor mode. It isn't supported on 386's
+ * and also on some strange 486's (NexGen etc.). All 586+'s are OK. The jumps
+ * before and after the test are here to work-around some nasty CPU bugs.
+ */
+
+__initfunc(void test_wp_bit(void))
+{
+ unsigned char tmp_reg;
+ unsigned long old = pg0[0];
+
+ printk("Checking if this processor honours the WP bit even in supervisor mode... ");
+ pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
+ local_flush_tlb();
+ current->mm->mmap->vm_start += PAGE_SIZE;
+ __asm__ __volatile__(
+ "jmp 1f; 1:\n"
+ "movb %0,%1\n"
+ "movb %1,%0\n"
+ "jmp 1f; 1:\n"
+ :"=m" (*(char *) __va(0)),
+ "=q" (tmp_reg)
+ :/* no inputs */
+ :"memory");
+ pg0[0] = old;
+ local_flush_tlb();
+ current->mm->mmap->vm_start -= PAGE_SIZE;
+ if (wp_works_ok < 0) {
+ wp_works_ok = 0;
+ printk("No.\n");
+#ifndef CONFIG_M386
+ panic("This kernel doesn't support CPU's with broken WP. Recompile it for a 386!");
+#endif
+ } else
+ printk("Ok.\n");
+}
+
__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem))
{
unsigned long start_low_mem = PAGE_SIZE;
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10),
initpages << (PAGE_SHIFT-10));
-/* test if the WP bit is honoured in supervisor mode */
- if (wp_works_ok < 0) {
- unsigned char tmp_reg;
- unsigned long old = pg0[0];
- printk("Checking if this processor honours the WP bit even in supervisor mode... ");
- pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY));
- local_flush_tlb();
- current->mm->mmap->vm_start += PAGE_SIZE;
- __asm__ __volatile__(
- "movb %0,%1 ; movb %1,%0"
- :"=m" (*(char *) __va(0)),
- "=q" (tmp_reg)
- :/* no inputs */
- :"memory");
- pg0[0] = old;
- local_flush_tlb();
- current->mm->mmap->vm_start -= PAGE_SIZE;
- if (wp_works_ok < 0) {
- wp_works_ok = 0;
- printk("No.\n");
- } else
- printk("Ok.\n");
- }
- return;
+
+ if (wp_works_ok < 0)
+ test_wp_bit();
}
void free_initmem(void)
#
# Floppy, IDE, and other block devices
#
-# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_FD=y
CONFIG_BLK_DEV_MD=y
CONFIG_MD_LINEAR=m
CONFIG_MD_STRIPED=m
-/* $Id: ebus.c,v 1.7 1997/08/28 02:23:17 ecd Exp $
+/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $
* ebus.c: PCI to EBus bridge device.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
extern unsigned int psycho_irq_build(unsigned int full_ino);
-__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev))
+static inline unsigned long
+ebus_alloc(unsigned long *memory_start, size_t size)
+{
+ unsigned long mem;
+
+ *memory_start = (*memory_start + 7) & ~(7);
+ mem = *memory_start;
+ *memory_start += size;
+ return mem;
+}
+
+__initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev))
+{
+ int regs[PROMREG_MAX];
+ int irqs[PROMREG_MAX];
+ char lbuf[128];
+ int i, len;
+
+ dev->prom_node = node;
+ prom_getstring(node, "name", lbuf, sizeof(lbuf));
+ strcpy(dev->prom_name, lbuf);
+
+ len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs));
+ dev->num_addrs = len / sizeof(regs[0]);
+
+ for (i = 0; i < dev->num_addrs; i++) {
+ if (regs[i] >= dev->parent->num_addrs) {
+ prom_printf("UGH: property for %s was %d, need < %d\n",
+ dev->prom_name, len, dev->parent->num_addrs);
+ panic(__FUNCTION__);
+ }
+ dev->base_address[i] = dev->parent->base_address[regs[i]];
+ }
+
+ len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs));
+ if ((len == -1) || (len == 0)) {
+ dev->num_irqs = 0;
+ } else {
+ dev->num_irqs = len / sizeof(irqs[0]);
+ for (i = 0; i < dev->num_irqs; i++)
+ dev->irqs[i] = psycho_irq_build(irqs[i]);
+ }
+
+#ifdef DEBUG_FILL_EBUS_DEV
+ printk("child '%s': address%s\n", dev->prom_name,
+ dev->num_addrs > 1 ? "es" : "");
+ for (i = 0; i < dev->num_addrs; i++)
+ printk(" %016lx\n", dev->base_address[i]);
+ if (dev->num_irqs) {
+ printk(" IRQ%s", dev->num_irqs > 1 ? "s" : "");
+ for (i = 0; i < dev->num_irqs; i++)
+ printk(" %08x", dev->irqs[i]);
+ printk("\n");
+ }
+#endif
+}
+
+__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev,
+ unsigned long memory_start))
{
struct linux_prom_registers regs[PROMREG_MAX];
+ struct linux_ebus_child *child;
int irqs[PROMINTR_MAX];
char lbuf[128];
int i, n, len;
-#ifndef CONFIG_PCI
- return;
-#endif
dev->prom_node = node;
prom_getstring(node, "name", lbuf, sizeof(lbuf));
strcpy(dev->prom_name, lbuf);
printk("\n");
}
#endif
+ if ((node = prom_getchild(node))) {
+ dev->children = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = dev->children;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+
+ while ((node = prom_getsibling(node))) {
+ child->next = (struct linux_ebus_child *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_child));
+
+ child = child->next;
+ child->next = 0;
+ child->parent = dev;
+ fill_ebus_child(node, child);
+ }
+ }
+
+ return memory_start;
}
__initfunc(unsigned long ebus_init(unsigned long memory_start,
struct linux_ebus_device *dev;
struct linux_ebus *ebus;
struct pci_dev *pdev;
+ struct pcidev_cookie *cookie;
char lbuf[128];
unsigned long addr, *base;
- int nd, len, ebusnd, topnd;
+ unsigned short pci_command;
+ int nd, len, ebusnd;
int reg, rng, nreg;
- int devfn;
int num_ebus = 0;
-#ifndef CONFIG_PCI
- return memory_start;
-#endif
-
- memory_start = ((memory_start + 7) & (~7));
-
- topnd = psycho_root->pbm_B.prom_node;
- if (!topnd)
+ if (!pcibios_present())
return memory_start;
- ebusnd = prom_searchsiblings(prom_getchild(topnd), "ebus");
- if (ebusnd == 0) {
- printk("EBUS: No EBUS's found.\n");
+ for (pdev = pci_devices; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev) {
+ printk("ebus: No EBus's found.\n");
return memory_start;
}
- ebus_chain = ebus = (struct linux_ebus *)memory_start;
- memory_start += sizeof(struct linux_ebus);
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus_chain = ebus = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
ebus->next = 0;
while (ebusnd) {
prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf));
ebus->prom_node = ebusnd;
strcpy(ebus->prom_name, lbuf);
- ebus->parent = pbm = &psycho_root->pbm_B;
+
+ ebus->self = pdev;
+ ebus->parent = pbm = cookie->pbm;
+
+ /* Enable BUS Master. */
+ pcibios_read_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, &pci_command);
+ pci_command |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pdev->bus->number, pdev->devfn,
+ PCI_COMMAND, pci_command);
len = prom_getproperty(ebusnd, "reg", (void *)regs,
sizeof(regs));
}
nreg = len / sizeof(struct linux_prom_pci_registers);
- devfn = (regs[0].phys_hi >> 8) & 0xff;
- for (pdev = pbm->pci_bus.devices; pdev; pdev = pdev->sibling)
- if (pdev->devfn == devfn)
- break;
- if (!pdev) {
- prom_printf("%s: can't find PCI device\n",
- __FUNCTION__);
- prom_halt();
- }
- ebus->self = pdev;
-
base = &ebus->self->base_address[0];
for (reg = 0; reg < nreg; reg++) {
if (!(regs[reg].phys_hi & 0x03000000))
prom_ebus_ranges_init(ebus);
nd = prom_getchild(ebusnd);
- ebus->devices = (struct linux_ebus_device *)memory_start;
- memory_start += sizeof(struct linux_ebus_device);
+ ebus->devices = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
dev = ebus->devices;
dev->next = 0;
+ dev->children = 0;
dev->parent = ebus;
- fill_ebus_device(nd, dev);
+ memory_start = fill_ebus_device(nd, dev, memory_start);
while ((nd = prom_getsibling(nd))) {
- dev->next = (struct linux_ebus_device *)memory_start;
- memory_start += sizeof(struct linux_ebus_device);
+ dev->next = (struct linux_ebus_device *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus_device));
dev = dev->next;
dev->next = 0;
+ dev->children = 0;
dev->parent = ebus;
- fill_ebus_device(nd, dev);
+ memory_start = fill_ebus_device(nd, dev, memory_start);
}
- ebusnd = prom_searchsiblings(prom_getsibling(ebusnd), "ebus");
+ for (pdev = pdev->next; pdev; pdev = pdev->next) {
+ if ((pdev->vendor == PCI_VENDOR_ID_SUN) &&
+ (pdev->device == PCI_DEVICE_ID_SUN_EBUS))
+ break;
+ }
+ if (!pdev)
+ break;
+
+ cookie = pdev->sysdata;
+ ebusnd = cookie->prom_node;
+
+ ebus->next = (struct linux_ebus *)
+ ebus_alloc(&memory_start, sizeof(struct linux_ebus));
+ ebus = ebus->next;
+ ebus->next = 0;
++num_ebus;
}
-/* $Id: ioctl32.c,v 1.17 1997/09/03 11:54:49 ecd Exp $
+/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $
* ioctl32.c: Conversion between 32bit and 64bit native ioctls.
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#include <asm/rtc.h>
#include <asm/openpromio.h>
-/*
- * XXX: for DaveM:
- * This is the kludge to know what size of buffer to
- * copy back to the user... (ecd)
- */
-int ifr_data_len;
-
/* As gcc will warn about casting u32 to some ptr, we have to cast it to
* unsigned long first, and that's what is A() for.
* You just do (void *)A(x), instead of having to type (void *)((unsigned long)x)
case SIOCGPPPVER:
{
u32 data;
+ int len;
+
__get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data));
- /*
- * XXX: for DaveM:
- * Here we use 'ifr_data_len' to know what size of buffer to
- * copy back to the user... (ecd)
- */
- if (copy_to_user((char *)A(data), ifr.ifr_data, ifr_data_len))
+ if(cmd == SIOCGPPPVER)
+ len = strlen(PPP_VERSION) + 1;
+ else if(cmd == SIOCGPPPCSTATS)
+ len = sizeof(struct ppp_comp_stats);
+ else
+ len = sizeof(struct ppp_stats);
+
+ if (copy_to_user((char *)A(data), ifr.ifr_data, len))
return -EFAULT;
break;
}
#include <linux/blk.h>
#include <linux/cdrom.h> /* for the compatibility eject ioctl */
-
-#ifndef FLOPPY_MOTOR_MASK
-#define FLOPPY_MOTOR_MASK 0xf0
-#endif
-
#ifndef fd_get_dma_residue
#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
#endif
unsigned int cmd, unsigned long arg)
{
struct hd_geometry *loc = (struct hd_geometry *) arg;
- int dev, err;
+ int dev;
if ((!inode) || !(inode->i_rdev))
return -EINVAL;
return -EINVAL;
switch (cmd) {
case HDIO_GETGEO:
+ {
+ struct hd_geometry g;
if (!loc) return -EINVAL;
- err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
- if (err)
- return err;
- put_user(hd_info[dev].head,
- (char *) &loc->heads);
- put_user(hd_info[dev].sect,
- (char *) &loc->sectors);
- put_user(hd_info[dev].cyl,
- (short *) &loc->cylinders);
- put_user(hd[MINOR(inode->i_rdev)].start_sect,
- (long *) &loc->start);
- return 0;
+ g.heads = hd_info[dev].head;
+ g.sectors = hd_info[dev].sect;
+ g.cylinders = hd_info[dev].cyl;
+ g.start = hd[MINOR(inode->i_rdev)].start_sect;
+ return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0;
+ }
case BLKRASET:
if(!suser()) return -EACCES;
if(arg > 0xff) return -EINVAL;
return 0;
case BLKRAGET:
if (!arg) return -EINVAL;
- err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
- if (err)
- return err;
- put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
- return 0;
+ return put_user(read_ahead[MAJOR(inode->i_rdev)],
+ (long *) arg);
case BLKGETSIZE: /* Return device size */
if (!arg) return -EINVAL;
- err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
- if (err)
- return err;
- put_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);
- return 0;
+ return put_user(hd[MINOR(inode->i_rdev)].nr_sects,
+ (long *) arg);
case BLKFLSBUF:
if(!suser()) return -EACCES;
fsync_dev(inode->i_rdev);
/*
* This routine is called to flush all partitions and partition tables
- * for a changed scsi disk, and then re-read the new partition table.
+ * for a changed disk, and then re-read the new partition table.
* If we are revalidating a disk because of a media change, then we
* enter with usage == 0. If we are using an ioctl, we automatically have
* usage == 1 (we need an open channel to use an ioctl :-), so this
for (i=max_p - 1; i >=0 ; i--) {
int minor = start + i;
kdev_t devi = MKDEV(MAJOR_NR, minor);
+ struct super_block *sb = get_super(devi);
+
sync_dev(devi);
- invalidate_inodes(devi);
+ if (sb)
+ invalidate_inodes(sb);
invalidate_buffers(devi);
gdev->part[minor].start_sect = 0;
gdev->part[minor].nr_sects = 0;
#include <linux/module.h>
#include <linux/md.h>
#include <linux/raid0.h>
-#include <linux/malloc.h>
+#include <linux/vmalloc.h>
#define MAJOR_NR MD_MAJOR
#define MD_DRIVER
#define MD_PERSONALITY
-static void create_strip_zones (int minor, struct md_dev *mddev)
+static int create_strip_zones (int minor, struct md_dev *mddev)
{
int i, j, c=0;
int current_offset=0;
c=0;
}
- data->strip_zone=kmalloc (sizeof(struct strip_zone)*data->nr_strip_zones,
- GFP_KERNEL);
+ if ((data->strip_zone=vmalloc(sizeof(struct strip_zone)*data->nr_strip_zones)) == NULL)
+ return 1;
data->smallest=NULL;
data->strip_zone[i-1].size) : 0;
current_offset=smallest_by_zone->size;
}
+ return 0;
}
static int raid0_run (int minor, struct md_dev *mddev)
MOD_INC_USE_COUNT;
- mddev->private=kmalloc (sizeof (struct raid0_data), GFP_KERNEL);
+ if ((mddev->private=vmalloc (sizeof (struct raid0_data))) == NULL) return 1;
data=(struct raid0_data *) mddev->private;
- create_strip_zones (minor, mddev);
+ if (create_strip_zones (minor, mddev))
+ {
+ vfree(data);
+ return 1;
+ }
nb_zone=data->nr_zones=
md_size[minor]/data->smallest->size +
(md_size[minor]%data->smallest->size ? 1 : 0);
-
- data->hash_table=kmalloc (sizeof (struct raid0_hash)*nb_zone, GFP_KERNEL);
+ printk ("raid0 : Allocating %d bytes for hash.\n",sizeof(struct raid0_hash)*nb_zone);
+ if ((data->hash_table=vmalloc (sizeof (struct raid0_hash)*nb_zone)) == NULL)
+ {
+ vfree(data->strip_zone);
+ vfree(data);
+ return 1;
+ }
size=data->strip_zone[cur].size;
i=0;
{
struct raid0_data *data=(struct raid0_data *) mddev->private;
- kfree (data->hash_table);
- kfree (data->strip_zone);
- kfree (data);
+ vfree (data->hash_table);
+ vfree (data->strip_zone);
+ vfree (data);
MOD_DEC_USE_COUNT;
return 0;
struct inode inode, out_inode;
struct file infile, outfile;
struct dentry in_dentry, out_dentry;
- unsigned short fs;
+ unsigned long fs;
kdev_t ram_device;
int nblocks, i;
char *buf;
fi
tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
+ tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
fi
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+bool 'Tadpole ANA H8 Support' CONFIG_H8
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'PC joystick support' CONFIG_JOYSTICK
endmenu
endif
endif
+ifeq ($(CONFIG_ACQUIRE_WDT),y)
+M = y
+L_OBJS += acquirewdt.o
+else
+ ifeq ($(CONFIG_ACQUIRE_WDT),m)
+ M_OBJS += acquirewdt.o
+ MM = m
+ endif
+endif
+
ifeq ($(CONFIG_AMIGAMOUSE),y)
M = y
L_OBJS += amigamouse.o
M = y
endif
+ifdef CONFIG_H8
+LX_OBJS += h8.o
+M = y
+endif
+
ifdef M
LX_OBJS += misc.o
else
--- /dev/null
+/*
+ * Acquire Single Board Computer Watchdog Timer driver for Linux 2.1.x
+ *
+ * Based on wdt.c. Original copyright messages:
+ *
+ * (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
+ * http://www.cymru.net
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+static int acq_is_open=0;
+
+/*
+ * You must set these - there is no sane way to probe for this board.
+ */
+
+#define WDT_STOP 0x43
+#define WDT_START 0x443
+#define WATCHDOG_MINOR 130
+
+#define WD_TIMO (100*60) /* 1 minute */
+
+
+/*
+ * Kernel methods.
+ */
+
+
+static void acq_ping(void)
+{
+ /* Write a watchdog value */
+ inb_p(WDT_START);
+}
+
+static long acq_write(struct inode *inode, struct file *file, const char *buf, unsigned long count)
+{
+ if(count)
+ {
+ acq_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static long acq_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
+{
+ return -EINVAL;
+}
+
+
+
+static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ static struct watchdog_info ident=
+ {
+ WDIOF_KEEPALIVEPING, 1, "Acquire WDT"
+ };
+
+ switch(cmd)
+ {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ if (copy_to_user((int *)arg, &acq_is_open, sizeof(int)))
+ return -EFAULT;
+ break;
+
+ case WDIOC_KEEPALIVE:
+ acq_ping();
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static int acq_open(struct inode *inode, struct file *file)
+{
+ switch(MINOR(inode->i_rdev))
+ {
+ case WATCHDOG_MINOR:
+ if(acq_is_open)
+ return -EBUSY;
+ MOD_INC_USE_COUNT;
+ /*
+ * Activate
+ */
+
+ acq_is_open=1;
+ inb_p(WDT_START);
+ return 0;
+ default:
+ return -ENODEV;
+ }
+}
+
+static int acq_close(struct inode *inode, struct file *file)
+{
+ if(MINOR(inode->i_rdev)==WATCHDOG_MINOR)
+ {
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ inb_p(WDT_STOP);
+#endif
+ acq_is_open=0;
+ }
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * Notifier for system down
+ */
+
+static int acq_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if(code==SYS_DOWN || code==SYS_HALT)
+ {
+ /* Turn the card off */
+ inb_p(WDT_STOP);
+ }
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+
+static struct file_operations acq_fops = {
+ NULL,
+ acq_read,
+ acq_write,
+ NULL, /* No Readdir */
+ NULL, /* No Select */
+ acq_ioctl,
+ NULL, /* No mmap */
+ acq_open,
+ acq_close
+};
+
+static struct miscdevice acq_miscdev=
+{
+ WATCHDOG_MINOR,
+ "Acquire WDT",
+ &acq_fops
+};
+
+
+/*
+ * The WDT card needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block acq_notifier=
+{
+ acq_notify_sys,
+ NULL,
+ 0
+};
+
+#ifdef MODULE
+
+#define acq_init init_module
+
+void cleanup_module(void)
+{
+ misc_deregister(&acq_miscdev);
+ unregister_reboot_notifier(&acq_notifier);
+ release_region(WDT_STOP,1);
+ release_region(WDT_START,1);
+}
+
+#endif
+
+__initfunc(int acq_init(void))
+{
+ printk("WDT driver for Acquire single board computer initialising.\n");
+
+ misc_register(&acq_miscdev);
+ request_region(WDT_STOP, 1, "Acquire WDT");
+ request_region(WDT_START, 1, "Acquire WDT");
+ unregister_reboot_notifier(&acq_notifier);
+ return 0;
+}
+
--- /dev/null
+/*
+ */
+/*
+ * Hitachi H8/337 Microcontroller driver
+ *
+ * The H8 is used to deal with the power and thermal environment
+ * of a system.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/timer.h>
+#include <linux/fcntl.h>
+#include <linux/malloc.h>
+#include <linux/linkage.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+#endif
+#include <linux/miscdevice.h>
+#include <linux/lists.h>
+#include <linux/ioport.h>
+
+#define __KERNEL_SYSCALLS__
+#include <asm/unistd.h>
+
+#include "h8.h"
+
+#define DEBUG_H8
+
+#ifdef DEBUG_H8
+#define Dprintk printk
+#else
+#define Dprintk
+#endif
+
+#define XDprintk if(h8_debug==-1)printk
+
+/*
+ * The h8 device is one of the misc char devices.
+ */
+#define H8_MINOR_DEV 140
+
+/*
+ * Forward declarations.
+ */
+int h8_init(void);
+int h8_display_blank(void);
+int h8_display_unblank(void);
+
+static int h8_open(struct inode *, struct file *);
+static void h8_release(struct inode *, struct file *);
+static long h8_read(struct inode *, struct file *, char *, u_long);
+static int h8_select(struct inode *, struct file *, int, select_table *);
+static int h8_ioctl(struct inode *, struct file *, u_int, u_long);
+
+static void h8_intr(int irq, void *dev_id, struct pt_regs *regs);
+
+#ifdef CONFIG_PROC_FS
+static int h8_get_info(char *, char **, off_t, int, int);
+#endif
+
+/*
+ * Support Routines.
+ */
+static void h8_hw_init(void);
+static void h8_start_new_cmd(void);
+static void h8_send_next_cmd_byte(void);
+static void h8_read_event_status(void);
+static void h8_sync(void);
+static void h8_q_cmd(u_char *, int, int);
+static void h8_cmd_done(h8_cmd_q_t *qp);
+static int h8_alloc_queues(void);
+
+static u_long h8_get_cpu_speed(void);
+static int h8_get_curr_temp(u_char curr_temp[]);
+static void h8_get_max_temp(void);
+static void h8_get_upper_therm_thold(void);
+static void h8_set_upper_therm_thold(int);
+static int h8_get_ext_status(u_char stat_word[]);
+
+static int h8_monitor_thread(void *);
+
+static int h8_manage_therm(void);
+static void h8_set_cpu_speed(int speed_divisor);
+
+static void h8_start_monitor_timer(unsigned long secs);
+static void h8_activate_monitor(unsigned long unused);
+
+/* in arch/alpha/kernel/lca.c */
+extern void lca_clock_print(void);
+extern int lca_get_clock(void);
+extern void lca_clock_fiddle(int);
+
+static void h8_set_event_mask(int);
+static void h8_clear_event_mask(int);
+
+/*
+ * Driver structures
+ */
+
+static struct timer_list h8_monitor_timer;
+static int h8_monitor_timer_active = 0;
+
+static char driver_version[] = "X0.0";/* no spaces */
+
+static struct file_operations h8_fops = {
+ NULL, /* lseek */
+ h8_read,
+ NULL, /* write */
+ NULL, /* readdir */
+ h8_select,
+ h8_ioctl,
+ NULL, /* mmap */
+ h8_open,
+ h8_release,
+ NULL, /* fsync */
+ NULL /* fasync */
+};
+
+static struct miscdevice h8_device = {
+ H8_MINOR_DEV,
+ "h8",
+ &h8_fops
+};
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry h8_proc_entry = {
+ 0, 3, "h8", S_IFREG | S_IRUGO, 1, 0, 0, 0, 0, h8_get_info
+};
+#endif
+
+union intr_buf intrbuf;
+int intr_buf_ptr;
+union intr_buf xx;
+u_char last_temp;
+
+/*
+ * I/O Macros for register reads and writes.
+ */
+#define H8_READ(a) inb((a))
+#define H8_WRITE(d,a) outb((d),(a))
+
+#define H8_GET_STATUS H8_READ((h8_base) + H8_STATUS_REG_OFF)
+#define H8_READ_DATA H8_READ((h8_base) + H8_DATA_REG_OFF)
+#define WRITE_DATA(d) H8_WRITE((d), h8_base + H8_DATA_REG_OFF)
+#define WRITE_CMD(d) H8_WRITE((d), h8_base + H8_CMD_REG_OFF)
+
+unsigned int h8_base = H8_BASE_ADDR;
+unsigned int h8_irq = H8_IRQ;
+unsigned int h8_state = H8_IDLE;
+unsigned int h8_index = -1;
+unsigned int h8_enabled = 0;
+
+queue_head_t h8_actq, h8_cmdq, h8_freeq;
+
+/*
+ * Globals used in thermal control of Alphabook1.
+ */
+int cpu_speed_divisor = -1;
+int h8_event_mask = 0;
+struct wait_queue *h8_monitor_wait = NULL;
+unsigned int h8_command_mask = 0;
+int h8_uthermal_threshold = DEFAULT_UTHERMAL_THRESHOLD;
+int h8_uthermal_window = UTH_HYSTERESIS;
+int h8_debug = 0xfffffdfc;
+int h8_ldamp = MHZ_115;
+int h8_udamp = MHZ_57;
+u_char h8_current_temp = 0;
+u_char h8_system_temp = 0;
+int h8_sync_channel = 0;
+struct wait_queue *h8_sync_wait = NULL;
+int h8_init_performed;
+
+/* CPU speeds and clock divisor values */
+int speed_tab[6] = {230, 153, 115, 57, 28, 14};
+
+/*
+ * H8 interrupt handler
+ */
+static void h8_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ u_char stat_reg, data_reg;
+ h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+
+ stat_reg = H8_GET_STATUS;
+ data_reg = H8_READ_DATA;
+
+ XDprintk("h8_intr: state %d status 0x%x data 0x%x\n", h8_state, stat_reg, data_reg);
+
+ switch (h8_state) {
+ /* Response to an asynchronous event. */
+ case H8_IDLE: { /* H8_IDLE */
+ if (stat_reg & H8_OFULL) {
+ if (data_reg == H8_INTR) {
+ h8_state = H8_INTR_MODE;
+ /* Executing a command to determine what happened. */
+ WRITE_CMD(H8_RD_EVENT_STATUS);
+ intr_buf_ptr = 1;
+ WRITE_CMD(H8_RD_EVENT_STATUS);
+ } else {
+ Dprintk("h8_intr: idle stat 0x%x data 0x%x\n",
+ stat_reg, data_reg);
+ }
+ } else {
+ Dprintk("h8_intr: bogus interrupt\n");
+ }
+ break;
+ }
+ case H8_INTR_MODE: { /* H8_INTR_MODE */
+ XDprintk("H8 intr/intr_mode\n");
+ if (data_reg == H8_BYTE_LEVEL_ACK) {
+ return;
+ } else if (data_reg == H8_CMD_ACK) {
+ return;
+ } else {
+ intrbuf.byte[intr_buf_ptr] = data_reg;
+ if(!intr_buf_ptr) {
+ h8_state = H8_IDLE;
+ h8_read_event_status();
+ }
+ intr_buf_ptr--;
+ }
+ break;
+ }
+ /* Placed in this state by h8_start_new_cmd(). */
+ case H8_XMIT: { /* H8_XMIT */
+ XDprintk("H8 intr/xmit\n");
+ /* If a byte level acknowledgement has been received */
+ if (data_reg == H8_BYTE_LEVEL_ACK) {
+ XDprintk("H8 intr/xmit BYTE ACK\n");
+ qp->nacks++;
+ if (qp->nacks > qp->ncmd)
+ if(h8_debug & 0x1)
+ Dprintk("h8intr: bogus # of acks!\n");
+ /*
+ * If the number of bytes sent is less than the total
+ * number of bytes in the command.
+ */
+ if (qp->cnt < qp->ncmd) {
+ h8_send_next_cmd_byte();
+ }
+ return;
+ /* If the complete command has produced an acknowledgement. */
+ } else if (data_reg == H8_CMD_ACK) {
+ XDprintk("H8 intr/xmit CMD ACK\n");
+ /* If there are response bytes */
+ if (qp->nrsp)
+ h8_state = H8_RCV;
+ else
+ h8_state = H8_IDLE;
+ qp->cnt = 0;
+ return;
+ /* Error, need to start over with a clean slate. */
+ } else if (data_reg == H8_NACK) {
+ XDprintk("h8_intr: NACK received restarting command\n");
+ qp->nacks = 0;
+ qp->cnt = 0;
+ h8_state = H8_IDLE;
+ WRITE_CMD(H8_SYNC);
+ return;
+ } else {
+ Dprintk ("h8intr: xmit unknown data 0x%x \n", data_reg);
+ return;
+ }
+ break;
+ }
+ case H8_RESYNC: { /* H8_RESYNC */
+ XDprintk("H8 intr/resync\n");
+ if (data_reg == H8_BYTE_LEVEL_ACK) {
+ return;
+ } else if (data_reg == H8_SYNC_BYTE) {
+ h8_state = H8_IDLE;
+ if (!QUEUE_EMPTY(&h8_actq, link))
+ h8_send_next_cmd_byte();
+ } else {
+ Dprintk ("h8_intr: resync unknown data 0x%x \n", data_reg);
+ return;
+ }
+ break;
+ }
+ case H8_RCV: { /* H8_RCV */
+ XDprintk("H8 intr/rcv\n");
+ if (qp->cnt < qp->nrsp) {
+ qp->rcvbuf[qp->cnt] = data_reg;
+ qp->cnt++;
+ /* If command reception finished. */
+ if (qp->cnt == qp->nrsp) {
+ h8_state = H8_IDLE;
+ QUEUE_REMOVE(&h8_actq, qp, link);
+ h8_cmd_done (qp);
+ /* More commands to send over? */
+ if (!QUEUE_EMPTY(&h8_cmdq, link))
+ h8_start_new_cmd();
+ }
+ return;
+ } else {
+ Dprintk ("h8intr: rcv overflow cmd 0x%x\n", qp->cmdbuf[0]);
+ }
+ break;
+ }
+ default: /* default */
+ Dprintk("H8 intr/unknown\n");
+ break;
+ }
+ return;
+}
+
+#ifdef MODULE
+
+int init_module(void)
+{
+ printk("H8 module at %X(Interrupt %d)\n", h8_base, h8_irq);
+ if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
+ {
+ printk("H8: error: IRQ %d is not free.\n", h8_irq);
+ return -EIO;
+ }
+
+ misc_register(&h8_device);
+ request_region(h8_base, 8, "h8");
+
+#ifdef CONFIG_PROC_FS
+ proc_register_dynamic(&proc_root, &h8_proc_entry);
+#endif
+
+ QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
+ QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
+ QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
+ h8_alloc_queues();
+
+ h8_hw_init();
+
+ kernel_thread(h8_monitor_thread, NULL, 0);
+
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ misc_deregister(&h8_device);
+ release_region(h8_base, 8);
+ free_irq(h8_irq, NULL);
+}
+
+#else /* MODULE */
+
+int h8_init(void)
+{
+ if(request_irq(h8_irq, h8_intr, SA_INTERRUPT, "h8", NULL))
+ {
+ printk("H8: error: IRQ %d is not free\n", h8_irq);
+ return -EIO;
+ }
+ printk("H8 at 0x%x IRQ %d\n", h8_base, h8_irq);
+
+#ifdef CONFIG_PROC_FS
+ proc_register_dynamic(&proc_root, &h8_proc_entry);
+#endif
+
+ misc_register(&h8_device);
+ request_region(h8_base, 8, "h8");
+
+ QUEUE_INIT(&h8_actq, link, h8_cmd_q_t *);
+ QUEUE_INIT(&h8_cmdq, link, h8_cmd_q_t *);
+ QUEUE_INIT(&h8_freeq, link, h8_cmd_q_t *);
+ h8_alloc_queues();
+
+ h8_hw_init();
+
+ kernel_thread(h8_monitor_thread, NULL, 0);
+
+ return 0;
+}
+#endif /* MODULE */
+
+void h8_hw_init(void)
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+
+ /* set CPU speed to max for booting */
+ h8_set_cpu_speed(MHZ_230);
+
+ /*
+ * Initialize the H8
+ */
+ h8_sync(); /* activate interrupts */
+
+ /* To clear conditions left by console */
+ h8_read_event_status();
+
+ /* Perform a conditioning read */
+ buf[0] = H8_DEVICE_CONTROL;
+ buf[1] = 0xff;
+ buf[2] = 0x0;
+ h8_q_cmd(buf, 3, 1);
+
+ /* Turn on built-in and external mice, capture power switch */
+ buf[0] = H8_DEVICE_CONTROL;
+ buf[1] = 0x0;
+ buf[2] = H8_ENAB_INT_PTR | H8_ENAB_EXT_PTR |
+ /*H8_DISAB_PWR_OFF_SW |*/ H8_ENAB_LOW_SPD_IND;
+ h8_q_cmd(buf, 3, 1);
+
+ h8_enabled = 1;
+ return;
+}
+
+#ifdef CONFIG_PROC_FS
+int h8_get_info(char *buf, char **start, off_t fpos, int length, int dummy)
+{
+ char *p;
+
+ if (!h8_enabled)
+ return 0;
+ p = buf;
+
+
+ /*
+ 0) Linux driver version (this will change if format changes)
+ 1)
+ 2)
+ 3)
+ 4)
+ */
+
+ p += sprintf(p, "%s \n",
+ driver_version
+ );
+
+ return p - buf;
+}
+#endif
+
+static long h8_read(struct inode *inode, struct file *fp, char *buf,
+ u_long count)
+{
+ printk("h8_read: IMPDEL\n");
+ return 0;
+}
+
+static int h8_select(struct inode *inode, struct file *fp, int sel_type,
+ select_table * wait)
+{
+ printk("h8_select: IMPDEL\n");
+ return 0;
+}
+
+static int h8_ioctl(struct inode * inode, struct file *filp,
+ u_int cmd, u_long arg)
+{
+ printk("h8_ioctl: IMPDEL\n");
+ return 0;
+}
+
+static void h8_release(struct inode * inode, struct file * filp)
+{
+ printk("h8_release: IMPDEL\n");
+}
+
+static int h8_open(struct inode * inode, struct file * filp)
+{
+ printk("h8_open: IMPDEL\n");
+ return 0;
+}
+
+/* Called from console driver -- must make sure h8_enabled. */
+int h8_display_blank(void)
+{
+#ifdef CONFIG_H8_DISPLAY_BLANK
+ int error;
+
+ if (!h8_enabled)
+ return 0;
+ error = h8_set_display_power_state(H8_STATE_STANDBY);
+ if (error == H8_SUCCESS)
+ return 1;
+ h8_error("set display standby", error);
+#endif
+ return 0;
+}
+
+/* Called from console driver -- must make sure h8_enabled. */
+int h8_display_unblank(void)
+{
+#ifdef CONFIG_H8_DISPLAY_BLANK
+ int error;
+
+ if (!h8_enabled)
+ return 0;
+ error = h8_set_display_power_state(H8_STATE_READY);
+ if (error == H8_SUCCESS)
+ return 1;
+ h8_error("set display ready", error);
+#endif
+ return 0;
+}
+
+int
+h8_alloc_queues(void)
+{
+ h8_cmd_q_t *qp;
+ unsigned long flags;
+ int i;
+
+ qp = (h8_cmd_q_t *)kmalloc((sizeof (h8_cmd_q_t) * H8_Q_ALLOC_AMOUNT),
+ GFP_KERNEL);
+
+ if (!qp) {
+ printk("H8: could not allocate memory for command queue\n");
+ return(0);
+ }
+ /* add to the free queue */
+ save_flags(flags); cli();
+ for (i = 0; i < H8_Q_ALLOC_AMOUNT; i++) {
+ /* place each at front of freeq */
+ QUEUE_ENTER(&h8_freeq, &qp[i], link, h8_cmd_q_t *);
+ }
+ restore_flags(flags);
+ return (1);
+}
+
+/*
+ * Basic means by which commands are sent to the H8.
+ */
+void
+h8_q_cmd(u_char *cmd, int cmd_size, int resp_size)
+{
+ h8_cmd_q_t *qp;
+ unsigned long flags;
+ int i;
+
+ /* get cmd buf */
+ save_flags(flags); cli();
+ while (QUEUE_EMPTY(&h8_freeq, link)) {
+ Dprintk("H8: need to allocate more cmd buffers\n");
+ restore_flags(flags);
+ h8_alloc_queues();
+ save_flags(flags); cli();
+ }
+ /* get first element from queue */
+ qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_freeq, link);
+ QUEUE_REMOVE(&h8_freeq, qp, link);
+
+ restore_flags(flags);
+
+ /* fill it in */
+ for (i = 0; i < cmd_size; i++)
+ qp->cmdbuf[i] = cmd[i];
+ qp->ncmd = cmd_size;
+ qp->nrsp = resp_size;
+
+ /* queue it at the end of the cmd queue */
+ save_flags(flags); cli();
+
+ QUEUE_ENTER(&h8_cmdq, qp, link, h8_cmd_q_t *);
+
+ restore_flags(flags);
+
+ h8_start_new_cmd();
+}
+
+void
+h8_start_new_cmd(void)
+{
+ unsigned long flags;
+ h8_cmd_q_t *qp;
+
+ save_flags(flags); cli();
+ if (h8_state != H8_IDLE) {
+ if (h8_debug & 0x1)
+ Dprintk("h8_start_new_cmd: not idle\n");
+ restore_flags(flags);
+ return;
+ }
+
+ if (!QUEUE_EMPTY(&h8_actq, link)) {
+ Dprintk("h8_start_new_cmd: inconsistency: IDLE with non-empty active queue!\n");
+ restore_flags(flags);
+ return;
+ }
+
+ if (QUEUE_EMPTY(&h8_cmdq, link)) {
+ Dprintk("h8_start_new_cmd: no command to dequeue\n");
+ restore_flags(flags);
+ return;
+ }
+ /*
+ * Take first command off of the command queue and put
+ * it on the active queue.
+ */
+ qp = (h8_cmd_q_t *) QUEUE_FIRST(&h8_cmdq, link);
+ QUEUE_REMOVE(&h8_cmdq, qp, link);
+ QUEUE_ENTER(&h8_actq, qp, link, h8_cmd_q_t *);
+ h8_state = H8_XMIT;
+ if (h8_debug & 0x1)
+ Dprintk("h8_start_new_cmd: Starting a command\n");
+
+ qp->cnt = 1;
+ WRITE_CMD(qp->cmdbuf[0]); /* Kick it off */
+
+ restore_flags(flags);
+ return;
+}
+
+void
+h8_send_next_cmd_byte(void)
+{
+ h8_cmd_q_t *qp = (h8_cmd_q_t *)QUEUE_FIRST(&h8_actq, link);
+ int cnt;
+
+ cnt = qp->cnt;
+ qp->cnt++;
+
+ if (h8_debug & 0x1)
+ Dprintk("h8 sending next cmd byte 0x%x (0x%x)\n",
+ cnt, qp->cmdbuf[cnt]);
+
+ if (cnt) {
+ WRITE_DATA(qp->cmdbuf[cnt]);
+ } else {
+ WRITE_CMD(qp->cmdbuf[cnt]);
+ }
+ return;
+}
+
+/*
+ * Synchronize H8 communications channel for command transmission.
+ */
+void
+h8_sync(void)
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+
+ buf[0] = H8_SYNC;
+ buf[1] = H8_SYNC_BYTE;
+ h8_q_cmd(buf, 2, 1);
+}
+
+/*
+ * Responds to external interrupt. Reads event status word and
+ * decodes type of interrupt.
+ */
+void
+h8_read_event_status(void)
+{
+
+ if(h8_debug & 0x200)
+ printk("h8_read_event_status: value 0x%x\n", intrbuf.word);
+
+ /*
+ * Power related items
+ */
+ if (intrbuf.word & H8_DC_CHANGE) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: DC_CHANGE\n");
+ /* see if dc added or removed, set batt/dc flag, send event */
+
+ h8_set_event_mask(H8_MANAGE_BATTERY);
+ wake_up(&h8_monitor_wait);
+ }
+
+ if (intrbuf.word & H8_POWER_BUTTON) {
+ printk("Power switch pressed - please wait - preparing to power
+off\n");
+ h8_set_event_mask(H8_POWER_BUTTON);
+ wake_up(&h8_monitor_wait);
+ }
+
+ /*
+ * Thermal related items
+ */
+ if (intrbuf.word & H8_THERMAL_THRESHOLD) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: THERMAL_THRESHOLD\n");
+ h8_set_event_mask(H8_MANAGE_UTHERM);
+ wake_up(&h8_monitor_wait);
+ }
+
+ /*
+ * nops -for now
+ */
+ if (intrbuf.word & H8_DOCKING_STATION_STATUS) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: DOCKING_STATION_STATUS\n");
+ /* read_ext_status */
+ }
+ if (intrbuf.word & H8_EXT_BATT_STATUS) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: EXT_BATT_STATUS\n");
+
+ }
+ if (intrbuf.word & H8_EXT_BATT_CHARGE_STATE) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: EXT_BATT_CHARGE_STATE\n");
+
+ }
+ if (intrbuf.word & H8_BATT_CHANGE_OVER) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: BATT_CHANGE_OVER\n");
+
+ }
+ if (intrbuf.word & H8_WATCHDOG) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: WATCHDOG\n");
+ /* nop */
+ }
+ if (intrbuf.word & H8_SHUTDOWN) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: SHUTDOWN\n");
+ /* nop */
+ }
+ if (intrbuf.word & H8_KEYBOARD) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: KEYBOARD\n");
+ /* nop */
+ }
+ if (intrbuf.word & H8_EXT_MOUSE_OR_CASE_SWITCH) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: EXT_MOUSE_OR_CASE_SWITCH\n");
+ /* read_ext_status*/
+ }
+ if (intrbuf.word & H8_INT_BATT_LOW) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: INT_BATT_LOW\n");
+ /* post event, warn user */
+ }
+ if (intrbuf.word & H8_INT_BATT_CHARGE_STATE) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: INT_BATT_CHARGE_STATE\n");
+ /* nop - happens often */
+ }
+ if (intrbuf.word & H8_INT_BATT_STATUS) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: INT_BATT_STATUS\n");
+
+ }
+ if (intrbuf.word & H8_INT_BATT_CHARGE_THRESHOLD) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: INT_BATT_CHARGE_THRESHOLD\n");
+ /* nop - happens often */
+ }
+ if (intrbuf.word & H8_EXT_BATT_LOW) {
+ if(h8_debug & 0x4)
+ printk("h8_read_event_status: EXT_BATT_LOW\n");
+ /*if no internal, post event, warn user */
+ /* else nop */
+ }
+
+ return;
+}
+
+/*
+ * Function called when H8 has performed requested command.
+ */
+void
+h8_cmd_done(h8_cmd_q_t *qp)
+{
+
+ /* what to do */
+ switch (qp->cmdbuf[0]) {
+ case H8_SYNC:
+ if (h8_debug & 0x40000)
+ printk("H8: Sync command done - byte returned was 0x%x\n",
+ qp->rcvbuf[0]);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_SN:
+ case H8_RD_ENET_ADDR:
+ printk("H8: Read ethernet addr - command done - address: %x - %x - %x - %x - %x - %x \n",
+ qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2],
+ qp->rcvbuf[3], qp->rcvbuf[4], qp->rcvbuf[5]);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_HW_VER:
+ case H8_RD_MIC_VER:
+ case H8_RD_MAX_TEMP:
+ printk("H8: Max recorded CPU temp %d, Sys temp %d\n",
+ qp->rcvbuf[0], qp->rcvbuf[1]);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_MIN_TEMP:
+ printk("H8: Min recorded CPU temp %d, Sys temp %d\n",
+ qp->rcvbuf[0], qp->rcvbuf[1]);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_CURR_TEMP:
+ h8_sync_channel |= H8_RD_CURR_TEMP;
+ xx.byte[0] = qp->rcvbuf[0];
+ xx.byte[1] = qp->rcvbuf[1];
+ wake_up(&h8_sync_wait);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_SYS_VARIENT:
+ case H8_RD_PWR_ON_CYCLES:
+ printk(" H8: RD_PWR_ON_CYCLES command done\n");
+ break;
+
+ case H8_RD_PWR_ON_SECS:
+ printk("H8: RD_PWR_ON_SECS command done\n");
+ break;
+
+ case H8_RD_RESET_STATUS:
+ case H8_RD_PWR_DN_STATUS:
+ case H8_RD_EVENT_STATUS:
+ case H8_RD_ROM_CKSM:
+ case H8_RD_EXT_STATUS:
+ xx.byte[1] = qp->rcvbuf[0];
+ xx.byte[0] = qp->rcvbuf[1];
+ h8_sync_channel |= H8_GET_EXT_STATUS;
+ wake_up(&h8_sync_wait);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_USER_CFG:
+ case H8_RD_INT_BATT_VOLT:
+ case H8_RD_DC_INPUT_VOLT:
+ case H8_RD_HORIZ_PTR_VOLT:
+ case H8_RD_VERT_PTR_VOLT:
+ case H8_RD_EEPROM_STATUS:
+ case H8_RD_ERR_STATUS:
+ case H8_RD_NEW_BUSY_SPEED:
+ case H8_RD_CONFIG_INTERFACE:
+ case H8_RD_INT_BATT_STATUS:
+ printk("H8: Read int batt status cmd done - returned was %x %x %x\n",
+ qp->rcvbuf[0], qp->rcvbuf[1], qp->rcvbuf[2]);
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_RD_EXT_BATT_STATUS:
+ case H8_RD_PWR_UP_STATUS:
+ case H8_RD_EVENT_STATUS_MASK:
+ case H8_CTL_EMU_BITPORT:
+ case H8_DEVICE_CONTROL:
+ if(h8_debug & 0x20000) {
+ printk("H8: Device control cmd done - byte returned was 0x%x\n",
+ qp->rcvbuf[0]);
+ }
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_CTL_TFT_BRT_DC:
+ case H8_CTL_WATCHDOG:
+ case H8_CTL_MIC_PROT:
+ case H8_CTL_INT_BATT_CHG:
+ case H8_CTL_EXT_BATT_CHG:
+ case H8_CTL_MARK_SPACE:
+ case H8_CTL_MOUSE_SENSITIVITY:
+ case H8_CTL_DIAG_MODE:
+ case H8_CTL_IDLE_AND_BUSY_SPDS:
+ printk("H8: Idle and busy speed command done\n");
+ break;
+
+ case H8_CTL_TFT_BRT_BATT:
+ case H8_CTL_UPPER_TEMP:
+ if(h8_debug & 0x10) {
+ XDprintk("H8: ctl upper thermal thresh cmd done - returned was %d\n",
+ qp->rcvbuf[0]);
+ }
+ QUEUE_ENTER(&h8_freeq, qp, link, h8_cmd_q_t *);
+ break;
+
+ case H8_CTL_LOWER_TEMP:
+ case H8_CTL_TEMP_CUTOUT:
+ case H8_CTL_WAKEUP:
+ case H8_CTL_CHG_THRESHOLD:
+ case H8_CTL_TURBO_MODE:
+ case H8_SET_DIAG_STATUS:
+ case H8_SOFTWARE_RESET:
+ case H8_RECAL_PTR:
+ case H8_SET_INT_BATT_PERCENT:
+ case H8_WRT_CFG_INTERFACE_REG:
+ case H8_WRT_EVENT_STATUS_MASK:
+ case H8_ENTER_POST_MODE:
+ case H8_EXIT_POST_MODE:
+ case H8_RD_EEPROM:
+ case H8_WRT_EEPROM:
+ case H8_WRT_TO_STATUS_DISP:
+ printk("H8: Write IO status display command done\n");
+ break;
+
+ case H8_DEFINE_SPC_CHAR:
+ case H8_DEFINE_TABLE_STRING_ENTRY:
+ case H8_PERFORM_EMU_CMD:
+ case H8_EMU_RD_REG:
+ case H8_EMU_WRT_REG:
+ case H8_EMU_RD_RAM:
+ case H8_EMU_WRT_RAM:
+ case H8_BQ_RD_REG:
+ case H8_BQ_WRT_REG:
+ case H8_PWR_OFF:
+ printk ("H8: misc command completed\n");
+ break;
+ }
+ return;
+}
+
+/*
+ * Retrieve the current cpu temperature and case temperature. Provides
+ * the feedback for the thermal control algorithm. Synchcronized via
+ * sleep() for priority so that no other actions in the process will take
+ * place before the data becomes available.
+ */
+int
+h8_get_curr_temp(u_char curr_temp[])
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+ unsigned long flags;
+
+ memset(buf, 0, H8_MAX_CMD_SIZE);
+ buf[0] = H8_RD_CURR_TEMP;
+
+ h8_q_cmd(buf, 1, 2);
+
+ save_flags(flags); cli();
+
+ while((h8_sync_channel & H8_RD_CURR_TEMP) == 0)
+ sleep_on(&h8_sync_wait);
+
+ restore_flags(flags);
+
+ h8_sync_channel &= ~H8_RD_CURR_TEMP;
+ curr_temp[0] = xx.byte[0];
+ curr_temp[1] = xx.byte[1];
+ xx.word = 0;
+
+ if(h8_debug & 0x8)
+ printk("H8: curr CPU temp %d, Sys temp %d\n",
+ curr_temp[0], curr_temp[1]);
+ return 0;
+}
+
+static void
+h8_get_max_temp(void)
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+
+ buf[0] = H8_RD_MAX_TEMP;
+ h8_q_cmd(buf, 1, 2);
+}
+
+/*
+ * Assigns an upper limit to the value of the H8 thermal interrupt.
+ * As an example setting a value of 115 F here will cause the
+ * interrupt to trigger when the cpu temperature reaches 115 F.
+ */
+static void
+h8_set_upper_therm_thold(int thold)
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+
+ /* write 0 to reinitialize interrupt */
+ buf[0] = H8_CTL_UPPER_TEMP;
+ buf[1] = 0x0;
+ buf[2] = 0x0;
+ h8_q_cmd(buf, 3, 1);
+
+ /* Do it for real */
+ buf[0] = H8_CTL_UPPER_TEMP;
+ buf[1] = 0x0;
+ buf[2] = thold;
+ h8_q_cmd(buf, 3, 1);
+}
+
+static void
+h8_get_upper_therm_thold(void)
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+
+ buf[0] = H8_CTL_UPPER_TEMP;
+ buf[1] = 0xff;
+ buf[2] = 0;
+ h8_q_cmd(buf, 3, 1);
+}
+
+/*
+ * The external status word contains information on keyboard controller,
+ * power button, changes in external batt status, change in DC state,
+ * docking station, etc. General purpose querying use.
+ */
+int
+h8_get_ext_status(u_char stat_word[])
+{
+ u_char buf[H8_MAX_CMD_SIZE];
+ unsigned long flags;
+
+ memset(buf, 0, H8_MAX_CMD_SIZE);
+ buf[0] = H8_RD_EXT_STATUS;
+
+ h8_q_cmd(buf, 1, 2);
+
+ save_flags(flags); cli();
+
+ while((h8_sync_channel & H8_GET_EXT_STATUS) == 0)
+ sleep_on(&h8_sync_wait);
+
+ restore_flags(flags);
+
+ h8_sync_channel &= ~H8_GET_EXT_STATUS;
+ stat_word[0] = xx.byte[0];
+ stat_word[1] = xx.byte[1];
+ xx.word = 0;
+
+ if(h8_debug & 0x8)
+ printk("H8: curr ext status %x, %x\n",
+ stat_word[0], stat_word[1]);
+
+ return 0;
+}
+
+/*
+ * Thread attached to task 0 manages thermal/physcial state of Alphabook.
+ * When a condition is detected by the interrupt service routine, the
+ * isr does a wakeup() on h8_monitor_wait. The mask value is then
+ * screened for the appropriate action.
+ */
+
+int
+h8_monitor_thread(void * unused)
+{
+ u_char curr_temp[2];
+
+ /*
+ * Need a logic based safety valve here. During boot when this thread is
+ * started and the thermal interrupt is not yet initialized this logic
+ * checks the temperature and acts accordingly. When this path is acted
+ * upon system boot is painfully slow, however, the priority associated
+ * with overheating is high enough to warrant this action.
+ */
+ h8_get_curr_temp(curr_temp);
+
+ printk("H8: Initial CPU temp: %d\n", curr_temp[0]);
+
+ if(curr_temp[0] >= h8_uthermal_threshold) {
+ h8_set_event_mask(H8_MANAGE_UTHERM);
+ h8_manage_therm();
+ } else {
+ /*
+ * Arm the upper thermal limit of the H8 so that any temp in
+ * excess will trigger the thermal control mechanism.
+ */
+ h8_set_upper_therm_thold(h8_uthermal_threshold);
+ }
+
+ for(;;) {
+ sleep_on(&h8_monitor_wait);
+
+ if(h8_debug & 0x2)
+ printk("h8_monitor_thread awakened, mask:%x\n",
+ h8_event_mask);
+
+ if (h8_event_mask & (H8_MANAGE_UTHERM|H8_MANAGE_LTHERM)) {
+ h8_manage_therm();
+ }
+
+#if 0
+ if (h8_event_mask & H8_POWER_BUTTON) {
+ h8_system_down();
+ }
+
+ /*
+ * If an external DC supply is removed or added make
+ * appropriate cpu speed adjustments.
+ */
+ if (h8_event_mask & H8_MANAGE_BATTERY) {
+ h8_run_level_3_manage(H8_RUN);
+ h8_clear_event_mask(H8_MANAGE_BATTERY);
+ }
+#endif
+ }
+}
+
+/*
+ * Function implements the following policy. When the machine is booted
+ * the system is set to run at full clock speed. When the upper thermal
+ * threshold is reached as a result of full clock a damping factor is
+ * applied to cool off the cpu. The default value is one quarter clock
+ * (57 Mhz). When as a result of this cooling a temperature lower by
+ * hmc_uthermal_window is reached, the machine is reset to a higher
+ * speed, one half clock (115 Mhz). One half clock is maintained until
+ * the upper thermal threshold is again reached restarting the cycle.
+ */
+
+int
+h8_manage_therm(void)
+{
+ u_char curr_temp[2];
+
+ if(h8_event_mask & H8_MANAGE_UTHERM) {
+ /* Upper thermal interrupt received, need to cool down. */
+ if(h8_debug & 0x10)
+ printk("H8: Thermal threshold %d F reached\n",
+ h8_uthermal_threshold);
+ h8_set_cpu_speed(h8_udamp);
+ h8_clear_event_mask(H8_MANAGE_UTHERM);
+ h8_set_event_mask(H8_MANAGE_LTHERM);
+ /* Check again in 30 seconds for cpu temperature */
+ h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
+ } else if (h8_event_mask & H8_MANAGE_LTHERM) {
+ /* See how cool the system has become as a result
+ of the reduction in speed. */
+ h8_get_curr_temp(curr_temp);
+ last_temp = curr_temp[0];
+ if (curr_temp[0] < (h8_uthermal_threshold - h8_uthermal_window))
+ {
+ /* System cooling has progressed to a point
+ that the cpu may be speeded up. */
+ h8_set_upper_therm_thold(h8_uthermal_threshold);
+ h8_set_cpu_speed(h8_ldamp); /* adjustable */
+ if(h8_debug & 0x10)
+ printk("H8: CPU cool, applying cpu_divisor: %d \n",
+ h8_ldamp);
+ h8_clear_event_mask(H8_MANAGE_LTHERM);
+ }
+ else /* Not cool enough yet, check again in 30 seconds. */
+ h8_start_monitor_timer(H8_TIMEOUT_INTERVAL);
+ } else {
+
+ }
+ return 0;
+}
+
+/*
+ * Function conditions the value of global_rpb_counter before
+ * calling the primitive which causes the actual speed change.
+ */
+void
+h8_set_cpu_speed(int speed_divisor)
+{
+
+#ifdef NOT_YET
+/*
+ * global_rpb_counter is consumed by alpha_delay() in determining just
+ * how much time to delay. It is necessary that the number of microseconds
+ * in DELAY(n) be kept consistent over a variety of cpu clock speeds.
+ * To that end global_rpb_counter is here adjusted.
+ */
+
+ switch (speed_divisor) {
+ case 0:
+ global_rpb_counter = rpb->rpb_counter * 2L;
+ break;
+ case 1:
+ global_rpb_counter = rpb->rpb_counter * 4L / 3L ;
+ break;
+ case 3:
+ global_rpb_counter = rpb->rpb_counter / 2L;
+ break;
+ case 4:
+ global_rpb_counter = rpb->rpb_counter / 4L;
+ break;
+ case 5:
+ global_rpb_counter = rpb->rpb_counter / 8L;
+ break;
+ /*
+ * This case most commonly needed for cpu_speed_divisor
+ * of 2 which is the value assigned by the firmware.
+ */
+ default:
+ global_rpb_counter = rpb->rpb_counter;
+ break;
+ }
+#endif /* NOT_YET */
+
+ if(h8_debug & 0x8)
+ printk("H8: Setting CPU speed to %d MHz\n",
+ speed_tab[speed_divisor]);
+
+ /* Make the actual speed change */
+ lca_clock_fiddle(speed_divisor);
+}
+
+/*
+ * Gets value stored in rpb representing cpu clock speed and adjusts this
+ * value based on the current clock speed divisor.
+ */
+u_long
+h8_get_cpu_speed(void)
+{
+ u_long speed = 0;
+ u_long counter;
+
+#ifdef NOT_YET
+ counter = rpb->rpb_counter / 1000000L;
+
+ switch (alphabook_get_clock()) {
+ case 0:
+ speed = counter * 2L;
+ break;
+ case 1:
+ speed = counter * 4L / 3L ;
+ break;
+ case 2:
+ speed = counter;
+ break;
+ case 3:
+ speed = counter / 2L;
+ break;
+ case 4:
+ speed = counter / 4L;
+ break;
+ case 5:
+ speed = counter / 8L;
+ break;
+ default:
+ break;
+ }
+ if(h8_debug & 0x8)
+ printk("H8: CPU speed current setting: %d MHz\n", speed);
+#endif /* NOT_YET */
+ return speed;
+}
+
+static void
+h8_activate_monitor(unsigned long unused)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ h8_monitor_timer_active = 0;
+ restore_flags(flags);
+
+ wake_up(&h8_monitor_wait);
+}
+
+static void
+h8_start_monitor_timer(unsigned long secs)
+{
+ unsigned long flags;
+
+ if (h8_monitor_timer_active)
+ return;
+
+ save_flags(flags); cli();
+ h8_monitor_timer_active = 1;
+ restore_flags(flags);
+
+ init_timer(&h8_monitor_timer);
+ h8_monitor_timer.function = h8_activate_monitor;
+ h8_monitor_timer.expires = secs * HZ + jiffies;
+ add_timer(&h8_monitor_timer);
+}
+
+static void h8_set_event_mask(int mask)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ h8_event_mask |= mask;
+ restore_flags(flags);
+}
+
+static void h8_clear_event_mask(int mask)
+{
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ h8_event_mask &= (~mask);
+ restore_flags(flags);
+}
--- /dev/null
+/*
+ */
+
+#ifndef __H8_H__
+#define __H8_H__
+
+/*
+ * Register address and offsets
+ */
+#define H8_BASE_ADDR 0x170 /* default */
+#define H8_IRQ 9 /* default */
+#define H8_STATUS_REG_OFF 0x4
+#define H8_CMD_REG_OFF 0x4
+#define H8_DATA_REG_OFF 0x0
+
+
+/* H8 register bit definitions */
+/* status register */
+#define H8_OFULL 0x1 /* output data register full */
+#define H8_IFULL 0x2 /* input data register full */
+#define H8_CMD 0x8 /* command / not data */
+
+#define H8_INTR 0xfa
+#define H8_NACK 0xfc
+#define H8_BYTE_LEVEL_ACK 0xfd
+#define H8_CMD_ACK 0xfe
+#define H8_SYNC_BYTE 0x99
+
+/*
+ * H8 command definitions
+ */
+/* System info commands */
+#define H8_SYNC 0x0
+#define H8_RD_SN 0x1
+#define H8_RD_ENET_ADDR 0x2
+#define H8_RD_HW_VER 0x3
+#define H8_RD_MIC_VER 0x4
+#define H8_RD_MAX_TEMP 0x5
+#define H8_RD_MIN_TEMP 0x6
+#define H8_RD_CURR_TEMP 0x7
+#define H8_RD_SYS_VARIENT 0x8
+#define H8_RD_PWR_ON_CYCLES 0x9
+#define H8_RD_PWR_ON_SECS 0xa
+#define H8_RD_RESET_STATUS 0xb
+#define H8_RD_PWR_DN_STATUS 0xc
+#define H8_RD_EVENT_STATUS 0xd
+#define H8_RD_ROM_CKSM 0xe
+#define H8_RD_EXT_STATUS 0xf
+#define H8_RD_USER_CFG 0x10
+#define H8_RD_INT_BATT_VOLT 0x11
+#define H8_RD_DC_INPUT_VOLT 0x12
+#define H8_RD_HORIZ_PTR_VOLT 0x13
+#define H8_RD_VERT_PTR_VOLT 0x14
+#define H8_RD_EEPROM_STATUS 0x15
+#define H8_RD_ERR_STATUS 0x16
+#define H8_RD_NEW_BUSY_SPEED 0x17
+#define H8_RD_CONFIG_INTERFACE 0x18
+#define H8_RD_INT_BATT_STATUS 0x19
+#define H8_RD_EXT_BATT_STATUS 0x1a
+#define H8_RD_PWR_UP_STATUS 0x1b
+#define H8_RD_EVENT_STATUS_MASK 0x56
+
+/* Read/write/modify commands */
+#define H8_CTL_EMU_BITPORT 0x32
+#define H8_DEVICE_CONTROL 0x21
+#define H8_CTL_TFT_BRT_DC 0x22
+#define H8_CTL_WATCHDOG 0x23
+#define H8_CTL_MIC_PROT 0x24
+#define H8_CTL_INT_BATT_CHG 0x25
+#define H8_CTL_EXT_BATT_CHG 0x26
+#define H8_CTL_MARK_SPACE 0x27
+#define H8_CTL_MOUSE_SENSITIVITY 0x28
+#define H8_CTL_DIAG_MODE 0x29
+#define H8_CTL_IDLE_AND_BUSY_SPDS 0x2a
+#define H8_CTL_TFT_BRT_BATT 0x2b
+#define H8_CTL_UPPER_TEMP 0x2c
+#define H8_CTL_LOWER_TEMP 0x2d
+#define H8_CTL_TEMP_CUTOUT 0x2e
+#define H8_CTL_WAKEUP 0x2f
+#define H8_CTL_CHG_THRESHOLD 0x30
+#define H8_CTL_TURBO_MODE 0x31
+#define H8_SET_DIAG_STATUS 0x40
+#define H8_SOFTWARE_RESET 0x41
+#define H8_RECAL_PTR 0x42
+#define H8_SET_INT_BATT_PERCENT 0x43
+#define H8_WRT_CFG_INTERFACE_REG 0x45
+#define H8_WRT_EVENT_STATUS_MASK 0x57
+#define H8_ENTER_POST_MODE 0x46
+#define H8_EXIT_POST_MODE 0x47
+
+/* Block transfer commands */
+#define H8_RD_EEPROM 0x50
+#define H8_WRT_EEPROM 0x51
+#define H8_WRT_TO_STATUS_DISP 0x52
+#define H8_DEFINE_SPC_CHAR 0x53
+
+/* Generic commands */
+#define H8_DEFINE_TABLE_STRING_ENTRY 0x60
+
+/* Battery control commands */
+#define H8_PERFORM_EMU_CMD 0x70
+#define H8_EMU_RD_REG 0x71
+#define H8_EMU_WRT_REG 0x72
+#define H8_EMU_RD_RAM 0x73
+#define H8_EMU_WRT_RAM 0x74
+#define H8_BQ_RD_REG 0x75
+#define H8_BQ_WRT_REG 0x76
+
+/* System admin commands */
+#define H8_PWR_OFF 0x80
+
+/*
+ * H8 command related definitions
+ */
+
+/* device control argument bits */
+#define H8_ENAB_EXTSMI 0x1
+#define H8_DISAB_IRQ 0x2
+#define H8_ENAB_FLASH_WRT 0x4
+#define H8_ENAB_THERM 0x8
+#define H8_ENAB_INT_PTR 0x10
+#define H8_ENAB_LOW_SPD_IND 0x20
+#define H8_ENAB_EXT_PTR 0x40
+#define H8_DISAB_PWR_OFF_SW 0x80
+#define H8_POWER_OFF 0x80
+
+/* H8 read event status bits */
+#define H8_DC_CHANGE 0x1
+#define H8_INT_BATT_LOW 0x2
+#define H8_INT_BATT_CHARGE_THRESHOLD 0x4
+#define H8_INT_BATT_CHARGE_STATE 0x8
+#define H8_INT_BATT_STATUS 0x10
+#define H8_EXT_BATT_CHARGE_STATE 0x20
+#define H8_EXT_BATT_LOW 0x40
+#define H8_EXT_BATT_STATUS 0x80
+#define H8_THERMAL_THRESHOLD 0x100
+#define H8_WATCHDOG 0x200
+#define H8_DOCKING_STATION_STATUS 0x400
+#define H8_EXT_MOUSE_OR_CASE_SWITCH 0x800
+#define H8_KEYBOARD 0x1000
+#define H8_BATT_CHANGE_OVER 0x2000
+#define H8_POWER_BUTTON 0x4000
+#define H8_SHUTDOWN 0x8000
+
+/* H8 control idle and busy speeds */
+#define H8_SPEED_LOW 0x1
+#define H8_SPEED_MED 0x2
+#define H8_SPEED_HI 0x3
+#define H8_SPEED_LOCKED 0x80
+
+#define H8_MAX_CMD_SIZE 18
+#define H8_Q_ALLOC_AMOUNT 10
+
+/* H8 state field values */
+#define H8_IDLE 1
+#define H8_XMIT 2
+#define H8_RCV 3
+#define H8_RESYNC 4
+#define H8_INTR_MODE 5
+
+/* Mask values for control functions */
+#define UTH_HYSTERESIS 5
+#define DEFAULT_UTHERMAL_THRESHOLD 115
+#define H8_TIMEOUT_INTERVAL 30
+#define H8_RUN 4
+
+#define H8_GET_MAX_TEMP 0x1
+#define H8_GET_CURR_TEMP 0x2
+#define H8_GET_UPPR_THRMAL_THOLD 0x4
+#define H8_GET_ETHERNET_ADDR 0x8
+#define H8_SYNC_OP 0x10
+#define H8_SET_UPPR_THRMAL_THOLD 0x20
+#define H8_GET_INT_BATT_STAT 0x40
+#define H8_GET_CPU_SPD 0x80
+#define H8_MANAGE_UTHERM 0x100
+#define H8_MANAGE_LTHERM 0x200
+#define H8_HALT 0x400
+#define H8_CRASH 0x800
+#define H8_GET_EXT_STATUS 0x10000
+#define H8_MANAGE_QUIET 0x20000
+#define H8_MANAGE_SPEEDUP 0x40000
+#define H8_MANAGE_BATTERY 0x80000
+#define H8_SYSTEM_DELAY_TEST 0x100000
+#define H8_POWER_SWITCH_TEST 0x200000
+
+/* cpu speeds and clock divisor values */
+#define MHZ_14 5
+#define MHZ_28 4
+#define MHZ_57 3
+#define MHZ_115 2
+#define MHZ_230 0
+
+/*
+ * H8 data
+ */
+struct h8_data {
+ u_int ser_num;
+ u_char ether_add[6];
+ u_short hw_ver;
+ u_short mic_ver;
+ u_short max_tmp;
+ u_short min_tmp;
+ u_short cur_tmp;
+ u_int sys_var;
+ u_int pow_on;
+ u_int pow_on_secs;
+ u_char reset_status;
+ u_char pwr_dn_status;
+ u_short event_status;
+ u_short rom_cksm;
+ u_short ext_status;
+ u_short u_cfg;
+ u_char ibatt_volt;
+ u_char dc_volt;
+ u_char ptr_horiz;
+ u_char ptr_vert;
+ u_char eeprom_status;
+ u_char error_status;
+ u_char new_busy_speed;
+ u_char cfg_interface;
+ u_short int_batt_status;
+ u_short ext_batt_status;
+ u_char pow_up_status;
+ u_char event_status_mask;
+};
+
+
+/*
+ * H8 command buffers
+ */
+typedef struct h8_cmd_q {
+ DLNODE(struct h8_cmd_q) link; /* double linked list */
+ int ncmd; /* number of bytes in command */
+ int nrsp; /* number of bytes in response */
+ int cnt; /* number of bytes sent/received */
+ int nacks; /* number of byte level acks */
+ u_char cmdbuf[H8_MAX_CMD_SIZE]; /* buffer to store command */
+ u_char rcvbuf[H8_MAX_CMD_SIZE]; /* buffer to store response */
+} h8_cmd_q_t;
+
+typedef struct __queue_head {
+ DLNODE(struct h8_cmd_q) link;
+} queue_head_t;
+
+union intr_buf {
+ u_char byte[2];
+ u_int word;
+};
+
+#endif /* __H8_H_ */
return 0;
}
-static long read_full(struct inode * node, struct file * file,
- char * buf, unsigned long count)
-{
- file->f_pos += count;
- return count;
-}
-
static long write_full(struct inode * inode, struct file * file,
const char * buf, unsigned long count)
{
#define mmap_kmem mmap_mem
#define zero_lseek null_lseek
+#define full_lseek null_lseek
#define write_zero write_null
+#define read_full read_zero
static struct file_operations mem_fops = {
memory_lseek,
};
static struct file_operations full_fops = {
- memory_lseek,
+ full_lseek,
read_full,
write_full,
NULL, /* full_readdir */
extern int sun_mouse_init(void);
extern void watchdog_init(void);
extern void wdt_init(void);
+extern void acq_init(void);
extern void pcwatchdog_init(void);
extern int rtc_init(void);
extern int dsp56k_init(void);
extern int nvram_init(void);
+extern void hfmodem_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
#ifdef CONFIG_WDT
wdt_init();
#endif
+#ifdef CONFIG_ACQUIRE_WDT
+ acq_init();
+#endif
#ifdef CONFIG_SOFT_WATCHDOG
watchdog_init();
#endif
#ifdef CONFIG_APM
apm_bios_init();
#endif
+#ifdef CONFIG_H8
+ h8_init();
+#endif
#ifdef CONFIG_RTC
rtc_init();
#endif
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
+#ifdef CONFIG_HFMODEM
+ hfmodem_init();
+#endif
#ifdef CONFIG_NVRAM
nvram_init();
#endif
#include <linux/kernel.h>
#include <linux/malloc.h>
+#include <linux/config.h>
+
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
-/* arc-rimi.c:
+/* $Id: arc-rimi.c,v 1.2 1997/09/05 08:57:51 mj Exp $
+
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
#undef SLOW_XMIT_COPY
-
-
-/* External functions from arcnet.c */
-
-
-
-#if ARCNET_DEBUG_MAX & D_SKB
-extern void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
- char *desc);
-#else
-#define arcnet_dump_skb(dev,skb,desc) ;
-#endif
-
-#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-extern void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
- char *desc);
-#else
-#define arcnet_dump_packet(dev,buffer,ext,desc) ;
-#endif
-
-extern void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
-extern void arcnet_makename(char *device);
-extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
-extern void arcnet_setup(struct device *dev);
-extern int arcnet_go_tx(struct device *dev,int enable_irq);
-extern void arcnetA_continue_tx(struct device *dev);
-extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
-extern void arcnet_use_count(int open);
-
-
-
/* Internal function declarations */
+
static int arcrimi_probe(struct device *dev);
static void arcrimi_rx(struct device *dev,int recbuf);
-static int arcrimi_found(struct device *dev,int ioaddr,int airq,u_long shmem);
+static int arcrimi_found(struct device *dev,int ioaddr,int airq,u_long shmem);
static void arcrimi_inthandler (struct device *dev);
static int arcrimi_reset (struct device *dev, int reset_delay);
static void arcrimi_setmask (struct device *dev, u_char mask);
/* Module parameters */
-
#ifdef MODULE
static int shmem=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
static int irq=0; /* or use the insmod io= irq= shmem= options */
/* Handy defines for ARCnet specific stuff */
-
/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define RDDATAflag 0x00 /* Next access is a read/~write */
-
-
-
#define ARCSTATUS readb(_STATUS)
#define ACOMMAND(cmd) writeb((cmd),_COMMAND)
#define ARCRESET writeb(TESTvalue,ioaddr-0x800) /* fake reset */
#define AINTMASK(msk) writeb((msk),_INTMASK)
#define SETCONF writeb(lp->config,_CONFIG)
-
static const char *version =
-"arc-rimi.c: v2.91 97/08/19 Avery Pennarun <apenwarr@bond.net> et al.\n";
-
-
+"arc-rimi.c: v2.92 97/09/02 Avery Pennarun <apenwarr@bond.net> et al.\n";
/****************************************************************************
* *
BUGLVL(D_NORMAL) printk(version);
BUGMSG(D_NORMAL,"Given: node %02Xh, shmem %lXh, irq %d\n",
dev->dev_addr[0],dev->mem_start,dev->irq);
-
+
if (dev->mem_start<=0 || dev->irq<=0)
{
BUGMSG(D_NORMAL,"No autoprobe for RIM I; you "
"must specify the shmem and irq!\n");
return -ENODEV;
}
-
+
if (dev->dev_addr[0]==0)
{
BUGMSG(D_NORMAL,"You need to specify your card's station "
"ID!\n");
return -ENODEV;
}
-
+
return arcrimi_found(dev,dev->dev_addr[0],dev->irq,dev->mem_start);
}
-
/* Set up the struct device associated with this card. Called after
* probing succeeds.
*/
struct arcnet_local *lp;
u_long first_mirror,last_mirror;
int mirror_size;
-
+
/* reserve the irq */
if (request_irq(airq,&arcnet_interrupt,0,"arcnet (RIM I)",NULL))
{
}
irq2dev_map[airq]=dev;
dev->irq=airq;
-
+
dev->base_addr=0;
writeb(TESTvalue,shmem);
writeb(node,shmem+1); /* actually the node ID */
-
+
/* find the real shared memory start/end points, including mirrors */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
-
+
/* guess the actual size of one "memory mirror" - the number of
* bytes between copies of the shared memory. On most cards, it's
* 2k (or there are no mirrors at all) but on some, it's 4k.
&& readb(shmem-mirror_size)!=TESTvalue
&& readb(shmem-2*mirror_size)==TESTvalue)
mirror_size*=2;
-
+
first_mirror=last_mirror=shmem;
while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
first_mirror+=mirror_size;
-
+
while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size;
last_mirror-=mirror_size;
-
+
dev->mem_start=first_mirror;
dev->mem_end=last_mirror+MIRROR_SIZE-1;
dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
-
+
/* Initialize the rest of the device structure. */
-
+
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
lp->openclose_device=arcrimi_openclose;
lp->prepare_tx=arcrimi_prepare_tx;
lp->inthandler=arcrimi_inthandler;
-
+
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
-
+
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
-
+
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
-
+
/* get and check the station ID from offset 1 in shmem */
lp->stationid = readb(first_mirror+1);
-
+
if (lp->stationid==0)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
-
+
BUGMSG(D_NORMAL,"ARCnet RIM I: station %02Xh found at IRQ %d, "
"ShMem %lXh (%ld*%d bytes).\n",
lp->stationid,
dev->irq, dev->mem_start,
(dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size);
-
+
return 0;
}
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->mem_start + 0x800;
int recbuf=lp->recbuf;
-
+
if (reset_delay==3)
{
ARCRESET;
return 0;
}
-
+
/* no IRQ's, please! */
lp->intmask=0;
SETMASK;
-
+
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,ARCSTATUS);
-
+
ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd|CONFIGclear);
-
+
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
-
+
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd|EXTconf);
-
+
#ifndef SLOW_XMIT_COPY
/* clean out all the memory to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start,0x42,2048);
#endif
-
+
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
-
+
/* re-enable interrupts */
lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
-
+
/* done! return success. */
return 0;
}
static void arcrimi_setmask(struct device *dev, u_char mask)
{
int ioaddr=dev->mem_start+0x800;
-
+
AINTMASK(mask);
}
static u_char arcrimi_status(struct device *dev)
{
int ioaddr=dev->mem_start+0x800;
-
+
return ARCSTATUS;
}
static void arcrimi_command(struct device *dev, u_char cmd)
{
int ioaddr=dev->mem_start+0x800;
-
+
ACOMMAND(cmd);
}
-
-
-
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->mem_start+0x800, status, boguscount = 3, didsomething;
-
+
AINTMASK(0);
-
+
BUGMSG(D_DURING,"in arcrimi_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
-
+
do
{
status = ARCSTATUS;
didsomething=0;
-
-
+
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
status);
arcrimi_reset(dev,0);
-
+
/* all other flag values are just garbage */
break;
}
-
-
+
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
-
+
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
-
+
/* enable receive of our next packet */
EnableReceiver();
-
+
/* Got a packet. */
arcrimi_rx(dev,!recbuf);
-
+
didsomething++;
}
-
+
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{
struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
-
+
lp->intmask &= ~TXFREEflag;
-
+
lp->in_txhandler++;
if (was_sending) lp->sending--;
-
+
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
-
+
if (was_sending && !(status&TXACKflag))
{
if (lp->lasttrans_dest != 0)
lp->lasttrans_dest);
}
}
-
+
/* send packet if there is one */
arcnet_go_tx(dev,0);
didsomething++;
-
+
if (lp->intx)
{
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
lp->in_txhandler--;
continue;
}
-
+
if (!lp->outgoing.skb)
{
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
-
+
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
-
+
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev,0);
-
+
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
dev_kfree_skb(out->skb,FREE_WRITE);
}
out->skb=NULL;
-
+
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
}
didsomething++;
-
+
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
arcnet_go_tx(dev,0);
didsomething++;
}
-
+
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
-
+
#ifdef SHOW_RECONFIGS
BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
status);
-
-
#endif /* SHOW_RECONFIGS */
-
+
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
-
+
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
-
+
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
-
+
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
-
+
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
-
+
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
-
+
SETMASK; /* put back interrupt mask */
-
}
-
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
- */
+ */
static void
arcrimi_rx(struct device *dev,int recbuf)
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
-
+
lp->stats.rx_packets++;
-
+
saddr=arcpacket->hardheader.source;
-
+
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
return;
}
/* Set source address to zero to mark it as old */
-
+
arcpacket->hardheader.source=0;
-
+
daddr=arcpacket->hardheader.destination;
-
+
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
{
offset=arcpacket->hardheader.offset2;
arcsoft=&arcpacket->raw[offset];
-
+
length=512-offset;
}
-
-
+
arcnet_rx(lp, arcsoft, length, saddr, daddr);
-
-
+
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
-
+
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)arcpacket->raw,0x42,512);
#endif
-
}
-
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
union ArcPacket *arcpacket =
(union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1));
-
+
#ifdef SLOW_XMIT_COPY
char *iptr,*iend,*optr;
#endif
-
+
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
-
+
length+=hdrlen;
-
+
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
-
+
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start+lp->txbuf*512,0x42,512);
#endif
-
+
arcpacket->hardheader.destination=daddr;
-
+
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
arcpacket->hardheader.offset1=offset=offset?offset:256-length;
-
+
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=offset?offset:512-length;
+ arcpacket->hardheader.offset2=offset=offset?offset:512-length;
}
else if (exceptA) /* RFC1201 Exception Packet */
{
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length-4;
-
+
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
-
+
arcpacket->raw[offset+0]=hdr[0];
arcpacket->raw[offset+1]=0xFF; /* FF flag */
arcpacket->raw[offset+2]=0xFF; /* FF padding */
{
/* RFC1051 - set 4 trailing bytes to 0 */
memset(&arcpacket->raw[508],0,4);
-
+
/* now round up to MinTU */
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-MinTU;
}
-
-
+
+
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
-
+
memcpy((u_char*)arcpacket+offset, (u_char*)hdr,hdrlen);
#ifdef SLOW_XMIT_COPY
for (iptr=data,iend=iptr+length-hdrlen,optr=(char *)arcpacket+offset+hdrlen;
#else
memcpy((u_char*)arcpacket+offset+hdrlen, data,length-hdrlen);
#endif
-
+
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
-
+
BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
-
+
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
-
/****************************************************************************
* *
* Kernel Loadable Module Support *
if (device)
strcpy(dev->name,device);
else arcnet_makename(dev->name);
-
+
if (node && node != 0xff)
dev->dev_addr[0]=node;
-
+
dev->irq=irq;
if (dev->irq==2) dev->irq=9;
-
+
if (shmem)
{
dev->mem_start=shmem;
dev->rmem_start=thiscard.mem_start+512*0;
dev->rmem_end=thiscard.mem_start+512*2-1;
}
-
+
if (register_netdev(dev) != 0)
return -EIO;
arcnet_use_count(1);
{
struct device *dev=&thiscard;
int ioaddr=dev->mem_start;
-
+
if (dev->start) (*dev->stop)(dev);
-
+
/* Flush TX and disable RX */
if (ioaddr)
{
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
}
-
+
if (dev->irq)
{
irq2dev_map[dev->irq] = NULL;
free_irq(dev->irq,NULL);
}
-
+
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
#else
-
__initfunc(void arcrimi_setup (char *str, int *ints))
{
struct device *dev;
MAX_ARCNET_DEVS);
return;
}
-
+
dev=&arcnet_devs[arcnet_num_devs];
-
+
if (ints[0] < 3)
{
printk("ARCnet RIM I: You must give address, IRQ and node ID.\n");
case 2: /* IRQ */
dev->irq=ints[2];
-
+
case 1: /* Mem address */
dev->mem_start=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
-
+
if (str)
strncpy(dev->name, str, 9);
-
+
arcnet_num_devs++;
}
#endif /* MODULE */
-
-
-
-/* arcnet.c:
+/* $Id: arcnet.c,v 1.30 1997/09/05 08:57:46 mj Exp $
+
Written 1994-1996 by Avery Pennarun,
derived from skeleton.c by Donald Becker.
- Contact Avery at: apenwarr@foxnet.net or
+ Contact Avery at: apenwarr@bond.net or
RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
**********************
**********************
+ v2.92 ALPHA (97/02/09)
+ - Code cleanup [Martin Mares <mj@atrey.karlin.mff.cuni.cz>]
+ - Better probing for the COM90xx chipset, although only as
+ a temporary solution until we implement adding of all found
+ devices at once. [mj]
+
v2.91 ALPHA (97/19/08)
- Add counting of octets in/out.
- Smarter recovery from RECON-during-transmit conditions. (ie.
retransmit immediately)
- Add support for the new 1.3.x IP header cache, and other features.
- - Debug level should be changed with a system call, not a hack to
- the "metric" flag.
+ - Replace setting of debug level with the "metric" flag hack by
+ something better. SIOCDEVPRIVATE is a good candidate, but it would
+ require an extra user-level utility.
- What about cards with shared memory that can be "turned off?"
(or that have none at all, like the SMC PC500longboard)
- Does this work now, with IO_MAPPED_BUFFERS?
+ Does this work now, with IO_MAPPED_BUFFERS?
- Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play
with temporarily.) Update: yes, the Pure Data config program
*/
static const char *version =
- "arcnet.c: v2.91 97/08/19 Avery Pennarun <apenwarr@bond.net> et al.\n";
-
-
+ "arcnet.c: v2.92 97/09/02 Avery Pennarun <apenwarr@bond.net> et al.\n";
#include <linux/module.h>
#include <linux/config.h>
/**************************************************************************/
-/* These are now provided by the chipset driver. There's a performance
+/* These are now provided by the chipset driver. There's a performance
* overhead in using them.
*/
-
#define AINTMASK(x) ((*lp->asetmask)(dev, x))
#define ARCSTATUS ((*lp->astatus)(dev))
#define ACOMMAND(x) ((*lp->acommand)(dev, x))
-
int arcnet_debug=ARCNET_DEBUG;
/* Exported function prototypes */
void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
-
EXPORT_SYMBOL(arcnet_debug);
EXPORT_SYMBOL(arcnet_tx_done);
EXPORT_SYMBOL(arcnet_use_count);
#endif
-
-
-
-
/****************************************************************************
* *
* Packet dumps for debugging *
}
#endif
+
/* Dump the contents of an ARCnet buffer
*/
#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
#endif
-
-
/* Setup a struct device for ARCnet. This should really be in net_init.c
* but since there are three different ARCnet devices ANYWAY... <gargle>
*
dev->pa_mask = 0;
dev->pa_alen = 4;
-
- /* Put in this stuff here, so we don't have to export the symbols
+ /* Put in this stuff here, so we don't have to export the symbols
* to the chipset drivers.
*/
* *
****************************************************************************/
-
/* Open/initialize the board. This is called sometime after booting when
* the 'ifconfig' program is run.
*
arcnet_open(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
if (dev->metric>=1000)
{
arcnet_debug=dev->metric-1000;
printk(KERN_INFO "%6s: debug level set to %d\n",dev->name,arcnet_debug);
dev->metric=1;
}
-
+
BUGMSG(D_INIT,"arcnet_open: resetting card.\n");
-
+
/* try to put the card in a defined state - if it fails the first
* time, actually reset it.
*/
if ((*lp->arcnet_reset)(dev,0) && (*lp->arcnet_reset)(dev,1))
return -ENODEV;
-#if 0
- /* reset the card twice in case something goes wrong the first time.
- */
- if ((*(lp->arcnet_reset))(dev,1) && (*(lp->arcnet_reset))(dev,1))
- return -ENODEV;
-#endif
-
+
dev->tbusy=0;
dev->interrupt=0;
lp->intx=0;
lp->in_txhandler=0;
-
+
/* The RFC1201 driver is the default - just store */
lp->adev=dev;
/* we're started */
dev->start=1;
-
+
#ifdef CONFIG_ARCNET_ETH
/* Initialize the ethernet-encap protocol driver */
lp->edev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
lp->edev->init=arcnetE_init;
register_netdev(lp->edev);
#endif
-
+
#ifdef CONFIG_ARCNET_1051
/* Initialize the RFC1051-encap protocol driver */
lp->sdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
lp->sdev->init=arcnetS_init;
register_netdev(lp->sdev);
#endif
-
+
/* Enable TX if we need to */
if (lp->en_dis_able_TX)
(*lp->en_dis_able_TX)(dev, 1);
-
+
/* make sure we're ready to receive IRQ's.
* arcnet_reset sets this for us, but if we receive one before
* START is set to 1, it could be ignored. So, we turn IRQ's
* off, then on again to clean out the IRQ controller.
*/
-
+
AINTMASK(0);
udelay(1); /* give it time to set the mask before
* we reset it again. (may not even be
* necessary)
*/
SETMASK;
-
+
/* Let it increase its use count */
(*lp->openclose_device)(1);
-
+
return 0;
}
arcnet_close(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
if (test_and_set_bit(0, (int *)&dev->tbusy))
BUGMSG(D_NORMAL, "arcnet_close: tbusy already set!\n");
lp->edev->start=0;
#endif
-
/* Shut down the card */
-
+
/* Disable TX if we need to */
if (lp->en_dis_able_TX)
(*lp->en_dis_able_TX)(dev, 0);
-
+
(*lp->arcnet_reset)(dev, 3); /* reset IRQ won't run if START=0 */
#if 0
lp->intmask=0;
- SETMASK; /* no IRQ's (except RESET, of course) */
+ SETMASK; /* no IRQ's (except RESET, of course) */
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
#endif
-
+
/* reset more flags */
- dev->interrupt=0;
+ dev->interrupt=0;
#ifdef CONFIG_ARCNET_ETH
- lp->edev->interrupt=0;
+ lp->edev->interrupt=0;
#endif
#ifdef CONFIG_ARCNET_1051
- lp->sdev->interrupt=0;
+ lp->sdev->interrupt=0;
#endif
-
-
-
/* do NOT free lp->adev!! It's static! */
lp->adev=NULL;
-
+
#ifdef CONFIG_ARCNET_ETH
/* free the ethernet-encap protocol device */
lp->edev->priv=NULL;
kfree(lp->edev);
lp->edev=NULL;
#endif
-
+
#ifdef CONFIG_ARCNET_1051
/* free the RFC1051-encap protocol device */
lp->sdev->priv=NULL;
kfree(lp->sdev);
lp->sdev=NULL;
#endif
-
+
/* Update the statistics here. (not necessary in ARCnet) */
-
+
/* Decrease the use count */
(*lp->openclose_device)(0);
-
+
return 0;
}
-
/****************************************************************************
* *
* Transmitter routines *
arcnet_send_packet_bad(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
BUGMSG(D_DURING,"transmit requested (status=%Xh, inTX=%d)\n",
ARCSTATUS,lp->intx);
-
+
if (lp->in_txhandler)
{
BUGMSG(D_NORMAL,"send_packet called while in txhandler!\n");
lp->stats.tx_dropped++;
return 1;
}
-
+
if (lp->intx>1)
{
BUGMSG(D_NORMAL,"send_packet called while intx!\n");
lp->stats.tx_dropped++;
return 1;
}
-
+
if (test_bit(0, (int *)&dev->tbusy))
{
/* If we get here, some higher level has decided we are broken.
int tickssofar = jiffies - dev->trans_start;
int status=ARCSTATUS;
-
+
if (tickssofar < TX_TIMEOUT)
{
BUGMSG(D_DURING,"premature kickme! (status=%Xh ticks=%d o.skb=%ph numsegs=%d segnum=%d\n",
lp->outgoing.segnum);
return 1;
}
-
+
lp->intmask &= ~TXFREEflag;
SETMASK;
-
+
if (status&TXFREEflag) /* transmit _DID_ finish */
{
BUGMSG(D_NORMAL,"tx timeout - missed IRQ? (status=%Xh, ticks=%d, mask=%Xh, dest=%02Xh)\n",
status,tickssofar,lp->intmask,lp->lasttrans_dest);
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
-
+
ACOMMAND(NOTXcmd);
}
-
+
if (lp->outgoing.skb)
{
dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
lp->stats.tx_dropped++;
}
lp->outgoing.skb=NULL;
-
+
#ifdef CONFIG_ARCNET_ETH
lp->edev->tbusy=0;
#endif
lp->txready=0;
lp->sending=0;
-
+
return 1;
}
-
+
if (lp->txready) /* transmit already in progress! */
{
BUGMSG(D_NORMAL,"trying to start new packet while busy! (status=%Xh)\n",
lp->stats.tx_errors++;
lp->stats.tx_fifo_errors++;
lp->txready=0; /* we definitely need this line! */
-
+
return 1;
}
-
+
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (test_and_set_bit(0, (int *)&lp->adev->tbusy))
#ifdef CONFIG_ARCNET_ETH
lp->edev->tbusy=1;
#endif
-
+
return 0;
}
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int bad,oldmask=0;
struct Outgoing *out=&(lp->outgoing);
-
+
lp->intx++;
-
+
oldmask |= lp->intmask;
lp->intmask=0;
SETMASK;
-
+
bad=arcnet_send_packet_bad(skb,dev);
if (bad)
{
SETMASK;
return bad;
}
-
+
/* arcnet_send_packet_pad has already set tbusy - don't bother here. */
-
+
lp->intmask = oldmask & ~TXFREEflag;
SETMASK;
-
+
out->length = 1 < skb->len ? skb->len : 1;
out->hdr=(struct ClientData*)skb->data;
out->skb=skb;
-
+
BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
-
+
out->hdr->sequence=(lp->sequence++);
-
+
/* fits in one packet? */
if (out->length-EXTRA_CLIENTDATA<=XMTU)
{
((char *)skb->data)+sizeof(struct ClientData),
out->length-sizeof(struct ClientData),
out->hdr->daddr,1,0);
-
+
/* done right away */
lp->stats.tx_bytes += out->skb->len;
dev_kfree_skb(out->skb,FREE_WRITE);
out->skb=NULL;
-
+
if (arcnet_go_tx(dev,1))
{
/* inform upper layers */
else /* too big for one - split it */
{
int maxsegsize=XMTU-4;
-
+
out->data=(u_char *)skb->data
+ sizeof(struct ClientData);
out->dataleft=out->length-sizeof(struct ClientData);
out->numsegs=(out->dataleft+maxsegsize-1)/maxsegsize;
out->segnum=0;
-
+
BUGMSG(D_TX,"packet (%d bytes) split into %d fragments:\n",
out->length,out->numsegs);
-
+
/* if a packet waiting, launch it */
arcnet_go_tx(dev,1);
-
+
if (!lp->txready)
{
/* prepare a packet, launch it and prepare
arcnet_go_tx(dev,1);
}
}
-
+
/* if segnum==numsegs, the transmission is finished;
* free the skb right away.
*/
out->skb=NULL;
}
}
-
+
dev->trans_start=jiffies;
lp->intx--;
-
+
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
-
+
return 0;
}
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int maxsegsize=XMTU-4;
struct Outgoing *out=&(lp->outgoing);
-
+
BUGMSG(D_DURING,"continue_tx called (status=%Xh, intx=%d, intxh=%d, intmask=%Xh\n",
ARCSTATUS,lp->intx,lp->in_txhandler,lp->intmask);
-
+
if (lp->txready)
{
BUGMSG(D_NORMAL,"continue_tx: called with packet in buffer!\n");
return;
}
-
+
if (out->segnum>=out->numsegs)
{
BUGMSG(D_NORMAL,"continue_tx: building segment %d of %d!\n",
out->segnum+1,out->numsegs);
}
-
+
if (!out->segnum) /* first packet */
out->hdr->split_flag=((out->numsegs-2)<<1)+1;
else
out->hdr->split_flag=out->segnum<<1;
-
+
out->seglen=maxsegsize;
if (out->seglen>out->dataleft) out->seglen=out->dataleft;
-
+
BUGMSG(D_TX,"building packet #%d (%d bytes) of %d (%d total), splitflag=%d\n",
out->segnum+1,out->seglen,out->numsegs,
out->length,out->hdr->split_flag);
-
+
(*lp->prepare_tx)(dev,((char *)out->hdr)+EXTRA_CLIENTDATA,
sizeof(struct ClientData)-EXTRA_CLIENTDATA,
out->data,out->seglen,out->hdr->daddr,1,0);
-
+
out->dataleft-=out->seglen;
out->data+=out->seglen;
out->segnum++;
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
struct arcnet_local *lp;
-
+
if (dev==NULL)
{
BUGLVL(D_DURING)
printk(KERN_DEBUG "arcnet: irq %d for unknown device.\n", irq);
return;
}
-
+
BUGMSG(D_DURING,"in arcnet_interrupt\n");
-
-
+
lp=(struct arcnet_local *)dev->priv;
-
+
/* RESET flag was enabled - if !dev->start, we must clear it right
* away (but nothing else) since inthandler() is never called.
*/
-
+
if (!dev->start)
- {
+ {
if (ARCSTATUS & RESETflag)
ACOMMAND(CFLAGScmd|RESETclear);
return;
}
-
+
if (test_and_set_bit(0, (int *)&dev->interrupt))
{
if (!test_and_clear_bit(0, (int *)&dev->tbusy))
BUGMSG(D_NORMAL, "In arcnet_tx_done: Someone cleared our dev->tbusy"
" flag!\n");
-
+
mark_bh(NET_BH);
}
}
* *
****************************************************************************/
-/*
+/*
* This is a generic packet receiver that calls arcnet??_rx depending on the
* protocol ID found.
*/
void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr)
{
struct device *dev=lp->adev;
-
+
BUGMSG(D_DURING,"received packet from %02Xh to %02Xh (%d bytes)\n",
saddr,daddr,length);
-
+
/* call the right receiver for the protocol */
switch (arcsoft[0])
{
lp->stats.rx_crc_errors++;
break;
}
-
+
/* If any worth-while packets have been received, a mark_bh(NET_BH)
* has been done by netif_rx and Linux will handle them after we
* return.
*/
-
-
+
+
}
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct sk_buff *skb;
struct ClientData *arcsoft,*soft;
-
+
BUGMSG(D_DURING,"it's an RFC1201 packet (length=%d)\n",
length);
-
+
/* compensate for EXTRA_CLIENTDATA (which isn't actually in the
* packet)
*/
arcsoft=(struct ClientData *)(buf-EXTRA_CLIENTDATA);
length+=EXTRA_CLIENTDATA;
-
+
if (arcsoft->split_flag==0xFF) /* Exception Packet */
{
BUGMSG(D_DURING,"compensating for exception packet\n");
-
+
/* skip over 4-byte junkola */
arcsoft=(struct ClientData *)
((u_char *)arcsoft + 4);
length-=4;
}
-
+
if (!arcsoft->split_flag) /* not split */
{
struct Incoming *in=&lp->incoming[saddr];
-
+
BUGMSG(D_RX,"incoming is not split (splitflag=%d)\n",
arcsoft->split_flag);
-
+
if (in->skb) /* already assembling one! */
{
BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
lp->stats.rx_missed_errors++;
in->skb=NULL;
}
-
+
in->sequence=arcsoft->sequence;
-
+
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
return;
}
soft=(struct ClientData *)skb->data;
-
+
skb_put(skb,length);
skb->dev = dev;
-
+
memcpy((u_char *)soft+EXTRA_CLIENTDATA,
(u_char *)arcsoft+EXTRA_CLIENTDATA,
length-EXTRA_CLIENTDATA);
soft->daddr=daddr;
soft->saddr=saddr;
-
+
/* ARP packets have problems when sent from DOS.
* source address is always 0 on some systems! So we take
* the hardware source addr (which is impossible to fumble)
{
struct arphdr *arp=(struct arphdr *)
((char *)soft+sizeof(struct ClientData));
-
+
/* make sure addresses are the right length */
if (arp->ar_hln==1 && arp->ar_pln==4)
{
char *cptr=(char *)(arp)+sizeof(struct arphdr);
-
+
if (!*cptr) /* is saddr = 00? */
{
BUGMSG(D_EXTRA,"ARP source address was 00h, set to %02Xh.\n",
lp->stats.rx_crc_errors++;
}
}
-
+
BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
-
+
lp->stats.rx_bytes += skb->len;
skb->protocol=arcnetA_type_trans(skb,dev);
netif_rx(skb);
* ARCnet card possible on the network. Seems rather like
* a waste of memory. Necessary?
*/
-
+
struct Incoming *in=&lp->incoming[saddr];
-
+
BUGMSG(D_RX,"packet is split (splitflag=%d, seq=%d)\n",
arcsoft->split_flag,in->sequence);
-
+
if (in->skb && in->sequence!=arcsoft->sequence)
{
BUGMSG(D_EXTRA,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n",
lp->stats.rx_missed_errors++;
in->lastpacket=in->numpackets=0;
}
-
+
if (arcsoft->split_flag & 1) /* first packet in split */
{
BUGMSG(D_RX,"brand new splitpacket (splitflag=%d)\n",
lp->stats.rx_missed_errors++;
kfree_skb(in->skb,FREE_WRITE);
}
-
+
in->sequence=arcsoft->sequence;
in->numpackets=((unsigned)arcsoft->split_flag>>1)+2;
in->lastpacket=1;
-
+
if (in->numpackets>16)
{
BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
lp->stats.rx_length_errors++;
return;
}
-
+
in->skb=skb=alloc_skb(508*in->numpackets
+ sizeof(struct ClientData),
GFP_ATOMIC);
lp->stats.rx_dropped++;
return;
}
-
+
soft=(struct ClientData *)skb->data;
-
+
skb_put(skb,sizeof(struct ClientData));
skb->dev=dev;
-
+
memcpy((u_char *)soft+EXTRA_CLIENTDATA,
(u_char *)arcsoft+EXTRA_CLIENTDATA,
sizeof(struct ClientData)-EXTRA_CLIENTDATA);
else /* not first packet */
{
int packetnum=((unsigned)arcsoft->split_flag>>1) + 1;
-
+
/* if we're not assembling, there's no point
* trying to continue.
*/
}
return;
}
-
+
in->lastpacket++;
if (packetnum!=in->lastpacket) /* not the right flag! */
{
lp->stats.rx_frame_errors++;
return;
}
-
+
/* "bad" duplicate, kill reassembly */
BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
in->lastpacket=in->numpackets=0;
return;
}
-
+
soft=(struct ClientData *)in->skb->data;
}
-
+
skb=in->skb;
-
+
memcpy(skb->data+skb->len,
(u_char *)arcsoft+sizeof(struct ClientData),
length-sizeof(struct ClientData));
skb_put(skb,length-sizeof(struct ClientData));
-
+
soft->daddr=daddr;
soft->saddr=saddr;
-
+
/* are we done? */
if (in->lastpacket == in->numpackets)
{
{
in->skb=NULL;
in->lastpacket=in->numpackets=0;
-
+
BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
-
+
lp->stats.rx_bytes += skb->len;
skb->protocol=arcnetA_type_trans(skb,dev);
netif_rx(skb);
}
-
-
/****************************************************************************
* *
* Miscellaneous routines *
* *
****************************************************************************/
-
/* Get the current statistics. This may be called with the card open or
* closed.
*/
static struct net_device_stats *arcnet_get_stats(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
return &lp->stats;
}
struct ClientData *head = (struct ClientData *)
skb_push(skb,dev->hard_header_len);
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
+
BUGMSG(D_DURING,"create header from %d to %d; protocol %d (%Xh); size %u.\n",
saddr ? *(u_char*)saddr : -1,
daddr ? *(u_char*)daddr : -1,
type,type,len);
-
+
/* set the protocol ID according to RFC1201 */
switch(type)
{
lp->stats.tx_aborted_errors++;
return 0;
}
-
+
/*
* Set the source hardware address.
*
head->saddr=((u_char*)saddr)[0];
else
head->saddr=((u_char*)(dev->dev_addr))[0];
-
+
head->split_flag=0; /* split packets are done elsewhere */
head->sequence=0; /* so are sequence numbers */
-
+
/* supposedly if daddr is NULL, we should ignore it... */
if(daddr)
{
}
else
head->daddr=0; /* better fill one in anyway */
-
+
return -dev->hard_header_len;
}
-
/* Rebuild the ARCnet ClientData header. This is called after an ARP
* (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields.
struct device *dev=skb->dev;
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
int status;
-
+
/*
* Only ARP and IP are currently supported
*
* FIXME: Anyone want to spec IPv6 over ARCnet ?
*/
-
+
if(head->protocol_id != ARC_P_IP)
{
BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
return 0;
}
-
+
/*
* Try to get ARP to resolve the header.
*/
{
struct ClientData *head;
struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
-
+
/* Pull off the arcnet header. */
skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len);
head=(struct ClientData *)skb->mac.raw;
-
+
if (head->daddr==0)
skb->pkt_type=PACKET_BROADCAST;
else if (dev->flags&IFF_PROMISC)
if (head->daddr != dev->dev_addr[0])
skb->pkt_type=PACKET_OTHERHOST;
}
-
+
/* now return the protocol number */
switch (head->protocol_id)
{
case ARC_P_IP: return htons(ETH_P_IP);
case ARC_P_ARP: return htons(ETH_P_ARP);
case ARC_P_RARP: return htons(ETH_P_RARP);
-
+
case ARC_P_IPX:
case ARC_P_NOVELL_EC:
return htons(ETH_P_802_3);
lp->stats.rx_crc_errors++;
return 0;
}
-
+
return htons(ETH_P_IP);
}
static int arcnetE_init(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
ether_setup(dev); /* we're emulating ether here, not ARCnet */
dev->dev_addr[0]=0;
dev->dev_addr[5]=lp->stationid;
dev->open=arcnetE_open_close;
dev->stop=arcnetE_open_close;
dev->hard_start_xmit=arcnetE_send_packet;
-
+
return 0;
}
u_char daddr;
short offset,length=skb->len+1;
u_char proto=ARC_P_ETHER;
-
+
lp->intx++;
-
+
oldmask |= lp->intmask;
lp->intmask=0;
SETMASK;
-
+
bad=arcnet_send_packet_bad(skb,dev);
if (bad)
{
SETMASK;
return bad;
}
-
+
/* arcnet_send_packet_pad has already set tbusy - don't bother here. */
lp->intmask=oldmask;
SETMASK;
-
+
if (length>XMTU)
{
BUGMSG(D_NORMAL,"MTU must be <= 493 for ethernet encap (length=%d).\n",
length);
BUGMSG(D_NORMAL,"transmit aborted.\n");
-
+
dev_kfree_skb(skb,FREE_WRITE);
lp->intx--;
return 0;
}
-
+
BUGMSG(D_DURING,"starting tx sequence...\n");
-
+
/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
daddr=0;
else
daddr=((struct ethhdr*)(skb->data))->h_dest[5];
-
+
/* load packet into shared memory */
offset=512-length;
if (length>MTU) /* long/exception packet */
{
offset-=256;
}
-
+
BUGMSG(D_DURING," length=%Xh, offset=%Xh\n",
length,offset);
-
-
- (*lp->prepare_tx)(dev, &proto, 1, skb->data, length-1, daddr, 0,
+ (*lp->prepare_tx)(dev, &proto, 1, skb->data, length-1, daddr, 0,
offset);
-
-
-
+
dev_kfree_skb(skb,FREE_WRITE);
if (arcnet_go_tx(dev,1))
/* inform upper layers */
arcnet_tx_done(lp->adev, lp);
}
-
+
dev->trans_start=jiffies;
lp->intx--;
static int arcnetS_init(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
arcnet_setup(dev);
-
+
/* And now fill particular fields with arcnet values */
dev->dev_addr[0]=lp->stationid;
dev->hard_header_len=sizeof(struct S_ClientData);
dev->hard_start_xmit=arcnetS_send_packet;
dev->hard_header=arcnetS_header;
dev->rebuild_header=arcnetS_rebuild_header;
-
+
return 0;
}
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int bad,length;
struct S_ClientData *hdr=(struct S_ClientData *)skb->data;
-
+
lp->intx++;
-
+
bad=arcnet_send_packet_bad(skb,dev);
if (bad)
{
}
/* arcnet_send_packet_pad has already set tbusy - don't bother here. */
-
+
length = 1 < skb->len ? skb->len : 1;
-
+
BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"tx");
-
+
/* fits in one packet? */
if (length-S_EXTRA_CLIENTDATA<=XMTU)
{
skb->data+sizeof(struct S_ClientData),
length-sizeof(struct S_ClientData),
hdr->daddr,0,0);
-
+
/* done right away */
dev_kfree_skb(skb,FREE_WRITE);
-
+
if (arcnet_go_tx(dev,1))
{
/* inform upper layers */
lp->stats.tx_dropped++;
arcnet_tx_done(lp->adev, lp);
}
-
+
dev->trans_start=jiffies;
lp->intx--;
-
+
/* make sure we didn't ignore a TX IRQ while we were in here */
lp->intmask |= TXFREEflag;
SETMASK;
-
+
return 0;
}
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct sk_buff *skb;
struct S_ClientData *arcsoft,*soft;
-
+
arcsoft=(struct S_ClientData *)(buf-S_EXTRA_CLIENTDATA);
length+=S_EXTRA_CLIENTDATA;
-
+
BUGMSG(D_DURING,"it's an RFC1051 packet (length=%d)\n",
length);
-
-
-
+
{ /* was "if not split" in A protocol, S is never split */
-
+
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
BUGMSG(D_NORMAL,"Memory squeeze, dropping packet.\n");
soft->daddr=daddr;
soft->saddr=saddr;
skb->dev = dev; /* is already lp->sdev */
-
+
BUGLVL(D_SKB) arcnet_dump_skb(dev,skb,"rx");
-
+
lp->stats.rx_bytes += skb->len;
skb->protocol=arcnetS_type_trans(skb,dev);
netif_rx(skb);
struct S_ClientData *head = (struct S_ClientData *)
skb_push(skb,dev->hard_header_len);
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
+
/* set the protocol ID according to RFC1051 */
switch(type)
{
lp->stats.tx_aborted_errors++;
return 0;
}
-
+
/*
* Set the source hardware address.
*
head->saddr=((u_char*)saddr)[0];
else
head->saddr=((u_char*)(dev->dev_addr))[0];
-
+
/* supposedly if daddr is NULL, we should ignore it... */
if(daddr)
{
}
else
head->daddr=0; /* better fill one in anyway */
-
+
return -dev->hard_header_len;
}
struct device *dev=skb->dev;
struct S_ClientData *head = (struct S_ClientData *)skb->data;
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
-
+
/*
* Only ARP and IP are currently supported
*/
-
+
if(head->protocol_id != ARC_P_IP_RFC1051)
{
BUGMSG(D_NORMAL,"I don't understand protocol type %d (%Xh) addresses!\n",
/*memcpy(eth->h_source, dev->dev_addr, dev->addr_len);*/
return 0;
}
-
+
/*
* Try to get ARP to resolve the header.
*/
{
struct S_ClientData *head;
struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
-
+
/* Pull off the arcnet header. */
skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len);
head=(struct S_ClientData *)skb->mac.raw;
-
+
if (head->daddr==0)
skb->pkt_type=PACKET_BROADCAST;
else if (dev->flags&IFF_PROMISC)
if (head->daddr != dev->dev_addr[0])
skb->pkt_type=PACKET_OTHERHOST;
}
-
+
/* now return the protocol number */
switch (head->protocol_id)
{
lp->stats.rx_crc_errors++;
return 0;
}
-
+
return htons(ETH_P_IP);
}
#endif /* CONFIG_ARCNET_1051 */
+
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
-
-
#ifdef MODULE
void cleanup_module(void)
}
void arcnet_use_count(int open)
-{
+{
if (open)
MOD_INC_USE_COUNT;
else
int arcnet_num_devs=0;
char arcnet_dev_names[MAX_ARCNET_DEVS][10];
-void arcnet_init(void)
+__initfunc(void arcnet_init(void))
{
int c;
-
- (void) init_module();
+
+ init_module();
/* Don't register_netdev here. The chain hasn't been initialised. */
-
+
#ifdef CONFIG_ARCNET_COM90xx
if ((!com90xx_explicit) && arcnet_num_devs < MAX_ARCNET_DEVS)
{
if (!arcnet_num_devs)
{
printk("Don't forget to load the chipset driver.\n");
- return;
+ return;
}
/* Link into the device chain */
arcnet_devs[c].next=dev_base;
dev_base=&arcnet_devs[0];
-
+
/* Give names to those without them */
-
+
for (c=0; c< arcnet_num_devs; c++)
if (!arcnet_dev_names[c][0])
arcnet_makename((char *)&arcnet_dev_names[c]);
-
}
-static
+
#endif /* MODULE */
-int init_module()
+
+
+#ifdef MODULE
+int init_module(void)
+#else
+__initfunc(static int init_module(void))
+#endif
{
-
-#if 1
+#ifdef ALPHA_WARNING
BUGLVL(D_EXTRA)
{
printk("arcnet: ***\n");
}
#endif
- printk("%sGeneric arcnet support for Linux kernel.\n"
- "Available protocols: ARCnet RFC1201"
+ printk("%sAvailable protocols: ARCnet RFC1201"
#ifdef CONFIG_ARCNET_ETH
", Ethernet-Encap"
#endif
}
-
-
-
void arcnet_makename(char *device)
{
- __u32 arcmask=0;
struct device *dev;
- char *c;
int arcnum;
- for (dev = dev_base; dev; dev=dev->next)
- {
- arcnum=0;
-
- if (!strncmp(dev->name, "arc", 3))
- {
- c = &dev->name[3];
- while ((*c)>='0' && (*c)<='9')
- {
- arcnum *= 10;
- arcnum += (*(c++)-'0');
- }
-
- if (arcnum<32)
- arcmask |= ((__u32)1 << arcnum);
- }
-
-
- }
-
- /* arcmask now holds a mask of the first 32 arcnet names available */
-
- if ((__u32)~arcmask)
- {
- for (arcnum=0; arcmask&1; arcnum++, arcmask >>=1)
- ;
-
- sprintf (device, "arc%d",arcnum);
- }
- else
+ arcnum = 0;
+ for (;;)
{
- printk (KERN_INFO "arcnet: Can't find name for device\n");
- sprintf (device, "arc???");
+ sprintf(device, "arc%d", arcnum);
+ for (dev = dev_base; dev; dev=dev->next)
+ if (dev->name != device && !strcmp(dev->name, device))
+ break;
+ if (!dev)
+ return;
+ arcnum++;
}
}
-
-
-/* com20020.c:
+/* $Id: com20020.c,v 1.2 1997/09/05 08:57:50 mj Exp $
+
Written 1997 by David Woodhouse <dwmw2@cam.ac.uk>
Derived from the original arcnet.c,
#include <net/arp.h>
-
-
-
-/* External functions from arcnet.c */
-
-
-
-#if ARCNET_DEBUG_MAX & D_SKB
-extern void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
- char *desc);
-#else
-#define arcnet_dump_skb(dev,skb,desc) ;
-#endif
-
-#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-extern void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
- char *desc);
-#else
-#define arcnet_dump_packet(dev,buffer,ext,desc) ;
-#endif
-extern void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
-extern void arcnet_makename(char *device);
-extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
-extern void arcnet_setup(struct device *dev);
-extern int arcnet_go_tx(struct device *dev,int enable_irq);
-extern void arcnetA_continue_tx(struct device *dev);
-extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
-extern void arcnet_use_count(int open);
-
-
/* Internal function declarations */
static int arc20020_probe(struct device *dev);
#endif
-
/* Handy defines for ARCnet specific stuff */
static char *clockrates[]={"2.5 Mb/s","1.25Mb/s","625 Kb/s","312.5 Kb/s",
"Reserved"};
-/* The number of low I/O ports used by the ethercard. */
+/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 9
#define _INTMASK (ioaddr+0) /* writable */
#define _ADDR_HI (ioaddr+2) /* Control registers for said */
#define _ADDR_LO (ioaddr+3)
-
#define RDDATAflag 0x80 /* Next access is a read/~write */
#define NEWNXTIDflag 0x02 /* ID to which token is passed has changed */
outb(0x18 , _CONFIG); \
}
-
#define ARCSTATUS inb(_STATUS)
#define ACOMMAND(cmd) outb((cmd),_COMMAND)
#define AINTMASK(msk) outb((msk),_INTMASK)
static const char *version =
- "com20020.c: v2.91 97/08/19 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "com20020.c: v2.92 97/09/02 Avery Pennarun <apenwarr@bond.net> et al.\n";
/****************************************************************************
* *
****************************************************************************/
-
/* We cannot probe for an IO mapped card either, although we can check that
* it's where we were told it was, and even autoirq
*/
return -ENODEV;
}
-
BUGMSG(D_INIT_REASONS,"Status after reset: %X\n",status);
-
/* Enable TX */
outb(0x39,_CONFIG);
outb(inb(ioaddr+8),ioaddr+7);
-
ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status);
}
-
/* Set up the struct device associated with this card. Called after
* probing succeeds.
*/
request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM20020)");
dev->base_addr=ioaddr;
-
dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL;
-
-
+
/* Initialize the rest of the device structure. */
-
+
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
lp=(struct arcnet_local *)(dev->priv);
lp->card_type = ARC_20020;
lp->card_type_str = "COM 20020";
-
+
lp->arcnet_reset=arc20020_reset;
lp->asetmask=arc20020_setmask;
lp->astatus=arc20020_status;
lp->openclose_device=arc20020_openclose;
lp->prepare_tx=arc20020_prepare_tx;
lp->inthandler=arc20020_inthandler;
-
-
+
dev->set_multicast_list = arc20020_set_mc_list;
-
+
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
-
+
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
-
+
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
-
+
/* get and check the station ID from offset 1 in shmem */
lp->timeout = dev->dev_addr[3] & 3; dev->dev_addr[3]=0;
lp->backplane =dev->dev_addr[1] & 1; dev->dev_addr[1]=0;
lp->setup = (dev->dev_addr[2] & 7) << 1; dev->dev_addr[2]=0;
-
+
if (dev->dev_addr[0])
lp->stationid=dev->dev_addr[0];
else
/* Default 0x38 + register: Node ID */
SETCONF;
outb(lp->stationid, ioaddr+7);
-
+
REGSETUP;
SETCONF;
outb(lp->setup, ioaddr+7);
-
+
if (!lp->stationid)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
-
+
BUGMSG(D_NORMAL,"ARCnet COM20020: station %02Xh found at %03lXh, IRQ %d.\n",
lp->stationid, dev->base_addr,dev->irq);
-
+
if (lp->backplane)
BUGMSG (D_NORMAL, "Using backplane mode.\n");
-
+
if (lp->timeout != 3)
BUGMSG (D_NORMAL, "Using Extended Timeout value of %d.\n",lp->timeout);
if (lp->setup)
{
BUGMSG (D_NORMAL, "Using CKP %d - Data rate %s.\n",
- lp->setup >>1,clockrates[lp->setup >> 1] );
+ lp->setup >>1,clockrates[lp->setup >> 1] );
}
return 0;
}
/****************************************************************************
* *
- * Utility routines for arcnet.c *
+ * Utility routines *
* *
****************************************************************************/
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int delayval,recbuf=lp->recbuf;
-
+
if (reset_delay==3)
{
ARCRESET;
return 0;
}
-
+
/* no IRQ's, please! */
lp->intmask=0;
SETMASK;
-
+
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,ARCSTATUS);
-
- lp->config = 0x20 | (lp->timeout<<3) | (lp->backplane<<2);
+
+ lp->config = 0x20 | (lp->timeout<<3) | (lp->backplane<<2);
/* power-up defaults */
SETCONF;
-
+
if (reset_delay)
{
/* reset the card */
ARCRESET;
JIFFER(RESETtime);
}
-
+
ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd|CONFIGclear);
-
+
/* verify that the ARCnet signature byte is present */
-
+
if (get_buffer_byte(dev,0) != TESTvalue)
{
BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
return 1;
}
-
+
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
-
+
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd|EXTconf);
-
+
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
-
+
/* re-enable interrupts */
lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
-
+
/* done! return success. */
return 0;
}
{
struct arcnet_local *lp=dev->priv;
int ioaddr=dev->base_addr;
-
+
if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP))
{ /* Enable promiscuous mode */
if (!(lp->setup & PROMISCflag))
SETCONF;
lp->setup &= ~PROMISCflag;
outb(lp->setup,ioaddr+7);
- }
+ }
}
MOD_DEC_USE_COUNT;
}
+
static void arc20020_en_dis_able_TX(struct device *dev, int enable)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
-
+
lp->config=enable?(lp->config | TXENflag):(lp->config & ~TXENflag);
SETCONF;
}
static void arc20020_setmask(struct device *dev, u_char mask)
{
short ioaddr=dev->base_addr;
-
+
AINTMASK(mask);
}
+
static u_char arc20020_status(struct device *dev)
{
short ioaddr=dev->base_addr;
return ARCSTATUS;
}
+
static void arc20020_command(struct device *dev, u_char cmd)
{
short ioaddr=dev->base_addr;
arc20020_inthandler(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
- int ioaddr=dev->base_addr, status, boguscount = 3, didsomething,
+ int ioaddr=dev->base_addr, status, boguscount = 3, didsomething,
dstatus;
-
-
-
+
AINTMASK(0);
-
+
BUGMSG(D_DURING,"in arc20020_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
-
+
do
{
status = ARCSTATUS;
didsomething=0;
-
-
+
+
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
status);
arc20020_reset(dev,0);
-
+
/* all other flag values are just garbage */
break;
}
-
-
+
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
int oldaddr=0;
-
+
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
-
+
/* enable receive of our next packet */
EnableReceiver();
-
+
if (lp->intx)
oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO);
-
-
+
/* Got a packet. */
arc20020_rx(dev,!recbuf);
-
-
+
if (lp->intx)
{
outb( (oldaddr >> 8), _ADDR_HI);
outb( oldaddr & 0xff, _ADDR_LO);
}
-
+
didsomething++;
}
-
+
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{
struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
-
+
lp->intmask &= ~TXFREEflag;
-
+
lp->in_txhandler++;
if (was_sending) lp->sending--;
-
+
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
-
+
if (was_sending && !(status&TXACKflag))
{
if (lp->lasttrans_dest != 0)
lp->lasttrans_dest);
}
}
-
+
/* send packet if there is one */
arcnet_go_tx(dev,0);
didsomething++;
-
+
if (lp->intx)
{
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
lp->in_txhandler--;
continue;
}
-
+
if (!lp->outgoing.skb)
{
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
-
+
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
-
+
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev,0);
-
+
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
dev_kfree_skb(out->skb,FREE_WRITE);
}
out->skb=NULL;
-
+
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
}
didsomething++;
-
+
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
arcnet_go_tx(dev,0);
didsomething++;
}
-
+
if ((dstatus=inb(_DIAGSTAT)) & NEWNXTIDflag)
{
REGNXTID;
SETCONF;
BUGMSG(D_EXTRA,"New NextID detected: %X\n",inb(ioaddr+7));
}
-
-
+
+
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
-
+
#ifdef SHOW_RECONFIGS
-
BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh, diag status=%Xh, config=%X)\n",
status,dstatus,lp->config);
#endif /* SHOW_RECONFIGS */
-
+
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
-
+
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
-
+
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
-
+
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
-
+
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
-
+
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
-
+
SETMASK; /* put back interrupt mask */
-
-}
+}
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
- */
+ */
static void
arc20020_rx(struct device *dev,int recbuf)
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
-
+
lp->stats.rx_packets++;
-
+
get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket);
-
+
saddr=arcpacket->hardheader.source;
-
+
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
return;
}
/* Set source address to zero to mark it as old */
-
+
put_buffer_byte(dev,recbuf*512,0);
-
+
arcpacket->hardheader.source=0;
-
+
daddr=arcpacket->hardheader.destination;
-
+
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
arcsoft=&arcpacket->raw[offset];
length=512-offset;
}
-
+
get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset);
-
+
arcnet_rx(lp, arcsoft, length, saddr, daddr);
-
+
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
}
-
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
char *data,int length,int daddr,int exceptA, int offset)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
-
+
length+=hdrlen;
-
+
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
-
+
put_buffer_byte(dev, lp->txbuf*512+1, daddr);
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length);
-
+
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4);
-
+
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
-
+
put_whole_buffer(dev, lp->txbuf*512+offset,4,"\0\0xff\0xff\0xff");
offset+=4;
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
-
+
put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0");
-
+
/* now round up to MinTU */
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU);
}
-
+
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
-
+
put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr);
put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data);
-
+
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
-
+
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
int init_module(void)
{
struct device *dev;
-
+
cards[0]=dev=(struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
-
+
memset(dev, 0, sizeof(struct device));
-
+
dev->name=(char *)kmalloc(9, GFP_KERNEL);
if (!dev->name)
{
if (node && node != 0xff)
dev->dev_addr[0]=node;
-
+
if (backplane) dev->dev_addr[1]=backplane?1:0;
if (clock) dev->dev_addr[2]=clock&7;
dev->dev_addr[3]=timeout&3;
dev->base_addr=io;
dev->irq=irq;
-
+
if (dev->irq==2) dev->irq=9;
if (register_netdev(dev) != 0)
return -EIO;
-
+
/* Increase use count of arcnet.o */
arcnet_use_count(1);
{
struct device *dev=cards[0];
int ioaddr=dev->base_addr;
-
+
if (dev->start) (*dev->stop)(dev);
-
+
/* Flush TX and disable RX */
if (ioaddr)
{
ACOMMAND(NOTXcmd); /* stop transmit */
ACOMMAND(NORXcmd); /* disable receive */
}
-
+
if (dev->irq)
{
irq2dev_map[dev->irq] = NULL;
free_irq(dev->irq,NULL);
}
-
+
if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
-
+
/* Decrease use count of arcnet.o */
arcnet_use_count(0);
}
+
#else
__initfunc(void com20020_setup (char *str, int *ints))
MAX_ARCNET_DEVS);
return;
}
-
+
dev=&arcnet_devs[arcnet_num_devs];
-
+
if (ints[0] < 1)
{
printk("com20020: You must give an IO address.\n");
case 2: /* IRQ */
dev->irq=ints[2];
-
+
case 1: /* IO address */
dev->base_addr=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
-
+
if (str)
strncpy(dev->name, str, 9);
-
+
arcnet_num_devs++;
}
#endif /* MODULE */
-
-
-
-/* com90io.c:
+/* $Id: com90io.c,v 1.2 1997/09/05 08:57:52 mj Exp $
+
Written 1997 by David Woodhouse <dwmw2@cam.ac.uk>
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
- Contact Avery at: apenwarr@foxnet.net or
+ Contact Avery at: apenwarr@bond.net or
RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
**********************
#include <net/arp.h>
-
-
-
-/* External functions from arcnet.c */
-
-
-
-#if ARCNET_DEBUG_MAX & D_SKB
-extern void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
- char *desc);
-#else
-#define arcnet_dump_skb(dev,skb,desc) ;
-#endif
-
-#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-extern void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
- char *desc);
-#else
-#define arcnet_dump_packet(dev,buffer,ext,desc) ;
-#endif
-extern void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
-extern void arcnet_makename(char *device);
-extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
-extern void arcnet_setup(struct device *dev);
-extern int arcnet_go_tx(struct device *dev,int enable_irq);
-extern void arcnetA_continue_tx(struct device *dev);
-extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
-extern void arcnet_use_count(int open);
-
-
/* Internal function declarations */
static int arc90io_probe(struct device *dev);
#endif
-
/* Handy defines for ARCnet specific stuff */
-/* The number of low I/O ports used by the ethercard. */
+/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 16
- /* COM 9026 controller chip --> ARCnet register addresses */
+/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define ARCRESET inb(_RESET)
-
#define SETCONF outb((lp->config),_CONFIG)
{
int ioaddr=dev->base_addr;
- outb(offset >> 8, _ADDR_HI);
+ outb(offset >> 8, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
return inb(_MEMDATA);
{
int ioaddr=dev->base_addr;
- outb(offset >> 8, _ADDR_HI);
+ outb(offset >> 8, _ADDR_HI);
outb(offset & 0xff, _ADDR_LO);
outb(datum, _MEMDATA);
outb( (offset >> 8) | AUTOINCflag, _ADDR_HI);
outb( offset & 0xff, _ADDR_LO);
-
+
while (length--)
#ifdef ONE_AT_A_TIME_TX
put_buffer_byte(dev,offset++,*(dest++));
static const char *version =
"com90io.c: v2.91 97/08/19 Avery Pennarun <apenwarr@bond.net> et al.\n";
+
/****************************************************************************
* *
* Probe and initialization *
* *
****************************************************************************/
-
-
/* We cannot probe for an IO mapped card either, although we can check that
* it's where we were told it was, and even autoirq
*/
{
int ioaddr=dev->base_addr,status,delayval;
unsigned long airqmask;
-
+
BUGLVL(D_NORMAL) printk(version);
-
+
if (ioaddr<0x200)
{
BUGMSG(D_NORMAL,"No autoprobe for IO mapped cards; you "
"must specify the base address!\n");
return -ENODEV;
}
-
+
if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGMSG(D_INIT_REASONS,"IO check_region %x-%x failed.\n",
ioaddr,ioaddr+ARCNET_TOTAL_SIZE-1);
return -ENXIO;
}
-
+
if (ARCSTATUS == 0xFF)
{
BUGMSG(D_INIT_REASONS,"IO address %x empty\n",ioaddr);
return -ENODEV;
}
-
+
ARCRESET;
JIFFER(RESETtime);
-
+
status=ARCSTATUS;
-
+
if ((status & 0x9D)
!= (NORXflag|RECONflag|TXFREEflag|RESETflag))
{
BUGMSG(D_INIT_REASONS,"Status invalid (%Xh).\n",status);
return -ENODEV;
}
-
-
+
BUGMSG(D_INIT_REASONS,"Status after reset: %X\n",status);
-
-
+
ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
-
+
BUGMSG(D_INIT_REASONS,"Status after reset acknowledged: %X\n",status);
-
+
status=ARCSTATUS;
-
+
if (status & RESETflag)
{
BUGMSG(D_INIT_REASONS,"Eternal reset (status=%Xh)\n",status);
return -ENODEV;
}
-
+
outb((0x16 | IOMAPflag) &~ENABLE16flag, _CONFIG);
-
-
+
/* Read first loc'n of memory */
-
+
outb(AUTOINCflag ,_ADDR_HI);
outb(0,_ADDR_LO);
-
+
if ((status=inb(_MEMDATA)) != 0xd1)
{
BUGMSG(D_INIT_REASONS,"Signature byte not found"
" (%Xh instead).\n", status);
return -ENODEV;
}
-
+
if (!dev->irq)
{
/* if we do this, we're sure to get an IRQ since the
* card has just reset and the NORXflag is on until
* we tell it to start receiving.
*/
-
+
airqmask = probe_irq_on();
outb(NORXflag,_INTMASK);
udelay(1);
outb(0,_INTMASK);
dev->irq = probe_irq_off(airqmask);
-
+
if (dev->irq<=0)
{
BUGMSG(D_INIT_REASONS,"Autoprobe IRQ failed\n");
return -ENODEV;
}
}
-
+
return arc90io_found(dev,dev->base_addr,dev->irq);
}
-
/* Set up the struct device associated with this card. Called after
* probing succeeds.
*/
__initfunc(int arc90io_found(struct device *dev,int ioaddr,int airq))
{
struct arcnet_local *lp;
-
+
/* reserve the irq */
if (request_irq(airq,&arcnet_interrupt,0,"arcnet (COM90xx-IO)",NULL))
{
}
irq2dev_map[airq]=dev;
dev->irq=airq;
-
+
/* reserve the I/O region - guaranteed to work by check_region */
request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (COM90xx-IO)");
dev->base_addr=ioaddr;
-
-
+
dev->mem_start=dev->mem_end=dev->rmem_start=dev->rmem_end=(long)NULL;
-
-
+
/* Initialize the rest of the device structure. */
-
+
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
lp=(struct arcnet_local *)(dev->priv);
lp->card_type = ARC_90xx_IO;
lp->card_type_str = "COM 90xx (IO)";
-
+
lp->arcnet_reset=arc90io_reset;
lp->asetmask=arc90io_setmask;
lp->astatus=arc90io_status;
lp->openclose_device=arc90io_openclose;
lp->prepare_tx=arc90io_prepare_tx;
lp->inthandler=arc90io_inthandler;
-
-
-
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
-
+
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
-
+
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
-
+
lp->config = (0x16 | IOMAPflag) & ~ENABLE16flag;
SETCONF;
-
+
/* get and check the station ID from offset 1 in shmem */
lp->stationid = get_buffer_byte(dev,1);
-
+
if (!lp->stationid)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
-
+
BUGMSG(D_NORMAL,"ARCnet COM90xx in IO-mapped mode: "
"station %02Xh found at %03lXh, IRQ %d.\n",
lp->stationid,
dev->base_addr,dev->irq);
-
+
return 0;
}
/****************************************************************************
* *
- * Utility routines for arcnet.c *
+ * Utility routines *
* *
****************************************************************************/
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int delayval,recbuf=lp->recbuf;
-
+
if (reset_delay==3)
{
ARCRESET;
return 0;
}
-
+
/* no IRQ's, please! */
lp->intmask=0;
SETMASK;
-
+
BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
dev->name,ARCSTATUS);
-
+
/* Set the thing to IO-mapped, 8-bit mode */
lp->config = (0x1C|IOMAPflag) & ~ENABLE16flag;
SETCONF;
-
+
if (reset_delay)
{
/* reset the card */
ARCRESET;
JIFFER(RESETtime);
}
-
+
ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
ACOMMAND(CFLAGScmd|CONFIGclear);
-
+
/* verify that the ARCnet signature byte is present */
-
+
if (get_buffer_byte(dev,0) != TESTvalue)
{
BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
return 1;
}
-
+
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
-
+
/* enable extended (512-byte) packets */
ACOMMAND(CONFIGcmd|EXTconf);
-
+
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
-
+
/* re-enable interrupts */
lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
lp->intmask|=RECONflag;
#endif
SETMASK;
-
+
/* done! return success. */
return 0;
}
}
-
static void arc90io_setmask(struct device *dev, u_char mask)
{
short ioaddr=dev->base_addr;
-
+
AINTMASK(mask);
}
arc90io_inthandler(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
- int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
+ int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
-
-
-
AINTMASK(0);
-
+
BUGMSG(D_DURING,"in arc90io_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
-
+
do
{
status = ARCSTATUS;
didsomething=0;
-
-
+
/* RESET flag was enabled - card is resetting and if RX
* is disabled, it's NOT because we just got a packet.
*/
BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
status);
arc90io_reset(dev,0);
-
+
/* all other flag values are just garbage */
break;
}
-
-
+
/* RX is inhibited - we must have received something. */
if (status & lp->intmask & NORXflag)
{
int recbuf=lp->recbuf=!lp->recbuf;
int oldaddr=0;
-
+
BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
status);
-
+
/* enable receive of our next packet */
EnableReceiver();
-
+
if (lp->intx)
oldaddr=(inb(_ADDR_HI)<<8) | inb(_ADDR_LO);
-
-
+
+
/* Got a packet. */
arc90io_rx(dev,!recbuf);
-
-
+
+
if (lp->intx)
{
outb( (oldaddr >> 8), _ADDR_HI);
outb( oldaddr & 0xff, _ADDR_LO);
}
-
+
didsomething++;
}
-
+
/* it can only be an xmit-done irq if we're xmitting :) */
/*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
if (status & lp->intmask & TXFREEflag)
{
struct Outgoing *out=&(lp->outgoing);
int was_sending=lp->sending;
-
+
lp->intmask &= ~TXFREEflag;
-
+
lp->in_txhandler++;
if (was_sending) lp->sending--;
-
+
BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
-
+
if (was_sending && !(status&TXACKflag))
{
if (lp->lasttrans_dest != 0)
lp->lasttrans_dest);
}
}
-
+
/* send packet if there is one */
arcnet_go_tx(dev,0);
didsomething++;
-
+
if (lp->intx)
{
BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
lp->in_txhandler--;
continue;
}
-
+
if (!lp->outgoing.skb)
{
BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
-
+
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
lp->in_txhandler--;
continue;
}
-
+
/* if more than one segment, and not all segments
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnetA_continue_tx(dev);
arcnet_go_tx(dev,0);
-
+
/* if segnum==numsegs, the transmission is finished;
* free the skb.
*/
dev_kfree_skb(out->skb,FREE_WRITE);
}
out->skb=NULL;
-
+
/* inform upper layers */
if (!lp->txready) arcnet_tx_done(dev, lp);
}
didsomething++;
-
+
lp->in_txhandler--;
}
else if (lp->txready && !lp->sending && !lp->intx)
arcnet_go_tx(dev,0);
didsomething++;
}
-
-
+
#ifdef DETECT_RECONFIGS
if (status & (lp->intmask) & RECONflag)
{
ACOMMAND(CFLAGScmd|CONFIGclear);
lp->stats.tx_carrier_errors++;
-
+
#ifdef SHOW_RECONFIGS
-
BUGMSG(D_NORMAL,"Network reconfiguration detected"
" (status=%Xh, config=%X)\n",
status,lp->config);
#endif /* SHOW_RECONFIGS */
-
+
#ifdef RECON_THRESHOLD
/* is the RECON info empty or old? */
if (!lp->first_recon || !lp->last_recon ||
BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
lp->first_recon=lp->last_recon=jiffies;
lp->num_recons=lp->network_down=0;
-
+
BUGMSG(D_DURING,"recon: clearing counters.\n");
}
else /* add to current RECON counter */
{
lp->last_recon=jiffies;
lp->num_recons++;
-
+
BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
lp->num_recons,
(lp->last_recon-lp->first_recon)/HZ,
lp->network_down);
-
+
/* if network is marked up;
* and first_recon and last_recon are 60+ sec
* apart;
BUGMSG(D_NORMAL,"cabling restored?\n");
lp->first_recon=lp->last_recon=0;
lp->num_recons=lp->network_down=0;
-
+
BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
}
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
-
+
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
-
+
SETMASK; /* put back interrupt mask */
-
}
-
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
- */
+ */
static void
arc90io_rx(struct device *dev,int recbuf)
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
-
+
lp->stats.rx_packets++;
-
+
get_whole_buffer(dev,recbuf*512,4,(char *)arcpacket);
-
+
saddr=arcpacket->hardheader.source;
-
+
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
return;
}
/* Set source address to zero to mark it as old */
-
+
put_buffer_byte(dev,recbuf*512,0);
-
+
arcpacket->hardheader.source=0;
-
+
daddr=arcpacket->hardheader.destination;
-
+
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
arcsoft=&arcpacket->raw[offset];
length=512-offset;
}
-
+
get_whole_buffer(dev,recbuf*512+offset,length,(char *)arcpacket+offset);
-
+
arcnet_rx(lp, arcsoft, length, saddr, daddr);
-
+
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
}
-
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
char *data,int length,int daddr,int exceptA, int offset)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
-
+
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
-
+
length+=hdrlen;
-
+
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
-
+
put_buffer_byte(dev, lp->txbuf*512+1, daddr);
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
put_buffer_byte(dev, lp->txbuf*512+2, offset=offset?offset:256-length);
-
+
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
{
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-length-4);
-
+
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
-
+
put_whole_buffer(dev, lp->txbuf*512+offset,4,"\0\0xff\0xff\0xff");
offset+=4;
}
else /* "other" Exception packet */
{
/* RFC1051 - set 4 trailing bytes to 0 */
-
+
put_whole_buffer(dev,lp->txbuf*512+508,4,"\0\0\0\0");
-
+
/* now round up to MinTU */
put_buffer_byte(dev, lp->txbuf*512+2, 0);
put_buffer_byte(dev, lp->txbuf*512+3, offset=512-MinTU);
}
-
+
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
-
+
put_whole_buffer(dev, 512*lp->txbuf+offset, hdrlen,(u_char *)hdr);
put_whole_buffer(dev, 512*lp->txbuf+offset+hdrlen,length-hdrlen,data);
-
+
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
-
+
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
int init_module(void)
{
struct device *dev=cards[0];
-
+
cards[0]=dev=(struct device *)kmalloc(sizeof(struct device), GFP_KERNEL);
if (!dev)
return -ENOMEM;
-
+
memset(dev, 0, sizeof(struct device));
-
+
dev->name=(char *)kmalloc(9, GFP_KERNEL);
if (!dev->name)
{
return -ENOMEM;
}
dev->init=arc90io_probe;
-
+
if (device)
strcpy(dev->name,device);
else arcnet_makename(dev->name);
dev->base_addr=io;
dev->irq=irq;
-
+
if (dev->irq==2) dev->irq=9;
-
+
if (register_netdev(dev) != 0)
return -EIO;
-
+
/* Increase use count of arcnet.o */
arcnet_use_count(1);
return 0;
{
struct device *dev=cards[0];
int ioaddr=dev->base_addr;
-
+
if (dev->start) (*dev->stop)(dev);
-
+
/* Flush TX and disable RX */
if (ioaddr)
{
driver is loaded later */
outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG);
}
-
+
if (dev->irq)
{
irq2dev_map[dev->irq] = NULL;
free_irq(dev->irq,NULL);
}
-
+
if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
unregister_netdev(dev);
kfree(dev->priv);
dev->priv = NULL;
-
+
/* Decrease use count of arcnet.o */
arcnet_use_count(0);
}
-#else
+#else
__initfunc(void com90io_setup (char *str, int *ints))
{
MAX_ARCNET_DEVS);
return;
}
-
+
dev=&arcnet_devs[arcnet_num_devs];
-
+
if (ints[0] < 1)
{
printk("com90xx IO-MAP: You must give an IO address.\n");
case 2: /* IRQ */
dev->irq=ints[2];
-
+
case 1: /* IO address */
dev->base_addr=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
-
+
if (str)
strncpy(dev->name, str, 9);
-
+
arcnet_num_devs++;
}
#endif /* MODULE */
-
-
-
-/* com90xx.c:
+/* $Id: com90xx.c,v 1.3 1997/09/05 18:27:23 mj Exp $
+
Derived from the original arcnet.c,
Written 1994-1996 by Avery Pennarun,
which was in turn derived from skeleton.c by Donald Becker.
- Contact Avery at: apenwarr@foxnet.net or
+ Contact Avery at: apenwarr@bond.net or
RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
**********************
#undef FAST_PROBE
-
-
-
-
-/* External functions from arcnet.c */
-
-
-
-#if ARCNET_DEBUG_MAX & D_SKB
-extern void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
- char *desc);
-#else
-#define arcnet_dump_skb(dev,skb,desc) ;
-#endif
-
-#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
-extern void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
- char *desc);
-#else
-#define arcnet_dump_packet(dev,buffer,ext,desc) ;
-#endif
-
-
-extern void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
-extern void arcnet_makename(char *device);
-extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
-extern void arcnet_setup(struct device *dev);
-extern int arcnet_go_tx(struct device *dev,int enable_irq);
-extern void arcnetA_continue_tx(struct device *dev);
-extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
-extern void arcnet_use_count(int open);
-
-
-
/* Internal function declarations */
-#ifdef MODULE
-static
+#ifdef MODULE
+static
#endif
int arc90xx_probe(struct device *dev);
static void arc90xx_rx(struct device *dev,int recbuf);
-static int arc90xx_found(struct device *dev,int ioaddr,int airq,u_long shmem);
+static int arc90xx_found(struct device *dev,int ioaddr,int airq,u_long shmem,int more);
static void arc90xx_inthandler (struct device *dev);
static int arc90xx_reset (struct device *dev, int reset_delay);
static void arc90xx_setmask (struct device *dev, u_char mask);
extern struct device arcnet_devs[];
extern char arcnet_dev_names[][10];
extern int arcnet_num_devs;
-
#endif
-
-
/* Handy defines for ARCnet specific stuff */
-/* The number of low I/O ports used by the ethercard. */
+/* The number of low I/O ports used by the card. */
#define ARCNET_TOTAL_SIZE 16
- /* COM 9026 controller chip --> ARCnet register addresses */
+/* COM 9026 controller chip --> ARCnet register addresses */
#define _INTMASK (ioaddr+0) /* writable */
#define _STATUS (ioaddr+0) /* readable */
#define _COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define RDDATAflag 0x00 /* Next access is a read/~write */
- #define ARCSTATUS inb(_STATUS)
- #define ACOMMAND(cmd) outb((cmd),_COMMAND)
- #define AINTMASK(msk) outb((msk),_INTMASK)
- #define SETCONF outb(lp->config,_CONFIG)
- #define ARCRESET inb(_RESET)
+#define ARCSTATUS inb(_STATUS)
+#define ACOMMAND(cmd) outb((cmd),_COMMAND)
+#define AINTMASK(msk) outb((msk),_INTMASK)
+#define SETCONF outb(lp->config,_CONFIG)
+#define ARCRESET inb(_RESET)
static const char *version =
- "com90xx.c: v2.91 97/08/19 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "com90xx.c: v2.92 97/09/02 Avery Pennarun <apenwarr@bond.net> et al.\n";
/****************************************************************************
static int init_once = 0;
static int numports=sizeof(ports)/sizeof(ports[0]),
numshmems=sizeof(shmems)/sizeof(shmems[0]);
-
int count,status,delayval,ioaddr,numprint,airq,retval=-ENODEV,
openparen=0;
unsigned long airqmask;
int *port;
u_long *shmem;
-
+
if (!init_once)
{
for (count=0x200; count<=0x3f0; count+=16)
ports[(count-0x200)/16] = count;
for (count=0xA0000; count<=0xFF800; count+=2048)
shmems[(count-0xA0000)/2048] = count;
- init_once=1;
- }
-
- BUGLVL(D_NORMAL) printk(version);
- BUGMSG(D_DURING,"space used for probe buffers: %d+%d=%d bytes\n",
+ BUGLVL(D_NORMAL) printk(version);
+ BUGMSG(D_DURING,"space used for probe buffers: %d+%d=%d bytes\n",
sizeof(ports),sizeof(shmems),
sizeof(ports)+sizeof(shmems));
-
-
-
+ }
+ init_once++;
+
BUGMSG(D_INIT,"given: base %lXh, IRQ %d, shmem %lXh\n",
dev->base_addr,dev->irq,dev->mem_start);
-
+
if (dev->base_addr > 0x1ff) /* Check a single specified port */
{
ports[0]=dev->base_addr;
}
else if (dev->base_addr > 0) /* Don't probe at all. */
return -ENXIO;
-
+
if (dev->mem_start)
{
shmems[0]=dev->mem_start;
numshmems=1;
}
-
-
+
/* Stage 1: abandon any reserved ports, or ones with status==0xFF
- * (empty), and reset any others by reading the reset port.
- */
+ * (empty), and reset any others by reading the reset port.
+ */
BUGMSG(D_INIT,"Stage 1: ");
numprint=0;
for (port = &ports[0]; port-ports<numports; port++)
numprint=1;
}
BUGMSG2(D_INIT,"%Xh ",*port);
-
+
ioaddr=*port;
-
+
if (check_region(*port, ARCNET_TOTAL_SIZE))
{
BUGMSG2(D_INIT_REASONS,"(check_region)\n");
port--;
continue;
}
-
+
if (ARCSTATUS == 0xFF)
{
- BUGMSG2(D_INIT_REASONS,"(empty)\n");
- BUGMSG(D_INIT_REASONS,"Stage 1: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
+ BUGMSG2(D_INIT_REASONS,"(empty)\n");
+ BUGMSG(D_INIT_REASONS,"Stage 1: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ *port=ports[numports-1];
+ numports--;
+ port--;
+ continue;
}
-
+
ARCRESET; /* begin resetting card */
BUGMSG2(D_INIT_REASONS,"\n");
BUGLVL(D_INIT_REASONS) numprint=0;
}
BUGMSG2(D_INIT,"\n");
-
+
if (!numports)
{
BUGMSG(D_NORMAL,"Stage 1: No ARCnet cards found.\n");
return -ENODEV;
}
-
-
+
/* Stage 2: we have now reset any possible ARCnet cards, so we can't
* do anything until they finish. If D_INIT, print the list of
* cards that are left.
*/
- BUGMSG(D_INIT,"Stage 2: ");
- numprint=0;
- for (port = &ports[0]; port-ports<numports; port++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 2: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%Xh ",*port);
- }
- BUGMSG2(D_INIT,"\n");
- JIFFER(RESETtime);
-
-
- /* Stage 3: abandon any shmem addresses that don't have the signature
- * 0xD1 byte in the right place, or are read-only.
- */
- BUGMSG(D_INIT,"Stage 3: ");
- numprint=0;
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- {
- u_long ptr;
-
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 3: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%lXh ",*shmem);
-
- ptr=(u_long)(*shmem);
-
- if (readb(ptr) != TESTvalue)
- {
- BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
- readb(ptr),TESTvalue);
- BUGMSG(D_INIT_REASONS,"Stage 3: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *shmem=shmems[numshmems-1];
- numshmems--;
- shmem--;
- continue;
- }
-
- /* By writing 0x42 to the TESTvalue location, we also make
- * sure no "mirror" shmem areas show up - if they occur
- * in another pass through this loop, they will be discarded
- * because *cptr != TESTvalue.
- */
- writeb(0x42,ptr);
- if (readb(ptr) != 0x42)
- {
- BUGMSG2(D_INIT_REASONS,"(read only)\n");
- BUGMSG(D_INIT_REASONS,"Stage 3: ");
- *shmem=shmems[numshmems-1];
- numshmems--;
- shmem--;
- continue;
- }
-
- BUGMSG2(D_INIT_REASONS,"\n");
- BUGMSG(D_INIT_REASONS,"Stage 3: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- }
- BUGMSG2(D_INIT,"\n");
-
- if (!numshmems)
- {
- BUGMSG(D_NORMAL,"Stage 3: No ARCnet cards found.\n");
- return -ENODEV;
- }
-
- /* Stage 4: something of a dummy, to report the shmems that are
- * still possible after stage 3.
- */
- BUGMSG(D_INIT,"Stage 4: ");
- numprint=0;
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 4: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%lXh ",*shmem);
- }
- BUGMSG2(D_INIT,"\n");
-
-
- /* Stage 5: for any ports that have the correct status, can disable
- * the RESET flag, and (if no irq is given) generate an autoirq,
- * register an ARCnet device.
- *
- * Currently, we can only register one device per probe, so quit
- * after the first one is found.
- */
- BUGMSG(D_INIT,"Stage 5: ");
- numprint=0;
- for (port = &ports[0]; port-ports<numports; port++)
- {
- numprint++;
- if (numprint>8)
- {
- BUGMSG2(D_INIT,"\n");
- BUGMSG(D_INIT,"Stage 5: ");
- numprint=1;
- }
- BUGMSG2(D_INIT,"%Xh ",*port);
-
- ioaddr=*port;
- status=ARCSTATUS;
-
- if ((status & 0x9D)
- != (NORXflag|RECONflag|TXFREEflag|RESETflag))
- {
- BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status);
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
- }
-
- ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
- status=ARCSTATUS;
- if (status & RESETflag)
- {
- BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n",
- status);
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
- }
-
- /* skip this completely if an IRQ was given, because maybe
- * we're on a machine that locks during autoirq!
- */
- if (!dev->irq)
- {
- /* if we do this, we're sure to get an IRQ since the
- * card has just reset and the NORXflag is on until
- * we tell it to start receiving.
- */
- airqmask = probe_irq_on();
- AINTMASK(NORXflag);
- udelay(1);
- AINTMASK(0);
- airq = probe_irq_off(airqmask);
-
- if (airq<=0)
- {
- BUGMSG2(D_INIT_REASONS,"(airq=%d)\n",airq);
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- *port=ports[numports-1];
- numports--;
- port--;
- continue;
- }
- }
- else
- {
- airq=dev->irq;
- }
-
- BUGMSG2(D_INIT,"(%d,", airq);
- openparen=1;
-
- /* Everything seems okay. But which shmem, if any, puts
- * back its signature byte when the card is reset?
- *
- * If there are multiple cards installed, there might be
- * multiple shmems still in the list.
- */
+ BUGMSG(D_INIT,"Stage 2: ");
+ numprint=0;
+ for (port = &ports[0]; port-ports<numports; port++)
+ {
+ numprint++;
+ if (numprint>8)
+ {
+ BUGMSG2(D_INIT,"\n");
+ BUGMSG(D_INIT,"Stage 2: ");
+ numprint=1;
+ }
+ BUGMSG2(D_INIT,"%Xh ",*port);
+ }
+ BUGMSG2(D_INIT,"\n");
+ JIFFER(RESETtime);
+
+ /* Stage 3: abandon any shmem addresses that don't have the signature
+ * 0xD1 byte in the right place, or are read-only.
+ */
+ BUGMSG(D_INIT,"Stage 3: ");
+ numprint=0;
+ for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+ {
+ u_long ptr;
+
+ numprint++;
+ if (numprint>8)
+ {
+ BUGMSG2(D_INIT,"\n");
+ BUGMSG(D_INIT,"Stage 3: ");
+ numprint=1;
+ }
+ BUGMSG2(D_INIT,"%lXh ",*shmem);
+
+ ptr=(u_long)(*shmem);
+
+ if (readb(ptr) != TESTvalue)
+ {
+ BUGMSG2(D_INIT_REASONS,"(mem=%02Xh, not %02Xh)\n",
+ readb(ptr),TESTvalue);
+ BUGMSG(D_INIT_REASONS,"Stage 3: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ *shmem=shmems[numshmems-1];
+ numshmems--;
+ shmem--;
+ continue;
+ }
+
+ /* By writing 0x42 to the TESTvalue location, we also make
+ * sure no "mirror" shmem areas show up - if they occur
+ * in another pass through this loop, they will be discarded
+ * because *cptr != TESTvalue.
+ */
+ writeb(0x42,ptr);
+ if (readb(ptr) != 0x42)
+ {
+ BUGMSG2(D_INIT_REASONS,"(read only)\n");
+ BUGMSG(D_INIT_REASONS,"Stage 3: ");
+ *shmem=shmems[numshmems-1];
+ numshmems--;
+ shmem--;
+ continue;
+ }
+
+ BUGMSG2(D_INIT_REASONS,"\n");
+ BUGMSG(D_INIT_REASONS,"Stage 3: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ }
+ BUGMSG2(D_INIT,"\n");
+
+ if (!numshmems)
+ {
+ BUGMSG(D_NORMAL,"Stage 3: No ARCnet cards found.\n");
+ return -ENODEV;
+ }
+
+ /* Stage 4: something of a dummy, to report the shmems that are
+ * still possible after stage 3.
+ */
+ BUGMSG(D_INIT,"Stage 4: ");
+ numprint=0;
+ for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+ {
+ numprint++;
+ if (numprint>8)
+ {
+ BUGMSG2(D_INIT,"\n");
+ BUGMSG(D_INIT,"Stage 4: ");
+ numprint=1;
+ }
+ BUGMSG2(D_INIT,"%lXh ",*shmem);
+ }
+ BUGMSG2(D_INIT,"\n");
+
+ /* Stage 5: for any ports that have the correct status, can disable
+ * the RESET flag, and (if no irq is given) generate an autoirq,
+ * register an ARCnet device.
+ *
+ * Currently, we can only register one device per probe, so quit
+ * after the first one is found.
+ */
+ BUGMSG(D_INIT,"Stage 5: ");
+ numprint=0;
+ for (port = &ports[0]; port-ports<numports; port++)
+ {
+ numprint++;
+ if (numprint>8)
+ {
+ BUGMSG2(D_INIT,"\n");
+ BUGMSG(D_INIT,"Stage 5: ");
+ numprint=1;
+ }
+ BUGMSG2(D_INIT,"%Xh ",*port);
+
+ ioaddr=*port;
+ status=ARCSTATUS;
+
+ if ((status & 0x9D)
+ != (NORXflag|RECONflag|TXFREEflag|RESETflag))
+ {
+ BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status);
+ BUGMSG(D_INIT_REASONS,"Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ *port=ports[numports-1];
+ numports--;
+ port--;
+ continue;
+ }
+
+ ACOMMAND(CFLAGScmd|RESETclear|CONFIGclear);
+ status=ARCSTATUS;
+ if (status & RESETflag)
+ {
+ BUGMSG2(D_INIT_REASONS," (eternal reset, status=%Xh)\n",
+ status);
+ BUGMSG(D_INIT_REASONS,"Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ *port=ports[numports-1];
+ numports--;
+ port--;
+ continue;
+ }
+
+ /* skip this completely if an IRQ was given, because maybe
+ * we're on a machine that locks during autoirq!
+ */
+ if (!dev->irq)
+ {
+ /* if we do this, we're sure to get an IRQ since the
+ * card has just reset and the NORXflag is on until
+ * we tell it to start receiving.
+ */
+ airqmask = probe_irq_on();
+ AINTMASK(NORXflag);
+ udelay(1);
+ AINTMASK(0);
+ airq = probe_irq_off(airqmask);
+
+ if (airq<=0)
+ {
+ BUGMSG2(D_INIT_REASONS,"(airq=%d)\n",airq);
+ BUGMSG(D_INIT_REASONS,"Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ *port=ports[numports-1];
+ numports--;
+ port--;
+ continue;
+ }
+ }
+ else
+ {
+ airq=dev->irq;
+ }
+
+ BUGMSG2(D_INIT,"(%d,", airq);
+ openparen=1;
+
+ /* Everything seems okay. But which shmem, if any, puts
+ * back its signature byte when the card is reset?
+ *
+ * If there are multiple cards installed, there might be
+ * multiple shmems still in the list.
+ */
#ifdef FAST_PROBE
- if (numports>1 || numshmems>1)
- {
- ARCRESET;
- JIFFER(RESETtime);
- }
- else
- {
- /* just one shmem and port, assume they match */
- writeb(TESTvalue,shmems[0]);
- }
+ if (numports>1 || numshmems>1)
+ {
+ ARCRESET;
+ JIFFER(RESETtime);
+ }
+ else
+ {
+ /* just one shmem and port, assume they match */
+ writeb(TESTvalue,shmems[0]);
+ }
#else
- ARCRESET;
- JIFFER(RESETtime);
+ ARCRESET;
+ JIFFER(RESETtime);
#endif
-
-
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- {
- u_long ptr;
- ptr=(u_long)(*shmem);
-
- if (readb(ptr) == TESTvalue) /* found one */
- {
- BUGMSG2(D_INIT,"%lXh)\n", *shmem);
- openparen=0;
-
- /* register the card */
- retval=arc90xx_found(dev,*port,airq,*shmem);
- if (retval) openparen=0;
-
- /* remove shmem from the list */
- *shmem=shmems[numshmems-1];
- numshmems--;
-
- break;
- }
- else
- {
- BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
- }
- }
-
- if (openparen)
- {
- BUGMSG2(D_INIT,"no matching shmem)\n");
- BUGMSG(D_INIT_REASONS,"Stage 5: ");
- BUGLVL(D_INIT_REASONS) numprint=0;
- }
-
- *port=ports[numports-1];
- numports--;
- port--;
-
- if (!retval) break;
- }
- BUGMSG(D_INIT_REASONS,"\n");
-
- /* Now put back TESTvalue on all leftover shmems.
- */
- for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
- writeb(TESTvalue,*shmem);
-
- if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n");
- return retval;
+
+ for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+ {
+ u_long ptr;
+ ptr=(u_long)(*shmem);
+
+ if (readb(ptr) == TESTvalue) /* found one */
+ {
+ int probe_more;
+ BUGMSG2(D_INIT,"%lXh)\n", *shmem);
+ openparen=0;
+
+ /* register the card */
+ if (init_once == 1 && numshmems > 1)
+ probe_more = numshmems - 1;
+ else
+ probe_more = 0;
+ retval=arc90xx_found(dev,*port,airq,*shmem,probe_more);
+ if (retval) openparen=0;
+
+ /* remove shmem from the list */
+ *shmem=shmems[numshmems-1];
+ numshmems--;
+
+ break;
+ }
+ else
+ {
+ BUGMSG2(D_INIT_REASONS,"%Xh-", readb(ptr));
+ }
+ }
+
+ if (openparen)
+ {
+ BUGMSG2(D_INIT,"no matching shmem)\n");
+ BUGMSG(D_INIT_REASONS,"Stage 5: ");
+ BUGLVL(D_INIT_REASONS) numprint=0;
+ }
+
+ *port=ports[numports-1];
+ numports--;
+ port--;
+
+ if (!retval) break;
+ }
+ BUGMSG(D_INIT_REASONS,"\n");
+
+ /* Now put back TESTvalue on all leftover shmems.
+ */
+ for (shmem = &shmems[0]; shmem-shmems<numshmems; shmem++)
+ writeb(TESTvalue,*shmem);
+
+ if (retval) BUGMSG(D_NORMAL,"Stage 5: No ARCnet cards found.\n");
+ return retval;
}
/* Set up the struct device associated with this card. Called after
* probing succeeds.
*/
-__initfunc(int arc90xx_found(struct device *dev,int ioaddr,int airq, u_long shmem))
+__initfunc(static int arc90xx_found(struct device *dev,int ioaddr,int airq, u_long shmem, int more))
{
struct arcnet_local *lp;
u_long first_mirror,last_mirror;
int mirror_size;
-
+
/* reserve the irq */
if (request_irq(airq,&arcnet_interrupt,0,"arcnet (90xx)",NULL))
{
}
irq2dev_map[airq]=dev;
dev->irq=airq;
-
-
+
/* reserve the I/O region - guaranteed to work by check_region */
request_region(ioaddr,ARCNET_TOTAL_SIZE,"arcnet (90xx)");
dev->base_addr=ioaddr;
-
+
/* find the real shared memory start/end points, including mirrors */
#define BUFFER_SIZE (512)
#define MIRROR_SIZE (BUFFER_SIZE*4)
-
+
/* guess the actual size of one "memory mirror" - the number of
- * bytes between copies of the shared memory. On most cards, it's
- * 2k (or there are no mirrors at all) but on some, it's 4k.
- */
+ * bytes between copies of the shared memory. On most cards, it's
+ * 2k (or there are no mirrors at all) but on some, it's 4k.
+ */
mirror_size=MIRROR_SIZE;
if (readb(shmem)==TESTvalue
&& readb(shmem-mirror_size)!=TESTvalue
&& readb(shmem-2*mirror_size)==TESTvalue)
mirror_size*=2;
-
+
first_mirror=last_mirror=shmem;
while (readb(first_mirror)==TESTvalue) first_mirror-=mirror_size;
first_mirror+=mirror_size;
-
+
while (readb(last_mirror)==TESTvalue) last_mirror+=mirror_size;
last_mirror-=mirror_size;
-
+
dev->mem_start=first_mirror;
dev->mem_end=last_mirror+MIRROR_SIZE-1;
dev->rmem_start=dev->mem_start+BUFFER_SIZE*0;
dev->rmem_end=dev->mem_start+BUFFER_SIZE*2-1;
-
- /* Initialize the rest of the device structure. */
-
+
+ /* Initialize the rest of the device structure. */
+
dev->priv = kmalloc(sizeof(struct arcnet_local), GFP_KERNEL);
if (dev->priv == NULL)
{
lp->openclose_device=arc90xx_openclose;
lp->prepare_tx=arc90xx_prepare_tx;
lp->inthandler=arc90xx_inthandler;
-
-
+
/* Fill in the fields of the device structure with generic
* values.
*/
arcnet_setup(dev);
-
+
/* And now fill particular fields with arcnet values */
dev->mtu=1500; /* completely arbitrary - agrees with ether, though */
dev->hard_header_len=sizeof(struct ClientData);
lp->sequence=1;
lp->recbuf=0;
-
+
BUGMSG(D_DURING,"ClientData header size is %d.\n",
sizeof(struct ClientData));
BUGMSG(D_DURING,"HardHeader size is %d.\n",
sizeof(struct archdr));
-
+
/* get and check the station ID from offset 1 in shmem */
lp->stationid = readb(first_mirror+1);
-
+
if (lp->stationid==0)
BUGMSG(D_NORMAL,"WARNING! Station address 00 is reserved "
"for broadcasts!\n");
BUGMSG(D_NORMAL,"WARNING! Station address FF may confuse "
"DOS networking programs!\n");
dev->dev_addr[0]=lp->stationid;
-
+
BUGMSG(D_NORMAL,"ARCnet COM90xx: station %02Xh found at %03lXh, IRQ %d, "
"ShMem %lXh (%ld*%xh).\n",
lp->stationid,
dev->base_addr, dev->irq, dev->mem_start,
(dev->mem_end-dev->mem_start+1)/mirror_size,mirror_size);
-#ifdef CONFIG_ARCNET_COM90xx
- /* OK. We're finished. Now do we need to probe for other cards? */
+ /* OK. We're finished. If there are probably other cards, add other
+ * COM90xx drivers to the device chain, so they get probed later.
+ */
- if (!com90xx_explicit)
+#ifndef MODULE
+ while (!com90xx_explicit && more--)
{
- /* We need to check whether there's another card here.
- * Just add another COM90xx driver to the device chain.
- */
-
if (arcnet_num_devs < MAX_ARCNET_DEVS)
{
arcnet_devs[arcnet_num_devs].next=dev->next;
dev->next=&arcnet_devs[arcnet_num_devs];
- dev->next->name=(char *)&arcnet_dev_names[arcnet_num_devs];
+ dev=dev->next;
+ dev->name=(char *)&arcnet_dev_names[arcnet_num_devs];
arcnet_num_devs++;
}
else
{
- while (dev->next) dev=dev->next;
-
- dev->next=kmalloc(sizeof(struct device), GFP_KERNEL);
- if (!dev->next)
- {
- BUGMSG(D_NORMAL, "No memory for allocating next device - no more "
- "will be probed for.\n");
- return 0;
- }
- memset(dev->next,0,sizeof(struct device));
- dev->next->name=kmalloc(10, GFP_KERNEL);
- if (!dev->next->name)
- {
- BUGMSG(D_NORMAL, "No memory for allocating next device - no more "
- "will be probed for.\n");
- kfree(dev->next);
- dev->next=NULL;
- return 0;
- }
+ BUGMSG(D_NORMAL, "Too many arcnet devices - no more will be probed for.\n");
+ return 0;
}
- arcnet_makename(dev->next->name);
- dev->next->init=arc90xx_probe;
+ arcnet_makename(dev->name);
+ dev->init=arc90xx_probe;
}
#endif
}
-
/* Do a hardware reset on the card, and set up necessary registers.
*
* This should be called as little as possible, because it disrupts the
*/
int arc90xx_reset(struct device *dev,int reset_delay)
{
- struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
- short ioaddr=dev->base_addr;
- int delayval,recbuf=lp->recbuf;
+ struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
+ short ioaddr=dev->base_addr;
+ int delayval,recbuf=lp->recbuf;
if (reset_delay==3)
{
ARCRESET;
return 0;
}
-
- /* no IRQ's, please! */
- lp->intmask=0;
- SETMASK;
- BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
- dev->name,ARCSTATUS);
+ /* no IRQ's, please! */
+ lp->intmask=0;
+ SETMASK;
- if (reset_delay)
- {
- /* reset the card */
- ARCRESET;
- JIFFER(RESETtime);
- }
+ BUGMSG(D_INIT,"Resetting %s (status=%Xh)\n",
+ dev->name,ARCSTATUS);
- ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
- ACOMMAND(CFLAGScmd|CONFIGclear);
+ if (reset_delay)
+ {
+ /* reset the card */
+ ARCRESET;
+ JIFFER(RESETtime);
+ }
- /* verify that the ARCnet signature byte is present */
- if (readb(dev->mem_start) != TESTvalue)
- {
- BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
- return 1;
- }
+ ACOMMAND(CFLAGScmd|RESETclear); /* clear flags & end reset */
+ ACOMMAND(CFLAGScmd|CONFIGclear);
- /* clear out status variables */
- recbuf=lp->recbuf=0;
- lp->txbuf=2;
+ /* verify that the ARCnet signature byte is present */
+ if (readb(dev->mem_start) != TESTvalue)
+ {
+ BUGMSG(D_NORMAL,"reset failed: TESTvalue not present.\n");
+ return 1;
+ }
- /* enable extended (512-byte) packets */
- ACOMMAND(CONFIGcmd|EXTconf);
+ /* clear out status variables */
+ recbuf=lp->recbuf=0;
+ lp->txbuf=2;
+
+ /* enable extended (512-byte) packets */
+ ACOMMAND(CONFIGcmd|EXTconf);
#ifndef SLOW_XMIT_COPY
- /* clean out all the memory to make debugging make more sense :) */
- BUGLVL(D_DURING)
- memset_io(dev->mem_start,0x42,2048);
+ /* clean out all the memory to make debugging make more sense :) */
+ BUGLVL(D_DURING)
+ memset_io(dev->mem_start,0x42,2048);
#endif
- /* and enable receive of our first packet to the first buffer */
- EnableReceiver();
+ /* and enable receive of our first packet to the first buffer */
+ EnableReceiver();
- /* re-enable interrupts */
- lp->intmask|=NORXflag;
+ /* re-enable interrupts */
+ lp->intmask|=NORXflag;
#ifdef DETECT_RECONFIGS
- lp->intmask|=RECONflag;
+ lp->intmask|=RECONflag;
#endif
- SETMASK;
+ SETMASK;
- /* done! return success. */
- return 0;
+ /* done! return success. */
+ return 0;
}
+
static void arc90xx_openclose(int open)
{
if (open)
AINTMASK(mask);
}
+
static u_char arc90xx_status(struct device *dev)
{
short ioaddr=dev->base_addr;
return ARCSTATUS;
}
+
static void arc90xx_command(struct device *dev, u_char cmd)
{
short ioaddr=dev->base_addr;
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr, status, boguscount = 3, didsomething;
-
-
+
AINTMASK(0);
-
+
BUGMSG(D_DURING,"in arcnet_inthandler (status=%Xh, intmask=%Xh)\n",
ARCSTATUS,lp->intmask);
-
+
do
{
status = ARCSTATUS;
- didsomething=0;
-
-
- /* RESET flag was enabled - card is resetting and if RX
- * is disabled, it's NOT because we just got a packet.
- */
- if (status & RESETflag)
- {
- BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
- status);
- arc90xx_reset(dev,0);
-
- /* all other flag values are just garbage */
- break;
- }
-
-
- /* RX is inhibited - we must have received something. */
- if (status & lp->intmask & NORXflag)
- {
- int recbuf=lp->recbuf=!lp->recbuf;
-
- BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
- status);
-
- /* enable receive of our next packet */
- EnableReceiver();
-
- /* Got a packet. */
- arc90xx_rx(dev,!recbuf);
-
- didsomething++;
- }
-
- /* it can only be an xmit-done irq if we're xmitting :) */
- /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
- if (status & lp->intmask & TXFREEflag)
- {
- struct Outgoing *out=&(lp->outgoing);
- int was_sending=lp->sending;
-
- lp->intmask &= ~TXFREEflag;
-
- lp->in_txhandler++;
- if (was_sending) lp->sending--;
-
- BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
- status,out->numsegs,out->segnum,out->skb);
-
- if (was_sending && !(status&TXACKflag))
- {
- if (lp->lasttrans_dest != 0)
- {
- BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
- status,lp->lasttrans_dest);
- lp->stats.tx_errors++;
- lp->stats.tx_carrier_errors++;
- }
- else
- {
- BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
- status,
- lp->lasttrans_dest);
- }
- }
-
- /* send packet if there is one */
- arcnet_go_tx(dev,0);
- didsomething++;
-
- if (lp->intx)
- {
- BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
- ARCSTATUS,lp->intx);
- lp->in_txhandler--;
- continue;
- }
-
- if (!lp->outgoing.skb)
- {
- BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
-
- /* inform upper layers */
- if (!lp->txready) arcnet_tx_done(dev, lp);
- lp->in_txhandler--;
- continue;
- }
-
- /* if more than one segment, and not all segments
- * are done, then continue xmit.
- */
- if (out->segnum<out->numsegs)
- arcnetA_continue_tx(dev);
- arcnet_go_tx(dev,0);
-
- /* if segnum==numsegs, the transmission is finished;
- * free the skb.
- */
- if (out->segnum>=out->numsegs)
- {
- /* transmit completed */
- out->segnum++;
- if (out->skb)
- {
- lp->stats.tx_bytes += out->skb->len;
- dev_kfree_skb(out->skb,FREE_WRITE);
- }
- out->skb=NULL;
-
- /* inform upper layers */
- if (!lp->txready) arcnet_tx_done(dev, lp);
- }
- didsomething++;
-
- lp->in_txhandler--;
- }
- else if (lp->txready && !lp->sending && !lp->intx)
- {
- BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
- status);
- arcnet_go_tx(dev,0);
- didsomething++;
- }
+ didsomething=0;
+
+ /* RESET flag was enabled - card is resetting and if RX
+ * is disabled, it's NOT because we just got a packet.
+ */
+ if (status & RESETflag)
+ {
+ BUGMSG(D_NORMAL,"spurious reset (status=%Xh)\n",
+ status);
+ arc90xx_reset(dev,0);
+
+ /* all other flag values are just garbage */
+ break;
+ }
+
+ /* RX is inhibited - we must have received something. */
+ if (status & lp->intmask & NORXflag)
+ {
+ int recbuf=lp->recbuf=!lp->recbuf;
+
+ BUGMSG(D_DURING,"receive irq (status=%Xh)\n",
+ status);
+
+ /* enable receive of our next packet */
+ EnableReceiver();
+
+ /* Got a packet. */
+ arc90xx_rx(dev,!recbuf);
+
+ didsomething++;
+ }
+
+ /* it can only be an xmit-done irq if we're xmitting :) */
+ /*if (status&TXFREEflag && !lp->in_txhandler && lp->sending)*/
+ if (status & lp->intmask & TXFREEflag)
+ {
+ struct Outgoing *out=&(lp->outgoing);
+ int was_sending=lp->sending;
+
+ lp->intmask &= ~TXFREEflag;
+
+ lp->in_txhandler++;
+ if (was_sending) lp->sending--;
+
+ BUGMSG(D_DURING,"TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
+ status,out->numsegs,out->segnum,out->skb);
+
+ if (was_sending && !(status&TXACKflag))
+ {
+ if (lp->lasttrans_dest != 0)
+ {
+ BUGMSG(D_EXTRA,"transmit was not acknowledged! (status=%Xh, dest=%02Xh)\n",
+ status,lp->lasttrans_dest);
+ lp->stats.tx_errors++;
+ lp->stats.tx_carrier_errors++;
+ }
+ else
+ {
+ BUGMSG(D_DURING,"broadcast was not acknowledged; that's normal (status=%Xh, dest=%02Xh)\n",
+ status,
+ lp->lasttrans_dest);
+ }
+ }
+
+ /* send packet if there is one */
+ arcnet_go_tx(dev,0);
+ didsomething++;
+
+ if (lp->intx)
+ {
+ BUGMSG(D_DURING,"TXDONE while intx! (status=%Xh, intx=%d)\n",
+ ARCSTATUS,lp->intx);
+ lp->in_txhandler--;
+ continue;
+ }
+
+ if (!lp->outgoing.skb)
+ {
+ BUGMSG(D_DURING,"TX IRQ done: no split to continue.\n");
+
+ /* inform upper layers */
+ if (!lp->txready) arcnet_tx_done(dev, lp);
+ lp->in_txhandler--;
+ continue;
+ }
+
+ /* if more than one segment, and not all segments
+ * are done, then continue xmit.
+ */
+ if (out->segnum<out->numsegs)
+ arcnetA_continue_tx(dev);
+ arcnet_go_tx(dev,0);
+
+ /* if segnum==numsegs, the transmission is finished;
+ * free the skb.
+ */
+ if (out->segnum>=out->numsegs)
+ {
+ /* transmit completed */
+ out->segnum++;
+ if (out->skb)
+ {
+ lp->stats.tx_bytes += out->skb->len;
+ dev_kfree_skb(out->skb,FREE_WRITE);
+ }
+ out->skb=NULL;
+
+ /* inform upper layers */
+ if (!lp->txready) arcnet_tx_done(dev, lp);
+ }
+ didsomething++;
+
+ lp->in_txhandler--;
+ }
+ else if (lp->txready && !lp->sending && !lp->intx)
+ {
+ BUGMSG(D_NORMAL,"recovery from silent TX (status=%Xh)\n",
+ status);
+ arcnet_go_tx(dev,0);
+ didsomething++;
+ }
#ifdef DETECT_RECONFIGS
- if (status & (lp->intmask) & RECONflag)
- {
- ACOMMAND(CFLAGScmd|CONFIGclear);
- lp->stats.tx_carrier_errors++;
-
+ if (status & (lp->intmask) & RECONflag)
+ {
+ ACOMMAND(CFLAGScmd|CONFIGclear);
+ lp->stats.tx_carrier_errors++;
+
#ifdef SHOW_RECONFIGS
- BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
- status);
-
-
+ BUGMSG(D_NORMAL,"Network reconfiguration detected (status=%Xh)\n",
+ status);
#endif /* SHOW_RECONFIGS */
-
+
#ifdef RECON_THRESHOLD
- /* is the RECON info empty or old? */
- if (!lp->first_recon || !lp->last_recon ||
- jiffies-lp->last_recon > HZ*10)
- {
- if (lp->network_down)
- BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
- lp->first_recon=lp->last_recon=jiffies;
- lp->num_recons=lp->network_down=0;
-
- BUGMSG(D_DURING,"recon: clearing counters.\n");
- }
- else /* add to current RECON counter */
- {
- lp->last_recon=jiffies;
- lp->num_recons++;
-
- BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
- lp->num_recons,
- (lp->last_recon-lp->first_recon)/HZ,
- lp->network_down);
-
- /* if network is marked up;
- * and first_recon and last_recon are 60+ sec
- * apart;
- * and the average no. of recons counted is
- * > RECON_THRESHOLD/min;
- * then print a warning message.
- */
- if (!lp->network_down
- && (lp->last_recon-lp->first_recon)<=HZ*60
- && lp->num_recons >= RECON_THRESHOLD)
- {
- lp->network_down=1;
- BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
- }
- else if (!lp->network_down
- && lp->last_recon-lp->first_recon > HZ*60)
- {
- /* reset counters if we've gone for
- * over a minute.
- */
- lp->first_recon=lp->last_recon;
- lp->num_recons=1;
- }
- }
- }
- else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
- {
- if (lp->network_down)
- BUGMSG(D_NORMAL,"cabling restored?\n");
- lp->first_recon=lp->last_recon=0;
- lp->num_recons=lp->network_down=0;
-
- BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
+ /* is the RECON info empty or old? */
+ if (!lp->first_recon || !lp->last_recon ||
+ jiffies-lp->last_recon > HZ*10)
+ {
+ if (lp->network_down)
+ BUGMSG(D_NORMAL,"reconfiguration detected: cabling restored?\n");
+ lp->first_recon=lp->last_recon=jiffies;
+ lp->num_recons=lp->network_down=0;
+
+ BUGMSG(D_DURING,"recon: clearing counters.\n");
+ }
+ else /* add to current RECON counter */
+ {
+ lp->last_recon=jiffies;
+ lp->num_recons++;
+
+ BUGMSG(D_DURING,"recon: counter=%d, time=%lds, net=%d\n",
+ lp->num_recons,
+ (lp->last_recon-lp->first_recon)/HZ,
+ lp->network_down);
+
+ /* if network is marked up;
+ * and first_recon and last_recon are 60+ sec
+ * apart;
+ * and the average no. of recons counted is
+ * > RECON_THRESHOLD/min;
+ * then print a warning message.
+ */
+ if (!lp->network_down
+ && (lp->last_recon-lp->first_recon)<=HZ*60
+ && lp->num_recons >= RECON_THRESHOLD)
+ {
+ lp->network_down=1;
+ BUGMSG(D_NORMAL,"many reconfigurations detected: cabling problem?\n");
+ }
+ else if (!lp->network_down
+ && lp->last_recon-lp->first_recon > HZ*60)
+ {
+ /* reset counters if we've gone for
+ * over a minute.
+ */
+ lp->first_recon=lp->last_recon;
+ lp->num_recons=1;
+ }
+ }
+ }
+ else if (lp->network_down && jiffies-lp->last_recon > HZ*10)
+ {
+ if (lp->network_down)
+ BUGMSG(D_NORMAL,"cabling restored?\n");
+ lp->first_recon=lp->last_recon=0;
+ lp->num_recons=lp->network_down=0;
+
+ BUGMSG(D_DURING,"not recon: clearing counters anyway.\n");
#endif
- }
+ }
#endif /* DETECT_RECONFIGS */
} while (--boguscount && didsomething);
-
+
BUGMSG(D_DURING,"net_interrupt complete (status=%Xh, count=%d)\n",
ARCSTATUS,boguscount);
BUGMSG(D_DURING,"\n");
-
+
SETMASK; /* put back interrupt mask */
-
}
-
/* A packet has arrived; grab it from the buffers and pass it to the generic
* arcnet_rx routing to deal with it.
- */
+ */
static void
arc90xx_rx(struct device *dev,int recbuf)
u_char *arcsoft;
short length,offset;
u_char daddr,saddr;
-
+
lp->stats.rx_packets++;
-
+
saddr=arcpacket->hardheader.source;
-
+
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
return;
}
/* Set source address to zero to mark it as old */
-
+
arcpacket->hardheader.source=0;
-
+
daddr=arcpacket->hardheader.destination;
-
+
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
{
offset=arcpacket->hardheader.offset2;
arcsoft=&arcpacket->raw[offset];
-
+
length=512-offset;
}
-
-
- arcnet_rx(lp, arcsoft, length, saddr, daddr);
+ arcnet_rx(lp, arcsoft, length, saddr, daddr);
BUGLVL(D_RX) arcnet_dump_packet(lp->adev,arcpacket->raw,length>240,"rx");
-
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)arcpacket->raw,0x42,512);
#endif
-
}
-
-
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnet_go_tx.
*/
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
union ArcPacket *arcpacket =
(union ArcPacket *)phys_to_virt(dev->mem_start+512*(lp->txbuf^1));
-
+
#ifdef SLOW_XMIT_COPY
char *iptr,*iend,*optr;
#endif
-
+
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
-
+
length+=hdrlen;
-
+
BUGMSG(D_TX,"arcnetAS_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
-
+
#ifndef SLOW_XMIT_COPY
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset_io(dev->mem_start+lp->txbuf*512,0x42,512);
#endif
-
+
arcpacket->hardheader.destination=daddr;
-
+
/* load packet into shared memory */
if (length<=MTU) /* Normal (256-byte) Packet */
arcpacket->hardheader.offset1=offset=offset?offset:256-length;
-
+
else if (length>=MinTU || offset) /* Extended (512-byte) Packet */
{
arcpacket->hardheader.offset1=0;
- arcpacket->hardheader.offset2=offset=offset?offset:512-length;
+ arcpacket->hardheader.offset2=offset=offset?offset:512-length;
}
else if (exceptA) /* RFC1201 Exception Packet */
{
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length-4;
-
+
/* exception-specific stuff - these four bytes
* make the packet long enough to fit in a 512-byte
* frame.
*/
-
+
arcpacket->raw[offset+0]=hdr[0];
arcpacket->raw[offset+1]=0xFF; /* FF flag */
arcpacket->raw[offset+2]=0xFF; /* FF padding */
{
/* RFC1051 - set 4 trailing bytes to 0 */
memset(&arcpacket->raw[508],0,4);
-
+
/* now round up to MinTU */
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-MinTU;
}
-
-
+
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
#else
memcpy((u_char*)arcpacket+offset+hdrlen, data,length-hdrlen);
#endif
-
+
BUGMSG(D_DURING,"transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
-
+
BUGLVL(D_TX) arcnet_dump_packet(dev,arcpacket->raw,length>MTU,"tx");
-
+
lp->lastload_dest=daddr;
lp->txready=lp->txbuf; /* packet is ready for sending */
}
if (device)
strcpy(dev->name,device);
else arcnet_makename(dev->name);
-
+
dev->base_addr=io;
-
+
dev->irq=irq;
if (dev->irq==2) dev->irq=9;
-
+
if (shmem)
{
dev->mem_start=shmem;
dev->rmem_start=thiscard.mem_start+512*0;
dev->rmem_end=thiscard.mem_start+512*2-1;
}
-
+
if (register_netdev(dev) != 0)
return -EIO;
arcnet_use_count(1);
void cleanup_module(void)
{
- struct device *dev=&thiscard;
- int ioaddr=dev->mem_start;
+ struct device *dev=&thiscard;
+ int ioaddr=dev->mem_start;
- if (dev->start) (*dev->stop)(dev);
+ if (dev->start) (*dev->stop)(dev);
- /* Flush TX and disable RX */
- if (ioaddr)
- {
- AINTMASK(0); /* disable IRQ's */
- ACOMMAND(NOTXcmd); /* stop transmit */
- ACOMMAND(NORXcmd); /* disable receive */
+ /* Flush TX and disable RX */
+ if (ioaddr)
+ {
+ AINTMASK(0); /* disable IRQ's */
+ ACOMMAND(NOTXcmd); /* stop transmit */
+ ACOMMAND(NORXcmd); /* disable receive */
#if defined(IO_MAPPED_BUFFERS) && !defined(COM20020)
- /* Set the thing back to MMAP mode, in case the old
- driver is loaded later */
- outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG);
+ /* Set the thing back to MMAP mode, in case the old
+ driver is loaded later */
+ outb( (inb(_CONFIG)&~IOMAPflag),_CONFIG);
#endif
- }
+ }
- if (dev->irq)
- {
- irq2dev_map[dev->irq] = NULL;
- free_irq(dev->irq,NULL);
- }
+ if (dev->irq)
+ {
+ irq2dev_map[dev->irq] = NULL;
+ free_irq(dev->irq,NULL);
+ }
- if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
- unregister_netdev(dev);
- kfree(dev->priv);
- dev->priv = NULL;
- arcnet_use_count(0);
+ if (dev->base_addr) release_region(dev->base_addr,ARCNET_TOTAL_SIZE);
+ unregister_netdev(dev);
+ kfree(dev->priv);
+ dev->priv = NULL;
+ arcnet_use_count(0);
}
+
#else
__initfunc(void com90xx_setup (char *str, int *ints))
MAX_ARCNET_DEVS);
return;
}
-
+
if (!ints[0] && (!str || !*str))
{
printk("com90xx: Disabled.\n");
}
dev=&arcnet_devs[arcnet_num_devs];
-
+
dev->dev_addr[3]=3;
dev->init=arc90xx_probe;
case 2: /* IRQ */
dev->irq=ints[2];
-
+
case 1: /* IO address */
dev->base_addr=ints[1];
}
dev->name = (char *)&arcnet_dev_names[arcnet_num_devs];
-
+
if (str)
strncpy(dev->name, str, 9);
/* 'options' is used to pass a transceiver override or full-duplex flag
e.g. "options=16" for FD, "options=32" for 100mbps-only. */
static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+
#ifdef MODULE
+
static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int debug = -1; /* The debug level */
-#endif
/* A list of all installed Speedo devices, for removing the driver module. */
static struct device *root_speedo_dev = NULL;
+#endif
+
int eepro100_init(struct device *dev)
{
int cards_found = 0;
extern inline int
lock_buffer (register struct ppp_buffer *buf)
{
- register int state;
+ register long state;
int flags;
/*
* Save the current state and if free then set it to the "busy" state
*/
if (ppp->flags & SC_LOG_RAWIN)
ppp_print_buffer ("receive buffer", data, count);
+
/*
* Collect the character and error condition for the character. Set the toss
* flag for the first character error.
ppp->toss = *flags;
++flags;
}
+
/*
* Set the flags for 8 data bits and no parity.
*
{
__u16 proto = PPP_PROTOCOL (data);
ppp_proto_type *proto_ptr;
+
/*
* Ignore empty frames
*/
int addr, ctrl, proto;
int new_count;
__u8 *new_data;
+
/*
* If there is a pending error from the receiver then log it and discard
* the damaged frame.
/*
- * drivers/pci/pci.c
+ * $Id: pci.c,v 1.44 1997/09/03 05:08:22 richard Exp $
*
* PCI services that are built on top of the BIOS32 service.
*
struct pci_bus pci_root;
struct pci_dev *pci_devices = 0;
-
/*
* The bridge_id field is an offset of an item into the array
* BRIDGE_MAPPING_TYPE. 0xff indicates that the device is not a PCI
DEVICE( VLSI, VLSI_82C597, "82C597-AFC2"),
DEVICE( VLSI, VLSI_VAS96011, "VAS96011 PowerPC"),
DEVICE( ADL, ADL_2301, "2301"),
+ DEVICE( NS, NS_87415, "87415"),
DEVICE( NS, NS_87410, "87410"),
DEVICE( TSENG, TSENG_W32P_2, "ET4000W32P"),
DEVICE( TSENG, TSENG_W32P_b, "ET4000W32P rev B"),
DEVICE( WEITEK, WEITEK_P9100, "P9100"),
BRIDGE( DEC, DEC_BRD, "DC21050", 0x00),
DEVICE( DEC, DEC_TULIP, "DC21040"),
- DEVICE( DEC, DEC_TGA, "DC21030"),
+ DEVICE( DEC, DEC_TGA, "TGA"),
DEVICE( DEC, DEC_TULIP_FAST, "DC21140"),
+ DEVICE( DEC, DEC_TGA2, "TGA2"),
DEVICE( DEC, DEC_FDDI, "DEFPA"),
DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"),
DEVICE( DEC, DEC_21142, "DC21142"),
DEVICE( OLICOM, OLICOM_OC2183, "OC-2183/2185"),
DEVICE( OLICOM, OLICOM_OC2326, "OC-2326"),
DEVICE( OLICOM, OLICOM_OC6151, "OC-6151/6152"),
+ DEVICE( SUN, SUN_EBUS, "EBUS"),
+ DEVICE( SUN, SUN_HAPPYMEAL, "Happy Meal"),
+ BRIDGE( SUN, SUN_PBM, "PCI Bus Module", 0x02),
DEVICE( CMD, CMD_640, "640 (buggy)"),
DEVICE( CMD, CMD_643, "643"),
DEVICE( CMD, CMD_646, "646"),
case PCI_VENDOR_ID_CONTAQ: return "Contaq";
case PCI_VENDOR_ID_FOREX: return "Forex";
case PCI_VENDOR_ID_OLICOM: return "Olicom";
+ case PCI_VENDOR_ID_SUN: return "Sun Microsystems";
case PCI_VENDOR_ID_CMD: return "CMD";
case PCI_VENDOR_ID_VISION: return "Vision";
case PCI_VENDOR_ID_BROOKTREE: return "Brooktree";
}
+const char *pcibios_strerror(int error)
+{
+ static char buf[32];
+
+ switch (error) {
+ case PCIBIOS_SUCCESSFUL:
+ case PCIBIOS_BAD_VENDOR_ID:
+ return "SUCCESSFUL";
+
+ case PCIBIOS_FUNC_NOT_SUPPORTED:
+ return "FUNC_NOT_SUPPORTED";
+
+ case PCIBIOS_DEVICE_NOT_FOUND:
+ return "DEVICE_NOT_FOUND";
+
+ case PCIBIOS_BAD_REGISTER_NUMBER:
+ return "BAD_REGISTER_NUMBER";
+
+ case PCIBIOS_SET_FAILED:
+ return "SET_FAILED";
+
+ case PCIBIOS_BUFFER_TOO_SMALL:
+ return "BUFFER_TOO_SMALL";
+
+ default:
+ sprintf (buf, "PCI ERROR 0x%x", error);
+ return buf;
+ }
+}
+
/*
* Turn on/off PCI bridge optimization. This should allow benchmarking.
if (len + 40 > size) {
return -1;
}
- len += sprintf(buf + len, "IRQ %d. ", dev->irq);
+ len += sprintf(buf + len, "IRQ %x. ", dev->irq);
}
if (dev->master) {
len += sprintf(buf + len, "Max Lat=%d.", max_lat);
}
- for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4) {
+ for (reg = 0; reg < 6; reg++) {
if (len + 40 > size) {
return -1;
}
- pcibios_read_config_dword(bus, devfn, reg, &l);
- base = l;
- if (!base) {
+ pcibios_read_config_dword(bus, devfn,
+ PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+ if (l == 0xffffffff)
+ base = 0;
+ else
+ base = l;
+ if (!base)
continue;
- }
if (base & PCI_BASE_ADDRESS_SPACE_IO) {
len += sprintf(buf + len,
- "\n I/O at 0x%lx.",
- base & PCI_BASE_ADDRESS_IO_MASK);
+ "\n I/O at 0x%lx [0x%lx].",
+ base & PCI_BASE_ADDRESS_IO_MASK,
+ dev->base_address[reg]);
} else {
const char *pref, *type = "unknown";
}
len += sprintf(buf + len,
"\n %srefetchable %s memory at "
- "0x%lx.", pref, type,
- base & PCI_BASE_ADDRESS_MEM_MASK);
+ "0x%lx [0x%lx].", pref, type,
+ base & PCI_BASE_ADDRESS_MEM_MASK,
+ dev->base_address[reg]);
}
}
void *mem;
#ifdef DEBUG
- printk("...pci_malloc(size=%ld,mem=%p)", size, *mem_startp);
+ printk("...pci_malloc(size=%ld,mem=%p)", size, (void *)*mem_startp);
#endif
mem = (void*) *mem_startp;
*mem_startp += (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
}
-__initfunc(static unsigned int scan_bus(struct pci_bus *bus, unsigned long *mem_startp))
+unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp)
{
unsigned int devfn, l, max;
- unsigned char cmd, tmp, hdr_type = 0;
+ unsigned char cmd, tmp, irq, hdr_type = 0;
struct pci_dev_info *info;
struct pci_dev *dev;
struct pci_bus *child;
+ int reg;
#ifdef DEBUG
- printk("...scan_bus(busno=%d,mem=%p)\n", bus->number, *mem_startp);
+ printk("...pci_scan_bus(busno=%d,mem=%p)\n", bus->number,
+ (void *)*mem_startp);
#endif
max = bus->secondary;
*/
info = pci_lookup_dev(dev->vendor, dev->device);
if (!info) {
- printk("Warning : Unknown PCI device (%x:%x). Please read include/linux/pci.h \n",
+ printk("PCI: Warning: Unknown PCI device (%x:%x). Please read include/linux/pci.h\n",
dev->vendor, dev->device);
} else {
/* Some BIOS' are lazy. Let's do their job: */
/* read irq level (may be changed during pcibios_fixup()): */
pcibios_read_config_byte(bus->number, devfn,
- PCI_INTERRUPT_LINE, &dev->irq);
+ PCI_INTERRUPT_LINE, &irq);
+ dev->irq = irq;
+
+ /* read base address registers, again pcibios_fixup() can
+ * tweak these
+ */
+ for (reg = 0; reg < 6; reg++) {
+ pcibios_read_config_dword(bus->number, devfn,
+ PCI_BASE_ADDRESS_0 + (reg << 2), &l);
+ if (l == 0xffffffff)
+ dev->base_address[reg] = 0;
+ else
+ dev->base_address[reg] = l;
+ }
/* check to see if this device is a PCI-PCI bridge: */
pcibios_read_config_dword(bus->number, devfn,
child->secondary = (buses >> 8) & 0xFF;
child->subordinate = (buses >> 16) & 0xFF;
child->number = child->secondary;
- max = scan_bus(child, mem_startp);
+ max = pci_scan_bus(child, mem_startp);
}
else
{
/*
* Now we can scan all subordinate buses:
*/
- max = scan_bus(child, mem_startp);
+ max = pci_scan_bus(child, mem_startp);
/*
* Set the subordinate bus number to its real
* value:
mem_start = pcibios_init(mem_start, mem_end);
if (!pcibios_present()) {
- printk("pci_init: no PCI BIOS detected\n");
+ printk("PCI: No PCI bus detected\n");
return mem_start;
}
printk("Probing PCI hardware.\n");
memset(&pci_root, 0, sizeof(pci_root));
- pci_root.subordinate = scan_bus(&pci_root, &mem_start);
+ pci_root.subordinate = pci_scan_bus(&pci_root, &mem_start);
/* give BIOS a chance to apply platform specific fixes: */
mem_start = pcibios_fixup(mem_start, mem_end);
-/* $Id: pcikbd.c,v 1.3 1997/09/04 05:50:35 ecd Exp $
+/* $Id: pcikbd.c,v 1.4 1997/09/05 22:59:53 ecd Exp $
* pcikbd.c: Ultra/AX PC keyboard support.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
- int node, index, irq;
+ struct linux_ebus_child *child;
for_all_ebusdev(edev, ebus) {
if(!strcmp(edev->prom_name, "8042")) {
- node = prom_getchild(edev->prom_node);
- node = prom_searchsiblings(node, "kb_ps2");
- if (node == kbd_node)
- goto found;
+ for_each_edevchild(edev, child) {
+ if (!strcmp(child->prom_name, "kb_ps2"))
+ goto found;
+ }
}
}
- printk("pcikbd_init: no 8042 found\n");
+ printk("pcikbd_probe: no 8042 found\n");
return -ENODEV;
found:
- if (prom_getproperty(node, "reg", (char *)&index, sizeof(index)) !=
- sizeof(index)) {
- printk("8042: can't get property '%s' from '%s'\n",
- "reg", "kb_ps2");
- return -ENODEV;
- }
-
- if (prom_getproperty(node, "interrupts", (char *)&irq, sizeof(irq)) !=
- sizeof(irq)) {
- printk("8042: can't get property '%s' from '%s'\n",
- "interrupts", "kb_ps2");
- return -ENODEV;
- }
-
- pcikbd_iobase = edev->base_address[index];
+ pcikbd_iobase = child->base_address[0];
if (check_region(pcikbd_iobase, sizeof(unsigned long))) {
printk("8042: can't get region %lx, %d\n",
pcikbd_iobase, (int)sizeof(unsigned long));
return -ENODEV;
}
-
request_region(pcikbd_iobase, sizeof(unsigned long), "8042 controller");
- printk("8042(kbd): iobase[%016lx] irq[%x]\n", pcikbd_iobase, irq);
- pcikbd_irq = irq;
+ pcikbd_irq = child->irqs[0];
if (request_irq(pcikbd_irq, &pcikbd_interrupt,
SA_SHIRQ, "keyboard", NULL)) {
printk("8042: cannot register IRQ %x\n", pcikbd_irq);
return -ENODEV;
}
+ printk("8042(kbd): iobase[%016lx] irq[%x]\n", pcikbd_iobase, pcikbd_irq);
+
/* pcikbd_init(); */
kbd_read_mask = KBD_STAT_OBF;
return 0;
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
- int node, index, irq;
+ struct linux_ebus_child *child;
for_all_ebusdev(edev, ebus) {
if(!strcmp(edev->prom_name, "8042")) {
- node = prom_getchild(edev->prom_node);
- node = prom_searchsiblings(node, "kdmouse");
- if (node == ms_node)
- goto found;
+ for_each_edevchild(edev, child) {
+ if (!strcmp(child->prom_name, "kdmouse"))
+ goto found;
+ }
}
}
printk("pcimouse_init: no 8042 found\n");
return -ENODEV;
found:
- if (prom_getproperty(node, "reg", (char *)&index, sizeof(index)) !=
- sizeof(index)) {
- printk("8042: can't get property '%s' from '%s'\n",
- "reg", "kdmouse");
- return -ENODEV;
- }
-
- if (prom_getproperty(node, "interrupts", (char *)&irq, sizeof(irq)) !=
- sizeof(irq)) {
- printk("8042: can't get property '%s' from '%s'\n",
- "interrupts", "kdmouse");
- return -ENODEV;
- }
-
- pcimouse_iobase = edev->base_address[index];
-
+ pcimouse_iobase = child->base_address[0];
/*
* Just in case the iobases for kbd/mouse ever differ...
*/
request_region(pcimouse_iobase, sizeof(unsigned long),
"8042 controller");
- printk("8042(mouse): iobase[%016lx] irq[%x]\n", pcimouse_iobase, irq);
- pcimouse_irq = irq;
-
+ pcimouse_irq = child->irqs[0];
if (request_irq(pcimouse_irq, &pcimouse_interrupt,
SA_SHIRQ, "mouse", NULL)) {
printk("8042: Cannot register IRQ %x\n", pcimouse_irq);
return -ENODEV;
}
+ printk("8042(mouse): iobase[%016lx] irq[%x]\n",
+ pcimouse_iobase, pcimouse_irq);
+
printk("8042: PS/2 auxiliary pointing device detected.\n");
aux_present = 1;
kbd_read_mask = AUX_STAT_OBF;
poll_aux_status();
outb(KBD_CCMD_WRITE_MODE, pcimouse_iobase + KBD_CNTL_REG);
poll_aux_status();
- outb(AUX_INTS_OFF, KBD_DATA_REG);
+ outb(AUX_INTS_OFF, pcimouse_iobase + KBD_DATA_REG);
poll_aux_status();
aux_end_atomic();
* 3) Add tagged queueing.
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/idprom.h>
#define DEBUG_ESP
*/
__initfunc(int esp_detect(Scsi_Host_Template *tpnt))
{
+#ifdef __sparc_v9__
+ struct devid_cookie dcookie;
+#endif
struct Sparc_ESP *esp, *elink;
struct Scsi_Host *esp_host;
struct linux_sbus *sbus;
int esp_node, i;
espchain = 0;
- if(!SBus_chain)
+ if(!SBus_chain) {
+#ifdef CONFIG_PCI
+ return 0;
+#else
panic("No SBUS in esp_detect()");
+#endif
+ }
for_each_sbus(sbus) {
for_each_sbusdev(sbdev_iter, sbus) {
struct linux_sbus_device *espdma = 0;
esp->edev->reg_addrs[0].reg_size;
esp->ehost->irq = esp->irq = esp->edev->irqs[0].pri;
+#ifndef __sparc_v9__
/* Allocate the irq only if necessary */
for_each_esp(elink) {
if((elink != esp) && (esp->irq == elink->irq)) {
panic("Cannot acquire ESP irq line");
esp_irq_acquired:
printk("esp%d: IRQ %d ", esp->esp_id, esp->ehost->irq);
+#else
+ /* On Ultra we must always call request_irq for each
+ * esp, so that imap registers get setup etc.
+ */
+ dcookie.real_dev_id = esp;
+ dcookie.imap = dcookie.iclr = 0;
+ dcookie.pil = -1;
+ dcookie.bus_cookie = sbus;
+ if(request_irq(esp->ehost->irq, esp_intr,
+ (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
+ "Sparc ESP SCSI", &dcookie))
+ panic("Cannot acquire ESP irq line");
+ esp->ehost->irq = esp->irq = dcookie.ret_ino;
+ printk("esp%d: INO[%x] IRQ %d ",
+ esp->esp_id, esp->ehost->irq, dcookie.ret_pil);
+#endif
/* Figure out our scsi ID on the bus */
esp->scsi_id = prom_getintdefault(esp->prom_node,
/* Please go to msgout phase, please please please... */
ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
esp->esp_id));
-#ifdef __SMP__
- ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id,
- local_irq_count[0], local_irq_count[1],
- local_irq_count[2], local_irq_count[3]));
-#endif
return esp_do_phase_determine(esp, eregs, dregs);
}
ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
esp->esp_id,
SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
-#ifdef __SMP__
- ESPLOG(("esp%d: local_irq_count[%x:%x:%x:%x]\n", esp->esp_id,
- local_irq_count[0], local_irq_count[1],
- local_irq_count[2], local_irq_count[3]));
-#endif
bytes_sent = 0;
}
return;
}
+#ifndef __sparc_v9__
+
#ifndef __SMP__
static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
{
repeat:
again = 0;
for_each_esp(esp) {
- /* XXX Ultra: This is gross, what we really need
- * XXX is a sbusirq_to_sparc_pil() function, call
- * XXX that and stick the result in the esp soft
- * XXX state structure. -DaveM
- */
-#ifndef __sparc_v9__
if((esp->irq & 0xf) == irq) {
-#endif
if(DMA_IRQ_P(esp->dregs)) {
again = 1;
DMA_INTSON(esp->dregs);
}
-#ifndef __sparc_v9__
}
-#endif
}
if(again)
goto repeat;
}
#else
-
-/* XXX Gross hack for sun4u SMP, fix it right later... -DaveM */
-#ifdef __sparc_v9__
-extern unsigned char ino_to_pil[];
-#define INO_TO_PIL(esp) (ino_to_pil[(esp)->irq])
-#else
-#define INO_TO_PIL(esp) ((esp)->irq & 0xf)
-#endif
-
/* For SMP we only service one ESP on the list list at our IRQ level! */
static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
{
/* Handle all ESP interrupts showing at this IRQ level. */
for_each_esp(esp) {
- if(INO_TO_PIL(esp) == irq) {
+ if(((esp)->irq & 0xf) == irq) {
if(DMA_IRQ_P(esp->dregs)) {
DMA_INTSOFF(esp->dregs);
}
}
#endif
+
+#else /* __sparc_v9__ */
+
+static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+ struct Sparc_ESP *esp = dev_id;
+
+ if(DMA_IRQ_P(esp->dregs)) {
+ DMA_INTSOFF(esp->dregs);
+
+ ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
+ esp_handle(esp);
+ ESPIRQ((")"));
+
+ DMA_INTSON(esp->dregs);
+ }
+}
+
+#endif
#include <linux/module.h>
#include "scsi_module.c"
+
+MODULE_PARM(ncr_irq, "i");
+MODULE_PARM(ncr_dma, "i");
+MODULE_PARM(ncr_addr, "i");
+MODULE_PARM(ncr_5380, "i");
+MODULE_PARM(ncr_53c400, "i");
+
#endif
* Paul Mackerras, August 1996.
* Copyright (C) 1996 Paul Mackerras.
*/
-
#include <linux/config.h>
-
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <asm/oplib.h>
#include <asm/vaddrs.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <linux/module.h>
unsigned short csum = 0;
unsigned short param[6];
unsigned long flags;
-#ifndef MODULE
+#if !defined(MODULE) && !defined(__sparc_v9__)
unsigned long dvma_addr;
#endif
int i, timeout;
}
/* Load the firmware. */
-#ifndef MODULE
- /* XXX THIS SHIT DOES NOT WORK ON ULTRA... FIXME -DaveM */
+#if !defined(MODULE) && !defined(__sparc_v9__)
dvma_addr = (unsigned long) mmu_lockarea((char *)&risc_code01[0],
(sizeof(u_short) * risc_code_length01));
param[0] = MBOX_LOAD_RAM;
restore_flags(flags);
return 1;
}
- /* XXX THIS SHIT DOES NOT WORK ON ULTRA... FIXME -DaveM */
mmu_unlockarea((char *)dvma_addr, (sizeof(u_short) * risc_code_length01));
#else
+ /* We need to do it this slow way always on Ultra. */
for(i = 0; i < risc_code_length01; i++) {
param[0] = MBOX_WRITE_RAM_WORD;
param[1] = risc_code_addr01 + i;
/* Detect all PTI Qlogic ISP's in the machine. */
__initfunc(int qlogicpti_detect(Scsi_Host_Template *tpnt))
{
+#ifdef __sparc_v9__
+ struct devid_cookie dcookie;
+#endif
struct qlogicpti *qpti, *qlink;
struct Scsi_Host *qpti_host;
struct linux_sbus *sbus;
/* Map this one read only. */
qpti->sreg = sreg = (volatile unsigned char *)
sparc_alloc_io((qpti->qdev->reg_addrs[0].phys_addr +
- (16 * PAGE_SIZE)), 0,
+ (16 * 4096)), 0,
sizeof(unsigned char),
"PTI Qlogic/ISP Status Reg",
qpti->qdev->reg_addrs[0].which_io, 1);
qpti_host->irq = qpti->irq = qpti->qdev->irqs[0].pri;
+#ifndef __sparc_v9__
/* Allocate the irq only if necessary. */
for_each_qlogicpti(qlink) {
if((qlink != qpti) && (qpti->irq == qlink->irq)) {
}
qpti_irq_acquired:
printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->qhost->irq);
+#else
+ /* On Ultra we must always call request_irq for each
+ * qpti, so that imap registers get setup etc.
+ */
+ dcookie.real_dev_id = qpti;
+ dcookie.imap = dcookie.iclr = 0;
+ dcookie.pil = -1;
+ dcookie.bus_cookie = sbus;
+ if(request_irq(qpti->qhost->irq, qlogicpti_intr_handler,
+ (SA_SHIRQ | SA_SBUS | SA_DCOOKIE),
+ "PTI Qlogic/ISP SCSI", &dcookie)) {
+ printk("Cannot acquire PTI Qlogic/ISP irq line\n");
+ /* XXX Unmap regs, unregister scsi host, free things. */
+ continue;
+ }
+ qpti->qhost->irq = qpti->irq = dcookie.ret_ino;
+ printk("qpti%d: INO[%x] IRQ %d ",
+ qpti->qpti_id, qpti->qhost->irq, dcookie.ret_pil);
+#endif
/* Figure out our scsi ID on the bus */
qpti->scsi_id = prom_getintdefault(qpti->prom_node,
memset(cmd, 0, sizeof(struct Command_Entry));
cmd->hdr.entry_cnt = 1;
cmd->hdr.entry_type = ENTRY_COMMAND;
- cmd->handle = (u_int) ((unsigned long)Cmnd); /* magic mushroom */
+#ifdef __sparc_v9__
+ cmd->handle = (u_int) (((unsigned long)Cmnd) - PAGE_OFFSET); /* magic mushroom */
+#else
+ cmd->handle = (u_int) ((unsigned long)Cmnd); /* magic mushroom */
+#endif
cmd->target_id = Cmnd->target;
cmd->target_lun = Cmnd->lun;
cmd->cdb_length = Cmnd->cmd_len;
return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
}
+#ifndef __sparc_v9__
+
static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
{
static int running = 0;
running--;
}
+#else /* __sparc_v9__ */
+
+static void qlogicpti_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct qlogicpti *qpti = dev_id;
+ Scsi_Cmnd *Cmnd;
+ struct Status_Entry *sts;
+ u_int in_ptr, out_ptr;
+
+ if(qpti->qregs->sbus_stat & SBUS_STAT_RINT) {
+ struct qlogicpti_regs *qregs = qpti->qregs;
+
+ in_ptr = qregs->mbox5;
+ qregs->hcctrl = HCCTRL_CRIRQ;
+ if(qregs->sbus_semaphore & SBUS_SEMAPHORE_LCK) {
+ switch(qregs->mbox0) {
+ case ASYNC_SCSI_BUS_RESET:
+ case EXECUTION_TIMEOUT_RESET:
+ qpti->send_marker = 1;
+ break;
+ case INVALID_COMMAND:
+ case HOST_INTERFACE_ERROR:
+ case COMMAND_ERROR:
+ case COMMAND_PARAM_ERROR:
+ break;
+ }
+ qregs->sbus_semaphore = 0;
+ }
+
+ /* This looks like a network driver! */
+ out_ptr = qpti->res_out_ptr;
+ while(out_ptr != in_ptr) {
+ sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
+ out_ptr = NEXT_RES_PTR(out_ptr);
+ Cmnd = (Scsi_Cmnd *) (((unsigned long)sts->handle)+PAGE_OFFSET);
+
+ if(sts->completion_status == CS_RESET_OCCURRED ||
+ sts->completion_status == CS_ABORTED ||
+ (sts->status_flags & STF_BUS_RESET))
+ qpti->send_marker = 1;
+
+ if(sts->state_flags & SF_GOT_SENSE)
+ memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+ sizeof(Cmnd->sense_buffer));
+
+ if(sts->hdr.entry_type == ENTRY_STATUS)
+ Cmnd->result = qlogicpti_return_status(sts);
+ else
+ Cmnd->result = DID_ERROR << 16;
+
+ if(Cmnd->use_sg)
+ mmu_release_scsi_sgl((struct mmu_sglist *)
+ Cmnd->buffer,
+ Cmnd->use_sg - 1,
+ qpti->qdev->my_bus);
+ else
+ mmu_release_scsi_one((__u32)((unsigned long)Cmnd->SCp.ptr),
+ Cmnd->request_bufflen,
+ qpti->qdev->my_bus);
+
+ qpti->cmd_count[Cmnd->target]--;
+ qregs->mbox5 = out_ptr;
+ Cmnd->scsi_done(Cmnd);
+ }
+ qpti->res_out_ptr = out_ptr;
+ }
+}
+
+#endif
+
int qlogicpti_abort(Scsi_Cmnd *Cmnd)
{
u_short param[6];
#endif
#define MAX_SCSI_DEVICE_CODE 10
+extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
extern void scsi_make_blocked_list(void);
extern volatile int in_scan_scsis;
EXPORT_SYMBOL(scsi_hosts);
EXPORT_SYMBOL(scsi_devicelist);
EXPORT_SYMBOL(scsi_devices);
+EXPORT_SYMBOL(scsi_device_types);
+
#endif /* CONFIG_MODULES */
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/wait.h>
-
-#define kver(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-
-#if LINUX_VERSION_CODE < kver(2,1,0)
-
-/* Segmentation stuff for pre-2.1 kernels */
-#include <asm/segment.h>
-
-static inline int copy_to_user(void *dst, void *src, unsigned long len)
-{
- int rv = verify_area(VERIFY_WRITE, dst, len);
- if ( rv )
- return -1;
- memcpy_tofs(dst,src,len);
- return 0;
-}
-
-static inline int copy_from_user(void *dst, void *src, unsigned long len)
-{
- int rv = verify_area(VERIFY_READ, src, len);
- if ( rv )
- return -1;
- memcpy_fromfs(dst,src,len);
- return 0;
-}
-
-#else
-
-/* Segmentation stuff for post-2.1 kernels */
#include <asm/uaccess.h>
-#define register_symtab(x) ((void)0)
-
-#endif
#ifdef DEBUG
#define DPRINTK(D) (printk D)
#define AUTOFS_SUPER_MAGIC 0x0187
-#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* Time before asking the daemon again */
+/*
+ * If the daemon returns a negative response (AUTOFS_IOC_FAIL) then the
+ * kernel will keep the negative response cached for up to the time given
+ * here, although the time can be shorter if the kernel throws the dcache
+ * entry away. This probably should be settable from user space.
+ */
+#define AUTOFS_NEGATIVE_TIMEOUT (60*HZ) /* 1 minute */
-/* Structures associated with the root directory hash */
+/* Structures associated with the root directory hash table */
#define AUTOFS_HASH_SIZE 67
u32 symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
};
-/* autofs_oz_mode(): do we see the man behind the curtain? */
+/* autofs_oz_mode(): do we see the man behind the curtain? (The
+ processes which do manipulations for us in user space sees the raw
+ filesystem without "magic".) */
+
static inline int autofs_oz_mode(struct autofs_sb_info *sbi) {
return sbi->catatonic || current->pgrp == sbi->oz_pgrp;
}
-/* Debug the mysteriously disappearing wait list */
-
-#ifdef DEBUG_WAITLIST
-#define CHECK_WAITLIST(S,O) autofs_check_waitlist_integrity(S,O)
-void autofs_check_waitlist_integrity(struct autofs_sb_info *,char *);
-#else
-#define CHECK_WAITLIST(S,O)
-#endif
-
/* Hash operations */
void autofs_initialize_hash(struct autofs_dirhash *);
#ifdef DEBUG
void autofs_say(const char *name, int len);
#else
-#define autofs_say(n,l)
+#define autofs_say(n,l) ((void)0)
#endif
* ------------------------------------------------------------------------- */
#include <linux/module.h>
-#include "autofs_i.h"
-
-#if LINUX_VERSION_CODE < kver(2,1,36)
-#define __initfunc(X) X
-#else
#include <linux/init.h>
-#endif
+#include "autofs_i.h"
static struct file_system_type autofs_fs_type = {
"autofs",
- 0 /* FS_NO_DCACHE doesn't work correctly */,
+ 0,
autofs_read_super,
NULL
};
#ifdef MODULE
int init_module(void)
{
- int status;
-
- if ((status = register_filesystem(&autofs_fs_type)) == 0)
- register_symtab(0);
- return status;
+ return register_filesystem(&autofs_fs_type);
}
void cleanup_module(void)
int rv;
unsigned long ntimeout;
-#if LINUX_VERSION_CODE < kver(2,1,0)
- if ( (rv = verify_area(VERIFY_WRITE, p, sizeof(unsigned long))) )
- return rv;
- ntimeout = get_user(p);
- put_user(sbi->exp_timeout/HZ, p);
-#else
if ( (rv = get_user(ntimeout, p)) ||
(rv = put_user(sbi->exp_timeout/HZ, p)) )
return rv;
-#endif
if ( ntimeout > ULONG_MAX/HZ )
sbi->exp_timeout = 0;
/* Return protocol version */
static inline int autofs_get_protover(int *p)
{
-#if LINUX_VERSION_CODE < kver(2,1,0)
- int rv;
- if ( (rv = verify_area(VERIFY_WRITE, p, sizeof(int))) )
- return rv;
- put_user(AUTOFS_PROTO_VERSION, p);
- return 0;
-#else
return put_user(AUTOFS_PROTO_VERSION, p);
-#endif
}
/* Perform an expiry operation */
static int autofs_write(struct file *file, const void *addr, int bytes)
{
- unsigned short fs;
+ unsigned long fs;
unsigned long old_signal;
const char *data = (const char *)addr;
int written = 0;
struct dentry * dentry = NULL;
struct inode * inode = NULL;
struct file file;
- unsigned short fs;
+ unsigned long fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
unsigned long dump_start, dump_size;
struct elfhdr interp_elf_ex;
struct file * file;
struct exec interp_ex;
- struct dentry *interpreter_dentry;
- unsigned long load_addr;
+ struct dentry *interpreter_dentry = NULL; /* to shut gcc up */
+ unsigned long load_addr, load_bias;
int load_addr_set = 0;
unsigned int interpreter_type = INTERPRETER_NONE;
unsigned char ibcs2_interpreter;
int i;
- int old_fs;
- int error;
+ unsigned long old_fs;
+ unsigned long error;
struct elf_phdr * elf_ppnt, *elf_phdata;
int elf_exec_fileno;
unsigned long elf_bss, k, elf_brk;
if (retval >= 0) {
old_fs = get_fs(); /* This could probably be optimized */
set_fs(get_ds());
- interpreter_dentry = open_namei(elf_interpreter, 0, 0);
+#ifdef __sparc__
+ if (ibcs2_interpreter) {
+ unsigned long old_pers = current->personality;
+
+ current->personality = PER_SVR4;
+ interpreter_dentry = open_namei(elf_interpreter, 0, 0);
+ current->personality = old_pers;
+ } else
+#endif
+ interpreter_dentry = open_namei(elf_interpreter, 0, 0);
set_fs(old_fs);
if (IS_ERR(interpreter_dentry))
retval = PTR_ERR(interpreter_dentry);
bprm->p = setup_arg_pages(bprm->p, bprm);
current->mm->start_stack = bprm->p;
+ /* Try and get dynamic programs out of the way of the default mmap
+ base, as well as whatever program they might try to exec. This
+ is because the brk will follow the loader, and is not movable. */
+
+ load_bias = (elf_ex.e_type == ET_DYN ? ELF_ET_DYN_BASE : 0);
+
/* Now we do a little grungy work by mmaping the ELF image into
the correct location in memory. At this point, we assume that
the image should be loaded at fixed address, not at a variable
set_fs(get_ds());
for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
if (elf_ppnt->p_type == PT_LOAD) {
- int elf_prot = 0;
+ int elf_prot = 0, elf_flags;
+ unsigned long vaddr = 0;
+
if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
+ elf_flags = MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE;
+
+ if (elf_ex.e_type == ET_EXEC || load_addr_set) {
+ vaddr = elf_ppnt->p_vaddr;
+ elf_flags |= MAP_FIXED;
+ }
+
error = do_mmap(file,
- ELF_PAGESTART(elf_ppnt->p_vaddr),
+ ELF_PAGESTART(load_bias + vaddr),
(elf_ppnt->p_filesz +
ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot,
- (MAP_FIXED | MAP_PRIVATE |
- MAP_DENYWRITE | MAP_EXECUTABLE),
+ elf_prot, elf_flags,
(elf_ppnt->p_offset -
ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
#ifdef LOW_ELF_STACK
- if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
- elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr);
+ if (error < elf_stack)
+ elf_stack = error-1;
#endif
if (!load_addr_set) {
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- load_addr_set = 1;
+ load_addr_set = 1;
+ load_addr = (elf_ppnt->p_vaddr -
+ elf_ppnt->p_offset);
+ if (elf_ex.e_type == ET_DYN) {
+ load_bias = error;
+ load_addr += error;
+ }
}
k = elf_ppnt->p_vaddr;
if (k < start_code) start_code = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
if (k > elf_bss) elf_bss = k;
-#if 1
if ((elf_ppnt->p_flags & PF_X) && end_code < k)
-#else
- if ( !(elf_ppnt->p_flags & PF_W) && end_code < k)
-#endif
end_code = k;
if (end_data < k) end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
}
set_fs(old_fs);
+ elf_entry += load_bias;
+ elf_bss += load_bias;
+ elf_brk += load_bias;
+ start_code += load_bias;
+ end_code += load_bias;
+ end_data += load_bias;
+
if (elf_interpreter) {
if (interpreter_type & 1)
elf_entry = load_aout_interp(&interp_ex,
current->executable = dget(bprm->dentry);
#endif
#ifdef LOW_ELF_STACK
- current->start_stack = bprm->p = elf_stack - 4;
+ current->start_stack = bprm->p = elf_stack;
#endif
current->suid = current->euid = current->fsuid = bprm->e_uid;
current->sgid = current->egid = current->fsgid = bprm->e_gid;
struct file file;
struct dentry *dentry;
struct inode *inode;
- unsigned short fs;
+ unsigned long fs;
char corefile[6+sizeof(current->comm)];
int segs;
int i;
*/
void d_move(struct dentry * dentry, struct dentry * target)
{
- struct list_head * oldhead;
-
if (!dentry->d_inode)
printk("VFS: moving negative dcache entry\n");
} while (i);
}
-/*
- * Check whether we can mount.
- */
-int fs_may_mount(kdev_t dev)
-{
- return 1;
-}
-
-/*
- * Check whether we can unmount.
- */
-int fs_may_umount(struct super_block *sb, struct dentry * root)
-{
- shrink_dcache();
- return root->d_count == 1;
-}
-
/* This belongs in file_table.c, not here... */
int fs_may_remount_ro(struct super_block *sb)
{
nfs_delete_inode(struct inode * inode)
{
dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+ clear_inode(inode);
}
void
-/* $Id: openpromfs.c,v 1.18 1997/07/17 02:24:01 davem Exp $
+/* $Id: openpromfs.c,v 1.21 1997/08/19 02:05:48 davem Exp $
* openpromfs.c: /proc/openprom handling routines
*
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
#ifdef __powerpc__
static struct proc_dir_entry proc_root_ppc_htab = {
PROC_PPC_HTAB, 8, "ppc_htab",
- S_IFREG | S_IRUGO, 1, 0, 0,
- 0, &proc_ppc_htab_inode_operations
+ S_IFREG | S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 1, 0, 0,
+ 0, &proc_ppc_htab_inode_operations,
+ NULL, NULL, /* get_info, fill_inode */
+ NULL, /* next */
+ NULL, NULL /* parent, subdir */
+
};
#endif
return retval;
}
+/*
+ * Check whether we can mount the specified device.
+ */
+int fs_may_mount(kdev_t dev)
+{
+ struct super_block * sb = get_super(dev);
+ int busy;
+
+ busy = sb && sb->s_root &&
+ (sb->s_root->d_count != 1 || sb->s_root->d_covers != sb->s_root);
+ return !busy;
+}
+
/*
* do_mount() does the actual mounting after sys_mount has done the ugly
* parameter parsing. When enough time has gone by, and everything uses the
struct vfsmount *vfsmnt;
int error;
+ error = -EACCES;
if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
- return -EACCES;
+ goto out;
/*flags |= MS_RDONLY;*/
dir_d = namei(dir_name);
error = PTR_ERR(dir_d);
if (IS_ERR(dir_d))
- return error;
+ goto out;
- if (dir_d->d_covers != dir_d) {
- dput(dir_d);
- return -EBUSY;
- }
- if (!S_ISDIR(dir_d->d_inode->i_mode)) {
- dput(dir_d);
- return -ENOTDIR;
- }
- if (!fs_may_mount(dev)) {
- dput(dir_d);
- return -EBUSY;
- }
- sb = read_super(dev,type,flags,data,0);
- if (!sb) {
- dput(dir_d);
- return -EINVAL;
- }
- if (sb->s_root->d_covers != sb->s_root) {
- dput(dir_d);
- return -EBUSY;
+ error = -ENOTDIR;
+ if (!S_ISDIR(dir_d->d_inode->i_mode))
+ goto dput_and_out;
+
+ error = -EBUSY;
+ if (dir_d->d_covers != dir_d)
+ goto dput_and_out;
+
+ /*
+ * Check whether to read the super block
+ */
+ sb = get_super(dev);
+ if (!sb || !sb->s_root) {
+ error = -EINVAL;
+ sb = read_super(dev,type,flags,data,0);
+ if (!sb)
+ goto dput_and_out;
}
+
+ /*
+ * We may have slept while reading the super block,
+ * so we check afterwards whether it's safe to mount.
+ */
+ error = -EBUSY;
+ if (!fs_may_mount(dev))
+ goto dput_and_out;
+
+ error = -ENOMEM;
vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
if (vfsmnt) {
vfsmnt->mnt_sb = sb;
vfsmnt->mnt_flags = flags;
+ d_mount(dir_d, sb->s_root);
+ return 0; /* we don't dput(dir) - see umount */
}
- d_mount(dir_d, sb->s_root);
- return 0; /* we don't dput(dir) - see umount */
+
+dput_and_out:
+ dput(dir_d);
+out:
+ return error;
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 8192
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
/* $0 is set by ld.so to a pointer to a function which might be
registered using atexit. This provides a mean for the dynamic
linker to call DT_FINI functions for shared libraries that have
#define N_FDC 2
#define N_DRIVE 8
+#define FLOPPY_MOTOR_MASK 0xf0
+
/*
* Most Alphas have no problems with floppy DMA crossing 64k borders. Sigh...
*/
#define flush_cache_range(mm, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
+#define flush_icache_range(start, end) do { } while (0)
/*
* Force a context reload. This is needed when we
* performed or not. If get_fs() == USER_DS, checking is performed, with
* get_fs() == KERNEL_DS, checking is bypassed.
*
+ * Or at least it did once upon a time. Nowadays it is a mask that
+ * defines which bits of the address space are off limits. This is a
+ * wee bit faster than the above.
+ *
* For historical reasons, these macros are grossly misnamed.
*/
#define VERIFY_WRITE 1
#define get_fs() (current->tss.fs)
-#define set_fs(x) (current->tss.fs = (x))
#define get_ds() (KERNEL_DS)
+/* Our scheme relies on all bits being preserved. Trap those evil
+ Intellists in their plot to use unsigned short. */
+
+extern unsigned long __bad_fs_size(void);
+
+#define set_fs(x) (current->tss.fs = \
+ sizeof(x) == sizeof(unsigned long) ? (x) \
+ : __bad_fs_size())
+
/*
* Is a address valid? This does a straighforward calculation rather
* than tests.
#define CONFIG_BUGi386
-static void no_halt(char *s, int *ints)
+__initfunc(static void no_halt(char *s, int *ints))
{
hlt_works_ok = 0;
}
-static void no_387(char *s, int *ints)
+__initfunc(static void no_387(char *s, int *ints))
{
hard_math = 0;
__asm__("movl %%cr0,%%eax\n\t"
"movl %%eax,%%cr0\n\t" : : : "ax");
}
-static char fpu_error = 0;
+static char __initdata fpu_error = 0;
-static void copro_timeout(void)
+__initfunc(static void copro_timeout(void))
{
fpu_error = 1;
timer_table[COPRO_TIMER].expires = jiffies+100;
outb_p(0,0xf0);
}
-static void check_fpu(void)
+__initfunc(static void check_fpu(void))
{
static double x = 4195835.0;
static double y = 3145727.0;
printk("Hmm, FDIV bug i%c86 system\n", '0'+x86);
}
-static void check_hlt(void)
+__initfunc(static void check_hlt(void))
{
printk(KERN_INFO "Checking 'hlt' instruction... ");
if (!hlt_works_ok) {
printk("Ok.\n");
}
-static void check_tlb(void)
+__initfunc(static void check_tlb(void))
{
#ifndef CONFIG_M386
/*
#endif
}
-static void check_bugs(void)
+__initfunc(static void check_bugs(void))
{
check_tlb();
check_fpu();
#define ELF_DATA ELFDATA2LSB;
#define ELF_ARCH EM_386
- /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
- starts %edx contains a pointer to a function which might be
- registered using `atexit'. This provides a mean for the
- dynamic linker to call DT_FINI functions for shared libraries
- that have been loaded before the code runs.
+/* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program starts %edx
+ contains a pointer to a function which might be registered using `atexit'.
+ This provides a mean for the dynamic linker to call DT_FINI functions for
+ shared libraries that have been loaded before the code runs.
- A value of 0 tells we have no such handler. */
+ A value of 0 tells we have no such handler. */
#define ELF_PLAT_INIT(_r) _r->edx = 0
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
/* Wow, the "main" arch needs arch dependent functions too.. :) */
/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
#define N_FDC 2
#define N_DRIVE 8
+#define FLOPPY_MOTOR_MASK 0xf0
+
/*
* The DMA channel used by the floppy controller cannot access data at
* addresses >= 16MB
#define flush_cache_range(mm, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr) do { } while (0)
#define flush_page_to_ram(page) do { } while (0)
+#define flush_icache_range(start, end) do { } while (0)
/*
* TLB flushing:
* For historical reasons, these macros are grossly misnamed.
*/
+extern unsigned long __bad_fs_size(void);
+
#define get_fs() (current->tss.segment)
-#define set_fs(x) (current->tss.segment = (x))
#define get_ds() (KERNEL_DS)
+/* Some architectures -- Alpha for one -- use "segment" schemes that
+ require all bits to be preserved, thus the i386 traditional `ushort'
+ doesn't work. To head off problems early, force the Intel folks
+ to do it Right as well. */
+
+#define set_fs(x) (current->tss.segment = \
+ sizeof(x) == sizeof(unsigned long) ? (x) \
+ : __bad_fs_size())
+
/*
* Address Ok:
*
#define N_FDC 1 /* do you *really* want a second controller? */
#define N_DRIVE 8
+#define FLOPPY_MOTOR_MASK 0xf0
+
/*
* The DMA channel used by the floppy controller cannot access data at
* addresses >= 16MB
if (IS_ERR (base)) return base;
- return lookup_dentry (name, base, follow_link);
+ base = lookup_dentry (name, base, follow_link);
+
+ if (IS_ERR (base)) return base;
+
+ if (!base->d_inode) {
+ dput(base);
+ return ERR_PTR(-ENOENT);
+ }
+
+ return base;
}
#ifdef CONFIG_BINFMT_IRIX
#define N_FDC 2 /* Don't change this! */
#define N_DRIVE 8
+#define FLOPPY_MOTOR_MASK 0xf0
+
/*
* The PowerPC has no problems with floppy DMA crossing 64k borders.
*/
-/* $Id: namei.h,v 1.7 1997/08/29 15:52:27 jj Exp $
+/* $Id: namei.h,v 1.8 1997/09/05 12:38:51 jj Exp $
* linux/include/asm-sparc/namei.h
*
* Routines to handle famous /usr/gnemul/s*.
if (IS_ERR (base)) return base;
- return lookup_dentry (name, base, follow_link);
+ base = lookup_dentry (name, base, follow_link);
+
+ if (IS_ERR (base)) return base;
+
+ if (!base->d_inode) {
+ dput(base);
+ return ERR_PTR(-ENOENT);
+ }
+
+ return base;
}
#define __prefix_lookup_dentry(name, follow_link) \
-/* $Id: ebus.h,v 1.2 1997/08/17 22:40:07 ecd Exp $
+/* $Id: ebus.h,v 1.3 1997/09/05 23:00:14 ecd Exp $
* ebus.h: PCI to Ebus pseudo driver software state.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
#include <asm/oplib.h>
+struct linux_ebus_child {
+ struct linux_ebus_child *next;
+ struct linux_ebus_device *parent;
+ int prom_node;
+ char prom_name[64];
+ unsigned long base_address[PROMREG_MAX];
+ int num_addrs;
+ unsigned int irqs[PROMINTR_MAX];
+ int num_irqs;
+};
+
struct linux_ebus_device {
struct linux_ebus_device *next;
+ struct linux_ebus_child *children;
struct linux_ebus *parent;
int prom_node;
char prom_name[64];
unsigned int irqs[PROMINTR_MAX];
int num_irqs;
};
-
+
struct linux_ebus {
struct linux_ebus *next;
struct linux_ebus_device *devices;
int num_ebus_ranges;
};
+struct linux_ebus_dma {
+ unsigned int dcsr;
+ unsigned int dacr;
+ unsigned int dbcr;
+};
+
+#define EBUS_DCSR_INT_PEND 0x00000001
+#define EBUS_DCSR_ERR_PEND 0x00000002
+#define EBUS_DCSR_DRAIN 0x00000004
+#define EBUS_DCSR_INT_EN 0x00000010
+#define EBUS_DCSR_RESET 0x00000080
+#define EBUS_DCSR_WRITE 0x00000100
+#define EBUS_DCSR_EN_DMA 0x00000200
+#define EBUS_DCSR_CYC_PEND 0x00000400
+#define EBUS_DCSR_DIAG_RD_DONE 0x00000800
+#define EBUS_DCSR_DIAG_WR_DONE 0x00001000
+#define EBUS_DCSR_EN_CNT 0x00002000
+#define EBUS_DCSR_TC 0x00004000
+#define EBUS_DCSR_DIS_CSR_DRN 0x00010000
+#define EBUS_DCSR_BURST_SZ_MASK 0x000c0000
+#define EBUS_DCSR_BURST_SZ_1 0x00080000
+#define EBUS_DCSR_BURST_SZ_4 0x00000000
+#define EBUS_DCSR_BURST_SZ_8 0x00040000
+#define EBUS_DCSR_BURST_SZ_16 0x000c0000
+#define EBUS_DCSR_DIAG_EN 0x00100000
+#define EBUS_DCSR_DIS_ERR_PEND 0x00400000
+#define EBUS_DCSR_TCI_DIS 0x00800000
+#define EBUS_DCSR_EN_NEXT 0x01000000
+#define EBUS_DCSR_DMA_ON 0x02000000
+#define EBUS_DCSR_A_LOADED 0x04000000
+#define EBUS_DCSR_NA_LOADED 0x08000000
+#define EBUS_DCSR_DEV_ID_MASK 0xf0000000
+
extern struct linux_ebus *ebus_chain;
extern unsigned long ebus_init(unsigned long, unsigned long);
#define for_each_ebusdev(dev, bus) \
for((dev) = (bus)->devices; (dev); (dev) = (dev)->next)
+#define for_each_edevchild(dev, child) \
+ for((child) = (dev)->children; (child); (child) = (child)->next)
+
#define for_all_ebusdev(dev, bus) \
for ((bus) = ebus_chain, ((dev) = (bus) ? (bus)->devices : 0); \
(bus); ((dev) = (dev)->next ? (dev)->next : \
-/* $Id: floppy.h,v 1.3 1997/07/11 03:03:22 davem Exp $
+/* $Id: floppy.h,v 1.4 1997/09/05 23:00:15 ecd Exp $
* asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ * Ultra/PCI support added: Sep 1997 Eddie C. Dost (ecd@skynet.be)
*/
#ifndef __ASM_SPARC64_FLOPPY_H
#define __ASM_SPARC64_FLOPPY_H
+#include <linux/config.h>
+
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/system.h>
* 3) Intel 82077 controller manual
*/
struct sun_flpy_controller {
- volatile unsigned char status_82072; /* Main Status reg. */
-#define dcr_82072 status_82072 /* Digital Control reg. */
-#define status1_82077 status_82072 /* Auxiliary Status reg. 1 */
-
- volatile unsigned char data_82072; /* Data fifo. */
-#define status2_82077 data_82072 /* Auxiliary Status reg. 2 */
-
+ volatile unsigned char status1_82077; /* Auxiliary Status reg. 1 */
+ volatile unsigned char status2_82077; /* Auxiliary Status reg. 2 */
volatile unsigned char dor_82077; /* Digital Output reg. */
volatile unsigned char tapectl_82077; /* What the? Tape control reg? */
-
volatile unsigned char status_82077; /* Main Status Register. */
#define drs_82077 status_82077 /* Digital Rate Select reg. */
-
volatile unsigned char data_82077; /* Data fifo. */
volatile unsigned char ___unused;
volatile unsigned char dir_82077; /* Digital Input reg. */
volatile unsigned char *fdc_status;
struct sun_floppy_ops {
- unsigned char (*fd_inb)(int port);
- void (*fd_outb)(unsigned char value, int port);
+ unsigned char (*fd_inb) (unsigned long port);
+ void (*fd_outb) (unsigned char value, unsigned long port);
+ void (*fd_enable_dma) (void);
+ void (*fd_disable_dma) (void);
+ void (*fd_set_dma_mode) (int);
+ void (*fd_set_dma_addr) (char *);
+ void (*fd_set_dma_count) (int);
+ unsigned int (*get_dma_residue) (void);
+ void (*fd_enable_irq) (void);
+ void (*fd_disable_irq) (void);
+ int (*fd_request_irq) (void);
+ void (*fd_free_irq) (void);
+ int (*fd_eject) (int);
};
static struct sun_floppy_ops sun_fdops;
#define fd_inb(port) sun_fdops.fd_inb(port)
#define fd_outb(value,port) sun_fdops.fd_outb(value,port)
-#define fd_enable_dma() sun_fd_enable_dma()
-#define fd_disable_dma() sun_fd_disable_dma()
+#define fd_enable_dma() sun_fdops.fd_enable_dma()
+#define fd_disable_dma() sun_fdops.fd_disable_dma()
#define fd_request_dma() (0) /* nothing... */
#define fd_free_dma() /* nothing... */
#define fd_clear_dma_ff() /* nothing... */
-#define fd_set_dma_mode(mode) sun_fd_set_dma_mode(mode)
-#define fd_set_dma_addr(addr) sun_fd_set_dma_addr(addr)
-#define fd_set_dma_count(count) sun_fd_set_dma_count(count)
-#define fd_enable_irq() /* nothing... */
-#define fd_disable_irq() /* nothing... */
+#define fd_set_dma_mode(mode) sun_fdops.fd_set_dma_mode(mode)
+#define fd_set_dma_addr(addr) sun_fdops.fd_set_dma_addr(addr)
+#define fd_set_dma_count(count) sun_fdops.fd_set_dma_count(count)
+#define get_dma_residue(x) sun_fdops.get_dma_residue()
+#define fd_enable_irq() sun_fdops.fd_enable_irq()
+#define fd_disable_irq() sun_fdops.fd_disable_irq()
#define fd_cacheflush(addr, size) /* nothing... */
-#define fd_request_irq() sun_fd_request_irq()
-#define fd_free_irq() /* nothing... */
-#if 0 /* P3: added by Alain, these cause a MMU corruption. 19960524 XXX */
-#define fd_dma_mem_alloc(size) ((unsigned long) vmalloc(size))
-#define fd_dma_mem_free(addr,size) (vfree((void *)(addr)))
-#endif
-
-#define FLOPPY_MOTOR_MASK 0x10
-
-/* It's all the same... */
-#define virt_to_bus(x) (x)
-#define bus_to_virt(x) (x)
+#define fd_request_irq() sun_fdops.fd_request_irq()
+#define fd_free_irq() sun_fdops.fd_free_irq()
+#define fd_eject(drive) sun_fdops.fd_eject(drive)
-/* XXX This isn't really correct. XXX */
-#define get_dma_residue(x) (0)
+static int FLOPPY_MOTOR_MASK = 0x10;
#define FLOPPY0_TYPE 4
#define FLOPPY1_TYPE 0
*/
#define FDC1 sun_floppy_init()
-static int FDC2=-1;
+static int FDC2 = -1;
#define N_FDC 1
#define N_DRIVE 8
/* No 64k boundary crossing problems on the Sparc. */
#define CROSS_64KB(a,s) (0)
-/* Routines unique to each controller type on a Sun. */
-static unsigned char sun_82072_fd_inb(int port)
+static unsigned char sun_82077_fd_inb(unsigned long port)
{
switch(port & 7) {
default:
- printk("floppy: Asked to read unknown port %d\n", port);
- panic("floppy: Port bolixed.");
- case 4: /* FD_STATUS */
- return sun_fdc->status_82072 & ~STATUS_DMA;
- case 5: /* FD_DATA */
- return sun_fdc->data_82072;
- case 7: /* FD_DIR */
- return (*AUXREG & AUXIO_FLPY_DCHG)? 0x80: 0;
- };
- panic("sun_82072_fd_inb: How did I get here?");
-}
-
-static void sun_82072_fd_outb(unsigned char value, int port)
-{
- switch(port & 7) {
- default:
- printk("floppy: Asked to write to unknown port %d\n", port);
- panic("floppy: Port bolixed.");
- case 2: /* FD_DOR */
- /* Oh geese, 82072 on the Sun has no DOR register,
- * the functionality is implemented via the AUXIO
- * I/O register. So we must emulate the behavior.
- *
- * ASSUMPTIONS: There will only ever be one floppy
- * drive attached to a Sun controller
- * and it will be at drive zero.
- */
- {
- unsigned bits = 0;
- if (value & 0x10) bits |= AUXIO_FLPY_DSEL;
- if ((value & 0x80) == 0) bits |= AUXIO_FLPY_EJCT;
- set_auxio(bits, (~bits) & (AUXIO_FLPY_DSEL|AUXIO_FLPY_EJCT));
- }
- break;
- case 5: /* FD_DATA */
- sun_fdc->data_82072 = value;
- break;
- case 7: /* FD_DCR */
- sun_fdc->dcr_82072 = value;
- break;
- case 4: /* FD_STATUS */
- sun_fdc->status_82072 = value;
- break;
- };
- return;
-}
-
-static unsigned char sun_82077_fd_inb(int port)
-{
- switch(port & 7) {
- default:
- printk("floppy: Asked to read unknown port %d\n", port);
+ printk("floppy: Asked to read unknown port %lx\n", port);
panic("floppy: Port bolixed.");
case 4: /* FD_STATUS */
return sun_fdc->status_82077 & ~STATUS_DMA;
panic("sun_82072_fd_inb: How did I get here?");
}
-static void sun_82077_fd_outb(unsigned char value, int port)
+static void sun_82077_fd_outb(unsigned char value, unsigned long port)
{
switch(port & 7) {
default:
- printk("floppy: Asked to write to unknown port %d\n", port);
+ printk("floppy: Asked to write to unknown port %lx\n", port);
panic("floppy: Port bolixed.");
case 2: /* FD_DOR */
/* Happily, the 82077 has a real DOR register. */
/* nothing... */
}
-static __inline__ void sun_fd_disable_dma(void)
+static void sun_fd_disable_dma(void)
{
doing_pdma = 0;
if (pdma_base) {
}
}
-static __inline__ void sun_fd_set_dma_mode(int mode)
+static void sun_fd_set_dma_mode(int mode)
{
switch(mode) {
case DMA_MODE_READ:
}
}
-static __inline__ void sun_fd_set_dma_addr(char *buffer)
+static void sun_fd_set_dma_addr(char *buffer)
{
pdma_vaddr = buffer;
}
-static __inline__ void sun_fd_set_dma_count(int length)
+static void sun_fd_set_dma_count(int length)
{
pdma_size = length;
}
-static __inline__ void sun_fd_enable_dma(void)
+static void sun_fd_enable_dma(void)
{
pdma_vaddr = mmu_lockarea(pdma_vaddr, pdma_size);
pdma_base = pdma_vaddr;
} else return 0;
}
+static void sun_fd_enable_irq(void)
+{
+}
+
+static void sun_fd_disable_irq(void)
+{
+}
+
+static void sun_fd_free_irq(void)
+{
+}
+
+static unsigned int sun_get_dma_residue(void)
+{
+ /* XXX This isn't really correct. XXX */
+ return 0;
+}
+
+static int sun_fd_eject(int drive)
+{
+ set_dor(0x00, 0xff, 0x90);
+ udelay(500);
+ set_dor(0x00, 0x6f, 0x00);
+ udelay(500);
+ return 0;
+}
+
+#ifdef CONFIG_PCI
+#include <asm/ebus.h>
+
+static struct linux_ebus_dma *sun_fd_ebus_dma;
+
+extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+static unsigned char sun_pci_fd_inb(unsigned long port)
+{
+ return inb(port);
+}
+
+static void sun_pci_fd_outb(unsigned char val, unsigned long port)
+{
+ outb(val, port);
+}
+
+static void sun_pci_fd_enable_dma(void)
+{
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&sun_fd_ebus_dma->dcsr);
+ dcsr |= (EBUS_DCSR_EN_DMA | EBUS_DCSR_EN_CNT);
+ writel(dcsr, (unsigned long)&sun_fd_ebus_dma->dcsr);
+}
+
+static void sun_pci_fd_disable_dma(void)
+{
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&sun_fd_ebus_dma->dcsr);
+ dcsr &= ~(EBUS_DCSR_EN_DMA | EBUS_DCSR_EN_CNT);
+ writel(dcsr, (unsigned long)&sun_fd_ebus_dma->dcsr);
+}
+
+static void sun_pci_fd_set_dma_mode(int mode)
+{
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&sun_fd_ebus_dma->dcsr);
+ /*
+ * For EBus WRITE means to system memory, which is
+ * READ for us.
+ */
+ if (mode == DMA_MODE_WRITE)
+ dcsr &= ~(EBUS_DCSR_WRITE);
+ else
+ dcsr |= EBUS_DCSR_WRITE;
+ writel(dcsr, (unsigned long)&sun_fd_ebus_dma->dcsr);
+}
+
+static void sun_pci_fd_set_dma_count(int length)
+{
+ writel(length, (unsigned long)&sun_fd_ebus_dma->dbcr);
+}
+
+static void sun_pci_fd_set_dma_addr(char *buffer)
+{
+ unsigned int addr;
+
+ addr = virt_to_bus(buffer);
+ writel(addr, (unsigned long)&sun_fd_ebus_dma->dacr);
+}
+
+static void sun_pci_fd_enable_irq(void)
+{
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&sun_fd_ebus_dma->dcsr);
+ dcsr |= EBUS_DCSR_INT_EN;
+ writel(dcsr, (unsigned long)&sun_fd_ebus_dma->dcsr);
+}
+
+static void sun_pci_fd_disable_irq(void)
+{
+ unsigned int dcsr;
+
+ dcsr = readl((unsigned long)&sun_fd_ebus_dma->dcsr);
+ dcsr &= ~(EBUS_DCSR_INT_EN);
+ writel(dcsr, (unsigned long)&sun_fd_ebus_dma->dcsr);
+}
+
+static int sun_pci_fd_request_irq(void)
+{
+ int error;
+
+ error = request_irq(FLOPPY_IRQ, floppy_interrupt, SA_SHIRQ, "floppy", sun_fdc);
+ return ((error == 0) ? 0 : -1);
+}
+
+static void sun_pci_fd_free_irq(void)
+{
+ free_irq(FLOPPY_IRQ, sun_fdc);
+}
+
+static unsigned int sun_pci_get_dma_residue(void)
+{
+ unsigned int res;
+
+ res = readl((unsigned long)&sun_fd_ebus_dma->dbcr);
+ return res;
+}
+
+static int sun_pci_fd_eject(int drive)
+{
+ return -EINVAL;
+}
+#endif
+
static struct linux_prom_registers fd_regs[2];
-static int sun_floppy_init(void)
+static unsigned long sun_floppy_init(void)
{
char state[128];
int fd_node, num_regs;
struct linux_sbus *bus;
struct linux_sbus_device *sdev;
- use_virtual_dma = 1;
-
FLOPPY_IRQ = 11;
for_all_sbusdev (sdev, bus) {
if (!strcmp(sdev->prom_name, "SUNW,fdtwo"))
break;
}
- if (!bus) return -1;
+ if (!bus) {
+#ifdef CONFIG_PCI
+ struct linux_ebus *ebus;
+ struct linux_ebus_device *edev;
+
+ for_all_ebusdev(edev, ebus) {
+ if (!strcmp(edev->prom_name, "fdthree"))
+ break;
+ }
+ if (!edev)
+ return -1;
+
+ if (check_region(edev->base_address[1], sizeof(struct linux_ebus_dma))) {
+ printk("sun_floppy_init: can't get region %016lx (%d)\n",
+ edev->base_address[1], (int)sizeof(struct linux_ebus_dma));
+ return -1;
+ }
+ request_region(edev->base_address[1], sizeof(struct linux_ebus_dma), "floppy DMA");
+
+ sun_fdc = (struct sun_flpy_controller *)edev->base_address[0];
+ FLOPPY_IRQ = edev->irqs[0];
+
+ sun_fd_ebus_dma = (struct linux_ebus_dma *)edev->base_address[1];
+ writel(EBUS_DCSR_BURST_SZ_16, (unsigned long)&sun_fd_ebus_dma->dcsr);
+
+ sun_fdops.fd_inb = sun_pci_fd_inb;
+ sun_fdops.fd_outb = sun_pci_fd_outb;
+
+ use_virtual_dma = 0;
+ sun_fdops.fd_enable_dma = sun_pci_fd_enable_dma;
+ sun_fdops.fd_disable_dma = sun_pci_fd_disable_dma;
+ sun_fdops.fd_set_dma_mode = sun_pci_fd_set_dma_mode;
+ sun_fdops.fd_set_dma_addr = sun_pci_fd_set_dma_addr;
+ sun_fdops.fd_set_dma_count = sun_pci_fd_set_dma_count;
+ sun_fdops.get_dma_residue = sun_pci_get_dma_residue;
+
+ sun_fdops.fd_enable_irq = sun_pci_fd_enable_irq;
+ sun_fdops.fd_disable_irq = sun_pci_fd_disable_irq;
+ sun_fdops.fd_request_irq = sun_pci_fd_request_irq;
+ sun_fdops.fd_free_irq = sun_pci_fd_free_irq;
+
+ sun_fdops.fd_eject = sun_pci_fd_eject;
+
+ fdc_status = &sun_fdc->status_82077;
+ FLOPPY_MOTOR_MASK = 0xf0;
+
+ return (unsigned long)sun_fdc;
+#else
+ return -1;
+#endif
+ }
fd_node = sdev->prom_node;
prom_getproperty(fd_node, "status", state, sizeof(state));
if(!strcmp(state, "disabled")) return -1;
fd_regs[0].which_io,
0x0);
/* Last minute sanity check... */
- if(sun_fdc->status_82072 == 0xff) {
+ if(sun_fdc->status1_82077 == 0xff) {
sun_fdc = NULL;
return -1;
}
sun_fdops.fd_inb = sun_82077_fd_inb;
sun_fdops.fd_outb = sun_82077_fd_outb;
+
+ use_virtual_dma = 1;
+ sun_fdops.fd_enable_dma = sun_fd_enable_dma;
+ sun_fdops.fd_disable_dma = sun_fd_disable_dma;
+ sun_fdops.fd_set_dma_mode = sun_fd_set_dma_mode;
+ sun_fdops.fd_set_dma_addr = sun_fd_set_dma_addr;
+ sun_fdops.fd_set_dma_count = sun_fd_set_dma_count;
+ sun_fdops.get_dma_residue = sun_get_dma_residue;
+
+ sun_fdops.fd_enable_irq = sun_fd_enable_irq;
+ sun_fdops.fd_disable_irq = sun_fd_disable_irq;
+ sun_fdops.fd_request_irq = sun_fd_request_irq;
+ sun_fdops.fd_free_irq = sun_fd_free_irq;
+
+ sun_fdops.fd_eject = sun_fd_eject;
+
fdc_status = &sun_fdc->status_82077;
/* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */
/* Success... */
- return (int) ((unsigned long)sun_fdc);
+ return (unsigned long)sun_fdc;
}
-static int sparc_eject(void)
-{
- set_dor(0x00, 0xff, 0x90);
- udelay(500);
- set_dor(0x00, 0x6f, 0x00);
- udelay(500);
- return 0;
-}
-
-#define fd_eject(drive) sparc_eject()
-
#endif /* !(__ASM_SPARC64_FLOPPY_H) */
-/* $Id: namei.h,v 1.7 1997/09/04 15:46:31 jj Exp $
+/* $Id: namei.h,v 1.8 1997/09/06 02:25:27 davem Exp $
* linux/include/asm-sparc64/namei.h
*
* Routines to handle famous /usr/gnemul/s*.
static inline struct dentry *
__sparc64_lookup_dentry(const char *name, int follow_link)
{
- int error;
struct dentry *base;
switch (current->personality) {
*
* Definitions for the ARCnet handlers.
*
- * Version: @(#)arcdevice.h 1.0 31/07/97
+ * Version: $Id: arcdevice.h,v 1.2 1997/09/05 08:57:56 mj Exp $
*
* Authors: Avery Pennarun <apenwarr@bond.net>
* David Woodhouse <dwmw2@cam.ac.uk>
#ifdef __KERNEL__
-
#define ARC_20020 1
#define ARC_RIM_I 2
#define ARC_90xx 3
#define DETECT_RECONFIGS
#undef SHOW_RECONFIGS
+
/* RECON_THRESHOLD is the maximum number of RECON messages to receive within
* one minute before printing a "cabling problem" warning. You must have
* DETECT_RECONFIGS enabled if you want to use this. The default value
*/
#define RECON_THRESHOLD 30
+
/* Define this to the minimum "timeout" value. If a transmit takes longer
* than TX_TIMEOUT jiffies, Linux will abort the TX and retry. On a large
* network, or one with heavy network traffic, this timeout may need to be
#define TX_TIMEOUT 20
+/* Display warnings about the driver being an ALPHA version.
+ */
+#define ALPHA_WARNING
+
+
/* New debugging bitflags: each option can be enabled individually.
*
* These can be set while the driver is running by typing:
};
-
/* the "client data" header - RFC1201 information
* notice that this screws up if it's not an even number of bytes
* <sigh>
#define S_EXTRA_CLIENTDATA (sizeof(struct S_ClientData)-1)
-
/* "Incoming" is information needed for each address that could be sending
* to us. Mostly for partially-received split packets.
*/
};
-
struct arcnet_local {
struct net_device_stats stats;
u_short sequence; /* sequence number (incs with each packet) */
u_char stationid, /* our 8-bit station address */
recbuf, /* receive buffer # (0 or 1) */
txbuf, /* transmit buffer # (2 or 3) */
- txready, /* buffer where a packet is ready to send */
- config, /* current value of CONFIG register */
- timeout, /* Extended timeout for COM20020 */
- backplane, /* Backplane flag for COM20020 */
- setup, /* Contents of setup register */
- intmask; /* current value of INTMASK register */
+ txready, /* buffer where a packet is ready to send */
+ config, /* current value of CONFIG register */
+ timeout, /* Extended timeout for COM20020 */
+ backplane, /* Backplane flag for COM20020 */
+ setup, /* Contents of setup register */
+ intmask; /* current value of INTMASK register */
short intx, /* in TX routine? */
in_txhandler, /* in TX_IRQ handler? */
sending, /* transmit in progress? */
#if defined(DETECT_RECONFIGS) && defined(RECON_THRESHOLD)
time_t first_recon, /* time of "first" RECON message to count */
- last_recon; /* time of most recent RECON */
- int num_recons, /* number of RECONs between first and last. */
+ last_recon; /* time of most recent RECON */
+ int num_recons, /* number of RECONs between first and last. */
network_down; /* do we think the network is down? */
#endif
void (*en_dis_able_TX) (struct device *dev, int enable);
void (*prepare_tx)(struct device *dev,u_char *hdr,int hdrlen,
char *data,int length,int daddr,int exceptA, int offset);
- void (*openclose_device)(int open);
-
+ void (*openclose_device)(int open);
struct device *adev; /* RFC1201 protocol device */
#ifdef CONFIG_ARCNET_1051
struct device *sdev; /* RFC1051 protocol device */
#endif
+};
+/* Functions exported by arcnet.c
+ */
-};
+#if ARCNET_DEBUG_MAX & D_SKB
+extern void arcnet_dump_skb(struct device *dev,struct sk_buff *skb,
+ char *desc);
+#else
+#define arcnet_dump_skb(dev,skb,desc) ;
+#endif
+#if (ARCNET_DEBUG_MAX & D_RX) || (ARCNET_DEBUG_MAX & D_TX)
+extern void arcnet_dump_packet(struct device *dev,u_char *buffer,int ext,
+ char *desc);
+#else
+#define arcnet_dump_packet(dev,buffer,ext,desc) ;
+#endif
-#endif /* __KERNEL__ */
-#endif /* _LINUX_ARCDEVICE_H */
+extern void arcnet_tx_done(struct device *dev, struct arcnet_local *lp);
+extern void arcnet_makename(char *device);
+extern void arcnet_interrupt(int irq,void *dev_id,struct pt_regs *regs);
+extern void arcnet_setup(struct device *dev);
+extern int arcnet_go_tx(struct device *dev,int enable_irq);
+extern void arcnetA_continue_tx(struct device *dev);
+extern void arcnet_rx(struct arcnet_local *lp, u_char *arcsoft, short length, int saddr, int daddr);
+extern void arcnet_use_count(int open);
+#endif /* __KERNEL__ */
+#endif /* _LINUX_ARCDEVICE_H */
int dtr;
unsigned char version; /* FDC version code */
unsigned char dor;
- int address; /* io address */
+ unsigned long address; /* io address */
unsigned int rawcmd:2;
unsigned int reset:1;
unsigned int need_configure:1;
*
* Global definitions for the ARCnet interface.
*
- * Version: @(#)if_arcnet.h 1.0 07/08/97
+ * Version: $Id: if_arcnet.h,v 1.2 1997/09/05 08:57:54 mj Exp $
*
* Author: David Woodhouse <dwmw2@cam.ac.uk>
* Avery Pennarun <apenwarr@bond.net>
/*
* This is an ARCnet frame header.
*/
-
+
struct archdr /* was struct HardHeader */
{
u_char source, /* source ARCnet - filled in automagically */
};
#endif /* _LINUX_IF_ARCNET_H */
-
*/
#define fsuser() (current->fsuid == 0)
+/*
+ * Display an IP address in readable format.
+ */
+
+#define NIPQUAD(addr) \
+ (((addr) >> 0) & 0xff), \
+ (((addr) >> 8) & 0xff), \
+ (((addr) >> 16) & 0xff), \
+ (((addr) >> 24) & 0xff)
+
#endif /* __KERNEL__ */
#define SI_LOAD_SHIFT 16
--- /dev/null
+/*
+ * linux/openpic.h -- OpenPIC definitions
+ *
+ * Copyright (C) 1997 Geert Uytterhoeven
+ *
+ * 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.
+ *
+ * This file is based on the following documentation:
+ *
+ * The Open Programmable Interrupt Controller (PIC)
+ * Register Interface Specification Revision 1.2
+ *
+ * Issue Date: October 1995
+ *
+ * Issued jointly by Advanced Micro Devices and Cyrix Corporation
+ *
+ * AMD is a registered trademark of Advanced Micro Devices, Inc.
+ * Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
+ * All Rights Reserved.
+ *
+ * To receive a copy of this documentation, send an email to openpic@amd.com.
+ *
+ * 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 _LINUX_OPENPIC_H
+#define _LINUX_OPENPIC_H
+
+#if !defined(__powerpc__) && !defined(__i386__)
+#error Unsupported OpenPIC platform
+#endif
+
+
+#ifdef __KERNEL__
+
+ /*
+ * OpenPIC supports up to 2048 interrupt sources and up to 32 processors
+ */
+
+#define OPENPIC_MAX_SOURCES 2048
+#define OPENPIC_MAX_PROCESSORS 32
+
+#define OPENPIC_NUM_TIMERS 4
+#define OPENPIC_NUM_IPI 4
+#define OPENPIC_NUM_PRI 16
+#define OPENPIC_NUM_VECTORS 256
+
+
+ /*
+ * OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
+ */
+
+typedef struct _OpenPIC_Reg {
+ u_int Reg; /* Little endian! */
+ char Pad[0xc];
+} OpenPIC_Reg;
+
+
+ /*
+ * Per Processor Registers
+ */
+
+typedef struct _OpenPIC_Processor {
+ /*
+ * Private Shadow Registers (for SLiC backwards compatibility)
+ */
+ u_int IPI0_Dispatch_Shadow; /* Write Only */
+ char Pad1[0x4];
+ u_int IPI0_Vector_Priority_Shadow; /* Read/Write */
+ char Pad2[0x34];
+ /*
+ * Interprocessor Interrupt Command Ports
+ */
+ OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */
+ /*
+ * Current Task Priority Register
+ */
+ OpenPIC_Reg _Current_Task_Priority; /* Read/Write */
+#ifndef __powerpc__
+ /*
+ * Who Am I Register
+ */
+ OpenPIC_Reg _Who_Am_I; /* Read Only */
+#else
+ char Pad3[0x10];
+#endif
+#ifndef __i386__
+ /*
+ * Interrupt Acknowledge Register
+ */
+ OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */
+#else
+ char Pad4[0x10];
+#endif
+ /*
+ * End of Interrupt (EOI) Register
+ */
+ OpenPIC_Reg _EOI; /* Read/Write */
+ char Pad5[0xf40];
+} OpenPIC_Processor;
+
+
+ /*
+ * Timer Registers
+ */
+
+typedef struct _OpenPIC_Timer {
+ OpenPIC_Reg _Current_Count; /* Read Only */
+ OpenPIC_Reg _Base_Count; /* Read/Write */
+ OpenPIC_Reg _Vector_Priority; /* Read/Write */
+ OpenPIC_Reg _Destination; /* Read/Write */
+} OpenPIC_Timer;
+
+
+ /*
+ * Global Registers
+ */
+
+typedef struct _OpenPIC_Global {
+ /*
+ * Feature Reporting Registers
+ */
+ OpenPIC_Reg _Feature_Reporting0; /* Read Only */
+ OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */
+ /*
+ * Global Configuration Registers
+ */
+ OpenPIC_Reg _Global_Configuration0; /* Read/Write */
+ OpenPIC_Reg _Global_Configuration1; /* Future Expansion */
+ /*
+ * Vendor Specific Registers
+ */
+ OpenPIC_Reg _Vendor_Specific[4];
+ /*
+ * Vendor Identification Register
+ */
+ OpenPIC_Reg _Vendor_Identification; /* Read Only */
+ /*
+ * Processor Initialization Register
+ */
+ OpenPIC_Reg _Processor_Initialization; /* Read/Write */
+ /*
+ * IPI Vector/Priority Registers
+ */
+ OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */
+ /*
+ * Spurious Vector Register
+ */
+ OpenPIC_Reg _Spurious_Vector; /* Read/Write */
+ /*
+ * Global Timer Registers
+ */
+ OpenPIC_Reg _Timer_Frequency; /* Read/Write */
+ OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
+ char Pad1[0xee00];
+} OpenPIC_Global;
+
+
+ /*
+ * Interrupt Source Registers
+ */
+
+typedef struct _OpenPIC_Source {
+ OpenPIC_Reg _Vector_Priority; /* Read/Write */
+ OpenPIC_Reg _Destination; /* Read/Write */
+} OpenPIC_Source;
+
+
+ /*
+ * OpenPIC Register Map
+ */
+
+struct OpenPIC {
+#ifndef __powerpc__
+ /*
+ * Per Processor Registers --- Private Access
+ */
+ OpenPIC_Processor Private;
+#else
+ char Pad1[0x1000];
+#endif
+ /*
+ * Global Registers
+ */
+ OpenPIC_Global Global;
+ /*
+ * Interrupt Source Configuration Registers
+ */
+ OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
+ /*
+ * Per Processor Registers
+ */
+ OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
+};
+
+extern volatile struct OpenPIC *OpenPIC;
+
+
+ /*
+ * Current Task Priority Register
+ */
+
+#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f
+
+ /*
+ * Who Am I Register
+ */
+
+#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f
+
+ /*
+ * Feature Reporting Register 0
+ */
+
+#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000
+#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16
+#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00
+#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8
+#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff
+
+ /*
+ * Global Configuration Register 0
+ */
+
+#define OPENPIC_CONFIG_RESET 0x80000000
+#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000
+#define OPENPIC_CONFIG_BASE_MASK 0x000fffff
+
+ /*
+ * Vendor Identification Register
+ */
+
+#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000
+#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16
+#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00
+#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8
+#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff
+
+ /*
+ * Vector/Priority Registers
+ */
+
+#define OPENPIC_MASK 0x80000000
+#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */
+#define OPENPIC_PRIORITY_MASK 0x000f0000
+#define OPENPIC_PRIORITY_SHIFT 16
+#define OPENPIC_VECTOR_MASK 0x000000ff
+
+
+ /*
+ * Interrupt Source Registers
+ */
+
+#define OPENPIC_SENSE_POLARITY 0x00800000 /* Undoc'd */
+#define OPENPIC_SENSE_LEVEL 0x00400000
+
+
+ /*
+ * Timer Registers
+ */
+
+#define OPENPIC_COUNT_MASK 0x7fffffff
+#define OPENPIC_TIMER_TOGGLE 0x80000000
+#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000
+
+
+ /*
+ * Aliases to make life simpler
+ */
+
+/* Per Processor Registers */
+#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg
+#define Current_Task_Priority _Current_Task_Priority.Reg
+#ifndef __powerpc__
+#define Who_Am_I _Who_Am_I.Reg
+#endif
+#ifndef __i386__
+#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg
+#endif
+#define EOI _EOI.Reg
+
+/* Global Registers */
+#define Feature_Reporting0 _Feature_Reporting0.Reg
+#define Feature_Reporting1 _Feature_Reporting1.Reg
+#define Global_Configuration0 _Global_Configuration0.Reg
+#define Global_Configuration1 _Global_Configuration1.Reg
+#define Vendor_Specific(i) _Vendor_Specific[i].Reg
+#define Vendor_Identification _Vendor_Identification.Reg
+#define Processor_Initialization _Processor_Initialization.Reg
+#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg
+#define Spurious_Vector _Spurious_Vector.Reg
+#define Timer_Frequency _Timer_Frequency.Reg
+
+/* Timer Registers */
+#define Current_Count _Current_Count.Reg
+#define Base_Count _Base_Count.Reg
+#define Vector_Priority _Vector_Priority.Reg
+#define Destination _Destination.Reg
+
+/* Interrupt Source Registers */
+#define Vector_Priority _Vector_Priority.Reg
+#define Destination _Destination.Reg
+
+
+ /*
+ * Vendor and Device IDs
+ */
+
+#define OPENPIC_VENDOR_ID_APPLE 0x14
+#define OPENPIC_DEVICE_ID_APPLE_HYDRA 0x46
+
+
+ /*
+ * OpenPIC Operations
+ */
+
+/* Global Operations */
+extern void openpic_init(void);
+extern void openpic_reset(void);
+extern void openpic_enable_8259_pass_through(void);
+extern void openpic_disable_8259_pass_through(void);
+#ifndef __i386__
+extern u_int openpic_irq(u_int cpu);
+#endif
+#ifndef __powerpc__
+extern void openpic_eoi(void);
+extern u_int openpic_get_priority(void);
+extern void openpic_set_priority(u_int pri);
+#else
+extern void openpic_eoi(u_int cpu);
+extern u_int openpic_get_priority(u_int cpu);
+extern void openpic_set_priority(u_int cpu, u_int pri);
+#endif
+extern u_int openpic_get_spurious(void);
+extern void openpic_set_spurious(u_int vector);
+extern void openpic_init_processor(u_int cpumask);
+
+/* Interprocessor Interrupts */
+extern void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+#ifndef __powerpc__
+extern void openpic_cause_IPI(u_int ipi, u_int cpumask);
+#else
+extern void openpic_cause_IPI(u_int cpu, u_int ipi, u_int cpumask);
+#endif
+
+/* Timer Interrupts */
+extern void openpic_inittimer(u_int timer, u_int pri, u_int vector);
+extern void openpic_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+extern void openpic_enable_irq(u_int irq);
+extern void openpic_disable_irq(u_int irq);
+extern void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+ int is_level);
+extern void openpic_mapirq(u_int irq, u_int cpumask);
+extern void openpic_set_sense(u_int irq, int sense);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_OPENPIC_H */
#define PCI_DEVICE_ID_ADL_2301 0x2301
#define PCI_VENDOR_ID_NS 0x100b
+#define PCI_DEVICE_ID_NS_87415 0x0002
#define PCI_DEVICE_ID_NS_87410 0xd001
#define PCI_VENDOR_ID_TSENG 0x100c
#define PCI_DEVICE_ID_DEC_TULIP 0x0002
#define PCI_DEVICE_ID_DEC_TGA 0x0004
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
+#define PCI_DEVICE_ID_DEC_TGA2 0x000D
#define PCI_DEVICE_ID_DEC_FDDI 0x000F
#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
#define PCI_DEVICE_ID_DEC_21142 0x0019
#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014
#define PCI_DEVICE_ID_OLICOM_OC6151 0x0021
+#define PCI_VENDOR_ID_SUN 0x108e
+#define PCI_DEVICE_ID_SUN_EBUS 0x1000
+#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001
+#define PCI_DEVICE_ID_SUN_PBM 0x8000
+
#define PCI_VENDOR_ID_CMD 0x1095
#define PCI_DEVICE_ID_CMD_640 0x0640
#define PCI_DEVICE_ID_CMD_643 0x0643
* necessary. The field must not be 0 unless the device
* cannot generate interrupts at all.
*/
- unsigned char irq; /* irq generated by this device */
+ unsigned int irq; /* irq generated by this device */
+
+ /* Base registers for this device, can be adjusted by
+ * pcibios_fixup() as necessary.
+ */
+ unsigned long base_address[6];
};
struct pci_bus {
extern unsigned long pci_init (unsigned long mem_start, unsigned long mem_end);
+extern unsigned int pci_scan_bus(struct pci_bus *bus, unsigned long *mem_startp);
+
extern struct pci_dev_info *pci_lookup_dev (unsigned int vendor,
unsigned int dev);
extern const char *pci_strclass (unsigned int class);
#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */
#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */
+#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */
#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */
#ifndef _INET_COMMON_H
#define _INET_COMMON_H
-#include <linux/config.h>
-
extern struct proto_ops inet_stream_ops;
extern struct proto_ops inet_dgram_ops;
#ifndef _SNMP_H
#define _SNMP_H
-#include <linux/config.h>
-
/*
* We use all unsigned longs. Linux will soon be so reliable that even these
* will rapidly get too small 8-). Seriously consider the IpInReceives count
extern unsigned long pci_init(unsigned long, unsigned long);
extern long mca_init(long, long);
extern long sbus_init(long, long);
+extern long powermac_init(unsigned long, unsigned long);
extern void sysctl_init(void);
extern void filescache_init(void);
extern void lp_setup(char *str, int *ints);
#endif
extern void eth_setup(char *str, int *ints);
+#ifdef CONFIG_ARCNET_COM20020
+extern void com20020_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_ARCNET_RIM_I
+extern void arcrimi_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_ARCNET_COM90xxIO
+extern void com90io_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_ARCNET_COM90xx
+extern void com90xx_setup(char *str, int *ints);
+#endif
#ifdef CONFIG_DECNET
extern void decnet_setup(char *str, int *ints);
#endif
#ifdef CONFIG_SOUNDMODEM
extern void sm_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_PMAC_CONSOLE
+extern void pmac_cons_setup(char *str, int *ints);
+extern void pmac_vmode_setup(char *str, int *ints);
+#endif
#ifdef CONFIG_WDT
extern void wdt_setup(char *str, int *ints);
#endif
#ifdef CONFIG_PLIP
extern void plip_setup(char *str, int *ints);
#endif
+#ifdef CONFIG_HFMODEM
+extern void hfmodem_setup(char *str, int *ints);
+#endif
#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
extern void ipc_init(void);
#ifdef CONFIG_INET
{ "ether=", eth_setup },
#endif
+#ifdef CONFIG_ARCNET_COM20020
+ { "com20020=", com20020_setup },
+#endif
+#ifdef CONFIG_ARCNET_RIM_I
+ { "arcrimi=", arcrimi_setup },
+#endif
+#ifdef CONFIG_ARCNET_COM90xxIO
+ { "com90io=", com90io_setup },
+#endif
+#ifdef CONFIG_ARCNET_COM90xx
+ { "com90xx=", com90xx_setup },
+#endif
#ifdef CONFIG_DECNET
{ "decnet=", decnet_setup },
#endif
#endif
#ifdef CONFIG_PLIP
{ "plip=", plip_setup },
+#endif
+#ifdef CONFIG_SOUNDMODEM
+ { "hfmodem=", hfmodem_setup },
+#endif
+#ifdef CONFIG_PMAC_CONSOLE
+ { "console=", pmac_cons_setup },
+ { "vmode=", pmac_vmode_setup },
#endif
{ 0, 0 }
};
}
#ifdef CONFIG_SBUS
memory_start = sbus_init(memory_start,memory_end);
+#endif
+#ifdef CONFIG_PMAC
+ memory_start = powermac_init(memory_start, memory_end);
#endif
memory_start = console_init(memory_start,memory_end);
#ifdef CONFIG_PCI
if (shmflg & SHM_REMAP)
goto out;
err = -ENOMEM;
- if (!(addr = get_unmapped_area(0, shp->shm_segsz)))
+ addr = 0;
+ again:
+ if (!(addr = get_unmapped_area(addr, shp->shm_segsz)))
goto out;
+ if(addr & (SHMLBA - 1)) {
+ addr = (addr + (SHMLBA - 1)) & ~(SHMLBA - 1);
+ goto again;
+ }
} else if (addr & (SHMLBA-1)) {
if (shmflg & SHM_RND)
addr &= ~(SHMLBA-1); /* round down */
NORET_TYPE void do_exit(long code)
{
- if (in_interrupt()) {
- local_irq_count[smp_processor_id()] = 0; /* Not really correct */
+ if (in_interrupt())
printk("Aiee, killing interrupt handler\n");
- }
fake_volatile:
acct_process(code);
current->flags |= PF_EXITING;
#include <linux/vmalloc.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <asm/pgtable.h>
/*
* Originally by Anonymous (as far as I know...)
goto err3;
}
+ /* On some machines it is necessary to do something here
+ to make the I and D caches consistent. */
+ flush_icache_range((unsigned long)mod, (unsigned long)mod + mod->size);
+
/* Update module references. */
mod->next = mod_tmp.next;
mod->refs = NULL;
int acct_process(long exitcode)
{
struct acct ac;
- unsigned short fs;
+ unsigned long fs;
if (acct_active) {
strncpy(ac.ac_comm, current->comm, ACCT_COMM);
* 1993-10-08 Torsten Duwe
* adjtime interface update and CMOS clock write code
* 1995-08-13 Torsten Duwe
- * kernel PLL updated to 1994-12-13 specs (rfc-1489)
+ * kernel PLL updated to 1994-12-13 specs (rfc-1589)
*/
#include <linux/errno.h>
}
continue;
- case 'I': /* IPv4 / IPv6 printout */
- {
- __u8 *ip4;
- char sbuf[6];
- if (qualifier == 'l') {
- __u16 *ip6 = va_arg(args, __u16 *);
- i = 6;
- for ( ; i > 0; --i, ++ip6)
- if (*ip6 != 0)
- break;
- if (i < 6)
- *str++ = ':';
- for ( ; i > 0; --i, ++ip6) {
- sprintf(sbuf,":%04x",(int)(*ip6));
- s = sbuf;
- while (*s)
- *str++ = *s++;
- }
- *str++ = ':';
- ip4 = (__u8*) ip6;
- } else {
- ip4 = va_arg(args, __u8 *);
- }
- for (i = 0; i < 4; ++i, ++ip4) {
- if (i == 3)
- sprintf(sbuf,"%d", 0xFF & (*ip4));
- else
- sprintf(sbuf,"%d.", 0xFF & (*ip4));
- s = sbuf;
- while (*s)
- *str++ = *s++;
- }
- }
- continue;
-
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
static inline int do_write_page(struct inode * inode, struct file * file,
const char * page, unsigned long offset)
{
- int old_fs, retval;
+ int retval;
unsigned long size;
+ unsigned long old_fs;
size = offset + PAGE_SIZE;
/* refuse to extend file size.. */
*
* The IP fragmentation functionality.
*
- * Version: $Id: ip_fragment.c,v 1.25 1997/08/17 05:56:07 freitag Exp $
+ * Version: $Id: ip_fragment.c,v 1.26 1997/09/04 22:35:00 davem Exp $
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
* Alan Cox <Alan.Cox@linux.org>
len = qp->ihlen + qp->len;
if(len>65535) {
- printk(KERN_INFO "Oversized IP packet from %I.\n",
- &qp->iph->saddr);
+ printk(KERN_INFO "Oversized IP packet from %d.%d.%d.%d.\n", NIPQUAD(qp->iph->saddr));
ip_statistics.IpReasmFails++;
ip_free(qp);
return NULL;
if ((skb = dev_alloc_skb(len)) == NULL) {
ip_statistics.IpReasmFails++;
- NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing "
- "queue %p\n", qp));
+ NETDEBUG(printk(KERN_ERR "IP: queue_glue: no memory for gluing queue %p\n", qp));
ip_free(qp);
return NULL;
}
/* Attempt to construct an oversize packet. */
if(ntohs(iph->tot_len)+(int)offset>65535) {
- printk(KERN_INFO "Oversized packet received from %I\n",
- &iph->saddr);
+ printk(KERN_INFO "Oversized packet received from %d.%d.%d.%d\n", NIPQUAD(iph->saddr));
frag_kfree_skb(skb, FREE_READ);
ip_statistics.IpReasmFails++;
return NULL;
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp.c,v 1.70 1997/09/01 03:14:28 davem Exp $
+ * Version: $Id: tcp.c,v 1.71 1997/09/06 05:11:45 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Wait for an incoming connection, avoid race
* conditions. This must be called with the socket locked.
*/
-static struct open_request * wait_for_connect(struct sock * sk)
+static struct open_request * wait_for_connect(struct sock * sk,
+ struct open_request **pprev)
{
struct wait_queue wait = { current, NULL };
- struct open_request *req = NULL, *dummy;
+ struct open_request *req = NULL;
add_wait_queue(sk->sleep, &wait);
for (;;) {
release_sock(sk);
schedule();
lock_sock(sk);
- req = tcp_find_established(&(sk->tp_pinfo.af_tcp), &dummy);
+ req = tcp_find_established(&(sk->tp_pinfo.af_tcp), pprev);
if (req)
break;
if (current->signal & ~current->blocked)
error = EAGAIN;
if (flags & O_NONBLOCK)
goto out;
- req = wait_for_connect(sk);
+ req = wait_for_connect(sk, &prev);
if (req)
goto got_new_connect;
error = ERESTARTSYS;
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_ipv4.c,v 1.61 1997/09/02 09:46:55 freitag Exp $
+ * Version: $Id: tcp_ipv4.c,v 1.62 1997/09/04 22:34:59 davem Exp $
*
* IPv4 specific functions
*
case CHECKSUM_HW:
if (tcp_v4_check(th,len,saddr,daddr,skb->csum)) {
struct iphdr * iph = skb->nh.iph;
- printk(KERN_DEBUG "TCPv4 bad checksum from %I:%04x to %I:%04x, len=%d/%d/%d\n",
- &saddr, ntohs(th->source), &daddr,
+ printk(KERN_DEBUG "TCPv4 bad checksum from %d.%d.%d.%d:%04x to %d.%d.%d.%d:%04x, len=%d/%d/%d\n",
+ NIPQUAD(saddr), ntohs(th->source), NIPQUAD(daddr),
ntohs(th->dest), len, skb->len, ntohs(iph->tot_len));
goto discard_it;
}
default:
/* CHECKSUM_UNNECESSARY */
- };
+ }
tcp_statistics.TcpInSegs++;
EXPORT_SYMBOL(ip_rcv);
EXPORT_SYMBOL(arp_rcv);
+EXPORT_SYMBOL(if_port_text);
+
#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
#include<linux/if_ltalk.h>
EXPORT_SYMBOL(ltalk_setup);