S: Riverside, California 92521-0304
S: USA
+N: Hans Grobler
+E: grobh@sun.ac.za
+D: Various AX.25/ROSE/NETROM + hamradio driver patches
+S: Department of Electronic Engineering
+S: University of Stellenbosch
+S: Stellenbosch, Western Cape
+S: South Africa
+
N: Grant Guenther
E: grant@torque.net
W: http://www.torque.net/linux-pp.html
Eine deutsche Version dieser Datei finden Sie unter
<http://www.stefan-winter.de/Changes-2.4.0.txt>.
-Last updated: October 25, 2000
+Last updated: December 11, 2000
Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
o Gnu make 3.77 # make --version
o binutils 2.9.1.0.25 # ld -v
o util-linux 2.10o # fdformat --version
-o modutils 2.3.18 # insmod -V
+o modutils 2.3.21 # insmod -V
o e2fsprogs 1.19 # tune2fs --version
o pcmcia-cs 3.1.21 # cardmgr -V
o PPP 2.4.0 # pppd --version
Modutils
--------
-o <ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.18.tar.bz2>
+o <ftp://ftp.kernel.org/pub/linux/utils/kernel/modutils/v2.3/modutils-2.3.21.tar.bz2>
Mkinitrd
--------
--- /dev/null
+INTRODUCTION
+------------
+
+Because not every I2C or SMBus adapter implements everything in the
+I2C specifications, a client can not trust that everything it needs
+is implemented when it is given the option to attach to an adapter:
+the client needs some way to check whether an adapter has the needed
+functionality.
+
+
+FUNCTIONALITY CONSTANTS
+-----------------------
+
+For the most up-to-date list of functionality constants, please check
+<linux/i2c.h>!
+
+ I2C_FUNC_I2C Plain i2c-level commands (Pure SMBus
+ adapters typically can not do these)
+ I2C_FUNC_10BIT_ADDR Handles the 10-bit address extensions
+ I2C_FUNC_PROTOCOL_MANGLING Knows about the I2C_M_REV_DIR_ADDR,
+ I2C_M_REV_DIR_ADDR and I2C_M_REV_DIR_NOSTART
+ flags (which modify the i2c protocol!)
+ I2C_FUNC_SMBUS_QUICK Handles the SMBus write_quick command
+ I2C_FUNC_SMBUS_READ_BYTE Handles the SMBus read_byte command
+ I2C_FUNC_SMBUS_WRITE_BYTE Handles the SMBus write_byte command
+ I2C_FUNC_SMBUS_READ_BYTE_DATA Handles the SMBus read_byte_data command
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA Handles the SMBus write_byte_data command
+ I2C_FUNC_SMBUS_READ_WORD_DATA Handles the SMBus read_word_data command
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA Handles the SMBus write_byte_data command
+ I2C_FUNC_SMBUS_PROC_CALL Handles the SMBus process_call command
+ I2C_FUNC_SMBUS_READ_BLOCK_DATA Handles the SMBus read_block_data command
+ I2C_FUNC_SMBUS_WRITE_BLOCK_DATA Handles the SMBus write_block_data command
+ I2C_FUNC_SMBUS_READ_I2C_BLOCK Handles the SMBus read_i2c_block_data command
+ I2C_FUNC_SMBUS_WRITE_I2C_BLOCK Handles the SMBus write_i2c_block_data command
+
+A few combinations of the above flags are also defined for your convenience:
+
+ I2C_FUNC_SMBUS_BYTE Handles the SMBus read_byte
+ and write_byte commands
+ I2C_FUNC_SMBUS_BYTE_DATA Handles the SMBus read_byte_data
+ and write_byte_data commands
+ I2C_FUNC_SMBUS_WORD_DATA Handles the SMBus read_word_data
+ and write_word_data commands
+ I2C_FUNC_SMBUS_BLOCK_DATA Handles the SMBus read_block_data
+ and write_block_data commands
+ I2C_FUNC_SMBUS_I2C_BLOCK Handles the SMBus read_i2c_block_data
+ and write_i2c_block_data commands
+ I2C_FUNC_SMBUS_EMUL Handles all SMBus commands than can be
+ emulated by a real I2C adapter (using
+ the transparent emulation layer)
+
+
+ALGORITHM/ADAPTER IMPLEMENTATION
+--------------------------------
+
+When you write a new algorithm driver, you will have to implement a
+function callback `functionality', that gets an i2c_adapter structure
+pointer as its only parameter:
+
+ struct i2c_algorithm {
+ /* Many other things of course; check <linux/i2c.h>! */
+ u32 (*functionality) (struct i2c_adapter *);
+ }
+
+A typically implementation is given below, from i2c-algo-bit.c:
+
+ static u32 bit_func(struct i2c_adapter *adap)
+ {
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
+ I2C_FUNC_PROTOCOL_MANGLING;
+ }
+
+
+
+CLIENT CHECKING
+---------------
+
+Before a client tries to attach to an adapter, or even do tests to check
+whether one of the devices it supports is present on an adapter, it should
+check whether the needed functionality is present. There are two functions
+defined which should be used instead of calling the functionality hook
+in the algorithm structure directly:
+
+ /* Return the functionality mask */
+ extern u32 i2c_get_functionality (struct i2c_adapter *adap);
+
+ /* Return 1 if adapter supports everything we need, 0 if not. */
+ extern int i2c_check_functionality (struct i2c_adapter *adap, u32 func);
+
+This is a typical way to use these functions (from the writing-clients
+document):
+ int foo_detect_client(struct i2c_adapter *adapter, int address,
+ unsigned short flags, int kind)
+ {
+ /* Define needed variables */
+
+ /* As the very first action, we check whether the adapter has the
+ needed functionality: we need the SMBus read_word_data,
+ write_word_data and write_byte functions in this example. */
+ if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE))
+ goto ERROR0;
+
+ /* Now we can do the real detection */
+
+ ERROR0:
+ /* Return an error */
+ }
+
+
+
+CHECKING THROUGH /DEV
+---------------------
+
+If you try to access an adapter from a userspace program, you will have
+to use the /dev interface. You will still have to check whether the
+functionality you need is supported, of course. This is done using
+the I2C_FUNCS ioctl. An example, adapted from the lm_sensors i2c_detect
+program, is below:
+
+ int file;
+ if (file = open("/dev/i2c-0",O_RDWR) < 0) {
+ /* Some kind of error handling */
+ exit(1);
+ }
+ if (ioctl(file,I2C_FUNCS,&funcs) < 0) {
+ /* Some kind of error handling */
+ exit(1);
+ }
+ if (! (funcs & I2C_FUNC_SMBUS_QUICK)) {
+ /* Oops, the needed functionality (SMBus write_quick function) is
+ not available! */
+ exit(1);
+ }
+ /* Now it is safe to use the SMBus write_quick command */
To use modprobe successfully, you generally place the following
command in your /etc/rc.d/rc.S script. (Read more about this in the
-"rc.hints" file in the module utilities package, "modules-x.y.z.tar.gz".)
+"rc.hints" file in the module utilities package, "modutils-x.y.z.tar.gz".)
/sbin/depmod -a
as part of the Sound Blaster 16 driver (adding only 800 bytes to the
SB16 driver).
-To use an ALS sound card under Linux, enable the following options in the
-sound configuration section of the kernel config:
+To use an ALS sound card under Linux, enable the following options as
+modules in the sound configuration section of the kernel config:
- 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support
- FM synthesizer (YM3812/OPL-3) support
+ - standalone MPU401 support may be required for some cards; for the
+ ALS-007, when using isapnptools, it is required
Since the ALS-007/100/200 are PnP cards, ISAPnP support should probably be
-compiled in.
+compiled in. If kernel level PnP support is not included, isapnptools will
+be required to configure the card before the sound modules are loaded.
-Alternatively, if you decide not to use kernel level ISAPnP, you can use the
-user mode isapnptools to wake up the sound card, as in 2.2.X. Set the "I/O
-base for SB", "Sound Blaster IRQ" and "Sound Blaster DMA" (8 bit -
-either 0, 1 or 3) to the values used in your particular installation (they
-should match the values used to configure the card using isapnp). The
-ALS-007 does NOT implement 16 bit DMA, so the "Sound Blaster 16 bit DMA"
-should be set to -1. If you wish to use the external MPU-401 interface on
-the card, "MPU401 I/O base of SB16" and "SB MPU401 IRQ" should be set to
-the appropriate values for your installation. (Note that the ALS-007
-requires a separate IRQ for the MPU-401, so don't specify -1 here). (Note
-that the base port of the internal FM synth is fixed at 0x388 on the ALS007;
-in any case the FM synth location cannot be set in the kernel configuration).
+When using kernel level ISAPnP, the kernel should correctly identify and
+configure all resources required by the card when the "sb" module is
+inserted. Note that the ALS-007 does not have a 16 bit DMA channel and that
+the MPU401 interface on this card uses a different interrupt to the audio
+section. This should all be correctly configured by the kernel; if problems
+with the MPU401 interface surface, try using the standalone MPU401 module,
+passing "0" as the "sb" module's "mpu_io" module parameter to prevent the
+soundblaster driver attempting to register the MPU401 itself. The onboard
+synth device can be accessed using the "opl3" module.
+
+If isapnptools is used to wake up the sound card (as in 2.2.x), the settings
+of the card's resources should be passed to the kernel modules ("sb", "opl3"
+and "mpu401") using the module parameters. When configuring an ALS-007, be
+sure to specify different IRQs for the audio and MPU401 sections - this card
+requires they be different. For "sb", "io", "irq" and "dma" should be set
+to the same values used to configure the audio section of the card with
+isapnp. "dma16" should be explicitly set to "-1" for an ALS-007 since this
+card does not have a 16 bit dma channel; if not specified the kernel will
+default to using channel 5 anyway which will cause audio not to work.
+"mpu_io" should be set to 0. The "io" parameter of the "opl3" module should
+also agree with the setting used by isapnp. To get the MPU401 interface
+working on an ALS-007 card, the "mpu401" module will be required since this
+card uses separate IRQs for the audio and MPU401 sections and there is no
+parameter available to pass a different IRQ to the "sb" driver (whose
+inbuilt MPU401 driver would otherwise be fine). Insert the mpu401 module
+passing appropriate values using the "io" and "irq" parameters.
The resulting sound driver will provide the following capabilities:
- 8 and 16 bit audio playback
Modified 2000-02-26 by Dave Forrest, drf5n@virginia.edu to add ALS100/ALS200
Modified 2000-04-10 by Paul Laufer, pelaufer@csupomona.edu to add ISAPnP info.
+Modified 2000-11-19 by Jonathan Woithe, jwoithe@physics.adelaide.edu.au
+ - updated information for kernel 2.4.x.
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 0
-EXTRAVERSION = -test13-pre5
+EXTRAVERSION = -test13-pre6
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
# a whole bunch of different types, and allows memory holes and
# everything. We scan through this memory map and build a list
# of the first 32 memory areas, which we return at [E820MAP].
-#
+# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
+
+#define SMAP 0x534d4150
meme820:
- movl $0x534d4150, %edx # ascii `SMAP'
xorl %ebx, %ebx # continuation counter
movw $E820MAP, %di # point into the whitelist
# so we can have the bios
jmpe820:
movl $0x0000e820, %eax # e820, upper word zeroed
+ movl $SMAP, %edx # ascii 'SMAP'
movl $20, %ecx # size of the e820rec
pushw %ds # data record.
popw %es
int $0x15 # make the call
jc bail820 # fall to e801 if it fails
- cmpl $0x534d4150, %eax # check the return is `SMAP'
+ cmpl $SMAP, %eax # check the return is `SMAP'
jne bail820 # fall to e801 if it fails
# cmpl $1, 16(%di) # is this usable memory?
#
# Define implied options from the CPU selection here
#
+
+unset CONFIG_X86_FXSR
+
if [ "$CONFIG_M386" = "y" ]; then
define_bool CONFIG_X86_CMPXCHG n
define_int CONFIG_X86_L1_CACHE_SHIFT 4
define_bool CONFIG_X86_ALIGNMENT_16 y
define_bool CONFIG_X86_TSC y
define_bool CONFIG_X86_USE_PPRO_CHECKSUM y
- define_bool CONFIG_X86_USE_3DNOW y
fi
tristate 'Toshiba Laptop support' CONFIG_TOSHIBA
bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
bool 'Symmetric multi-processing support' CONFIG_SMP
if [ "$CONFIG_SMP" != "y" ]; then
- bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC
- if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then
- define_bool CONFIG_X86_IO_APIC y
- define_bool CONFIG_X86_LOCAL_APIC y
- fi
+ bool 'APIC and IO-APIC support on uniprocessors' CONFIG_X86_UP_IOAPIC
+ if [ "$CONFIG_X86_UP_IOAPIC" = "y" ]; then
+ define_bool CONFIG_X86_IO_APIC y
+ define_bool CONFIG_X86_LOCAL_APIC y
+ fi
fi
if [ "$CONFIG_SMP" = "y" -a "$CONFIG_X86_CMPXCHG" = "y" ]; then
- define_bool CONFIG_HAVE_DEC_LOCK y
+ define_bool CONFIG_HAVE_DEC_LOCK y
fi
endmenu
tristate 'ATA/IDE/MFM/RLL support' CONFIG_IDE
if [ "$CONFIG_IDE" != "n" ]; then
- source drivers/ide/Config.in
+ source drivers/ide/Config.in
else
- define_bool CONFIG_BLK_DEV_IDE_MODES n
- define_bool CONFIG_BLK_DEV_HD n
+ define_bool CONFIG_BLK_DEV_IDE_MODES n
+ define_bool CONFIG_BLK_DEV_HD n
fi
endmenu
obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
- pci-dma.o i386_ksyms.o i387.o bluesmoke.o
+ pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o
ifdef CONFIG_PCI
unsigned long cpu = smp_processor_id();
if (!test_bit(cpu, &flush_cpumask))
- BUG();
+ return;
+ /*
+ * This was a BUG() but until someone can quote me the
+ * line from the intel manual that guarantees an IPI to
+ * multiple CPUs is retried _only_ on the erroring CPUs
+ * its staying as a return
+ *
+ * BUG();
+ */
+
if (flush_mm == cpu_tlbstate[cpu].active_mm) {
if (cpu_tlbstate[cpu].state == TLBSTATE_OK) {
if (flush_va == FLUSH_ALL)
__asm__("mull %2"
:"=a" (eax), "=d" (edx)
- :"g" (fast_gettimeoffset_quotient),
+ :"rm" (fast_gettimeoffset_quotient),
"0" (eax));
/* our adjusted time offset in microseconds */
#define ACPI_OS_NAME "Linux"
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
bool ' Enable 2W RX bursts (optional)' CONFIG_ATM_ENI_BURST_RX_2W
fi
fi
+ tristate 'Fujitsu FireStream (FS50/FS155) ' CONFIG_ATM_FIRESTREAM
tristate 'ZeitNet ZN1221/ZN1225' CONFIG_ATM_ZATM
if [ "$CONFIG_ATM_ZATM" != "n" ]; then
bool ' Enable extended debugging' CONFIG_ATM_ZATM_DEBUG
}
}
- // prevent module unload while sleeping (kmalloc/down)
- // doing this any earlier would complicate more error return paths
- MOD_INC_USE_COUNT;
-
// get space for our vcc stuff
vcc = kmalloc (sizeof(amb_vcc), GFP_KERNEL);
if (!vcc) {
PRINTK (KERN_ERR, "out of memory!");
- MOD_DEC_USE_COUNT;
return -ENOMEM;
}
atm_vcc->dev_data = (void *) vcc;
// say the VPI/VCI is free again
clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
- MOD_DEC_USE_COUNT;
return;
}
close: amb_close,
send: amb_send,
sg_send: amb_sg_send,
- proc_read: amb_proc_read
+ proc_read: amb_proc_read,
+ owner: THIS_MODULE,
};
/********** housekeeping **********/
devs += ia_detect();
#endif
#ifdef CONFIG_ATM_FORE200E
- devs += fore200e_detect();
+ devs += fore200e_detect();
#endif
return devs;
}
static void atmtcp_v_dev_close(struct atm_dev *dev)
{
- MOD_DEC_USE_COUNT;
+ /* Nothing.... Isn't this simple :-) -- REW */
}
close: atmtcp_v_close,
ioctl: atmtcp_v_ioctl,
send: atmtcp_v_send,
- proc_read: atmtcp_v_proc
+ proc_read: atmtcp_v_proc,
+ owner: THIS_MODULE
};
struct atmtcp_dev_data *dev_data;
struct atm_dev *dev;
- MOD_INC_USE_COUNT;
-
dev_data = kmalloc(sizeof(*dev_data),GFP_KERNEL);
- if (!dev_data) {
- MOD_DEC_USE_COUNT;
+ if (!dev_data)
return -ENOMEM;
- }
dev = atm_dev_register(DEV_LABEL,&atmtcp_v_dev_ops,itf,NULL);
if (!dev) {
kfree(dev_data);
- MOD_DEC_USE_COUNT;
return itf == -1 ? -ENOMEM : -EBUSY;
}
dev->ci_range.vpi_bits = MAX_VPI_BITS;
--- /dev/null
+
+/* drivers/atm/firestream.c - FireStream 155 (MB86697) and
+ * FireStream 50 (MB86695) device driver
+ */
+
+/* Written & (C) 2000 by R.E.Wolff@BitWizard.nl
+ * Copied snippets from zatm.c by Werner Almesberger, EPFL LRC/ICA
+ * and ambassador.c Copyright (C) 1995-1999 Madge Networks Ltd
+ */
+
+/*
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian
+ system and in the file COPYING in the Linux kernel source.
+*/
+
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/sonet.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/ioport.h> /* for request_region */
+#include <linux/uio.h>
+#include <linux/init.h>
+#include <linux/capability.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+#include <linux/wait.h>
+
+#include "firestream.h"
+
+static int loopback = 0;
+static int num=0x5a;
+
+/* According to measurements (but they look suspicious to me!) done in
+ * '97, 37% of the packets are one cell in size. So it pays to have
+ * buffers allocated at that size. A large jump in percentage of
+ * packets occurs at packets around 536 bytes in length. So it also
+ * pays to have those pre-allocated. Unfortunately, we can't fully
+ * take advantage of this as the majority of the packets is likely to
+ * be TCP/IP (As where obviously the measurement comes from) There the
+ * link would be opened with say a 1500 byte MTU, and we can't handle
+ * smaller buffers more efficiently than the larger ones. -- REW
+ */
+
+/* Due to the way Linux memory management works, specifying "576" as
+ * an allocation size here isn't going to help. They are allocated
+ * from 1024-byte regions anyway. With the size of the sk_buffs (quite
+ * large), it doesn't pay to allocate the smallest size (64) -- REW */
+
+/* This is all guesswork. Hard numbers to back this up or disprove this,
+ * are appreciated. -- REW */
+
+/* The last entry should be about 64k. However, the "buffer size" is
+ * passed to the chip in a 16 bit field. I don't know how "65536"
+ * would be interpreted. -- REW */
+
+#define NP FS_NR_FREE_POOLS
+int rx_buf_sizes[NP] = {128, 256, 512, 1024, 2048, 4096, 16384, 65520};
+/* log2: 7 8 9 10 11 12 14 16 */
+
+#if 0
+int rx_pool_sizes[NP] = {1024, 1024, 512, 256, 128, 64, 32, 32};
+#else
+/* debug */
+int rx_pool_sizes[NP] = {128, 128, 128, 64, 64, 64, 32, 32};
+#endif
+/* log2: 10 10 9 8 7 6 5 5 */
+/* sumlog2: 17 18 18 18 18 18 19 21 */
+/* mem allocated: 128k 256k 256k 256k 256k 256k 512k 2M */
+/* tot mem: almost 4M */
+
+/* NP is shorter, so that it fits on a single line. */
+#undef NP
+
+
+/* Small hardware gotcha:
+
+ The FS50 CAM (VP/VC match registers) always take the lowest channel
+ number that matches. This is not a problem.
+
+ However, they also ignore wether the channel is enabled or
+ not. This means that if you allocate channel 0 to 1.2 and then
+ channel 1 to 0.0, then disabeling channel 0 and writing 0 to the
+ match channel for channel 0 will "steal" the traffic from channel
+ 1, even if you correctly disable channel 0.
+
+ Workaround:
+
+ - When disabling channels, write an invalid VP/VC value to the
+ match register. (We use 0xffffffff, which in the worst case
+ matches VP/VC = <maxVP>/<maxVC>, but I expect it not to match
+ anything as some "when not in use, program to 0" bits are now
+ programmed to 1...)
+
+ - Don't initialize the match registers to 0, as 0.0 is a valid
+ channel.
+*/
+
+
+/* Optimization hints and tips.
+
+ The FireStream chips are very capable of reducing the amount of
+ "interrupt-traffic" for the CPU. This driver requests an interrupt on EVERY
+ action. You could try to minimize this a bit.
+
+ Besides that, the userspace->kernel copy and the PCI bus are the
+ performance limiting issues for this driver.
+
+ You could queue up a bunch of outgoing packets without telling the
+ FireStream. I'm not sure that's going to win you much though. The
+ Linux layer won't tell us in advance when it's not going to give us
+ any more packets in a while. So this is tricky to implement right without
+ introducing extra delays.
+
+ -- REW
+ */
+
+
+
+
+/* The strings that define what the RX queue entry is all about. */
+/* Fujitsu: Please tell me which ones can have a pointer to a
+ freepool descriptor! */
+static char *res_strings[] = {
+ "RX OK: streaming not EOP",
+ "RX OK: streaming EOP",
+ "RX OK: Single buffer packet",
+ "RX OK: packet mode",
+ "RX OK: F4 OAM (end to end)",
+ "RX OK: F4 OAM (Segment)",
+ "RX OK: F5 OAM (end to end)",
+ "RX OK: F5 OAM (Segment)",
+ "RX OK: RM cell",
+ "RX OK: TRANSP cell",
+ "RX OK: TRANSPC cell",
+ "Unmatched cell",
+ "reserved 12",
+ "reserved 13",
+ "reserved 14",
+ "Unrecognized cell",
+ "reserved 16",
+ "reassemby abort: AAL5 abort",
+ "packet purged",
+ "packet ageing timeout",
+ "channel ageing timeout",
+ "calculated lenght error",
+ "programmed lenght limit error",
+ "aal5 crc32 error",
+ "oam transp or transpc crc10 error",
+ "reserved 25",
+ "reserved 26",
+ "reserved 27",
+ "reserved 28",
+ "reserved 29",
+ "reserved 30",
+ "reassembly abort: no buffers",
+ "receive buffer overflow",
+ "change in GFC",
+ "receive buffer full",
+ "low priority discard - no receive descriptor",
+ "low priority discard - missing end of packet",
+ "reserved 41",
+ "reserved 42",
+ "reserved 43",
+ "reserved 44",
+ "reserved 45",
+ "reserved 46",
+ "reserved 47",
+ "reserved 48",
+ "reserved 49",
+ "reserved 50",
+ "reserved 51",
+ "reserved 52",
+ "reserved 53",
+ "reserved 54",
+ "reserved 55",
+ "reserved 56",
+ "reserved 57",
+ "reserved 58",
+ "reserved 59",
+ "reserved 60",
+ "reserved 61",
+ "reserved 62",
+ "reserved 63",
+};
+
+static char *irq_bitname[] = {
+ "LPCO",
+ "DPCO",
+ "RBRQ0_W",
+ "RBRQ1_W",
+ "RBRQ2_W",
+ "RBRQ3_W",
+ "RBRQ0_NF",
+ "RBRQ1_NF",
+ "RBRQ2_NF",
+ "RBRQ3_NF",
+ "BFP_SC",
+ "INIT",
+ "INIT_ERR",
+ "USCEO",
+ "UPEC0",
+ "VPFCO",
+ "CRCCO",
+ "HECO",
+ "TBRQ_W",
+ "TBRQ_NF",
+ "CTPQ_E",
+ "GFC_C0",
+ "PCI_FTL",
+ "CSQ_W",
+ "CSQ_NF",
+ "EXT_INT",
+ "RXDMA_S"
+};
+
+
+#define PHY_EOF -1
+#define PHY_CLEARALL -2
+
+struct reginit_item {
+ int reg, val;
+};
+
+
+struct reginit_item PHY_NTC_INIT[] __initdata = {
+ { PHY_CLEARALL, 0x40 },
+ { 0x12, 0x0001 },
+ { 0x13, 0x7605 },
+ { 0x1A, 0x0001 },
+ { 0x1B, 0x0005 },
+ { 0x38, 0x0003 },
+ { 0x39, 0x0006 }, /* changed here to make loopback */
+ { 0x01, 0x5262 },
+ { 0x15, 0x0213 },
+ { 0x00, 0x0003 },
+ { PHY_EOF, 0}, /* -1 signals end of list */
+};
+
+
+/* Safetyfeature: If the card interrupts more than this number of times
+ in a jiffy (1/100th of a second) then we just disable the interrupt and
+ print a message. This prevents the system from hanging.
+
+ 150000 packets per second is close to the limit a PC is going to have
+ anyway. We therefore have to disable this for production. -- REW */
+#undef IRQ_RATE_LIMIT 100
+
+/* Interrupts work now. Unlike serial cards, ATM cards don't work all
+ that great without interrupts. -- REW */
+#undef FS_POLL_FREQ 100
+
+/*
+ This driver can spew a whole lot of debugging output at you. If you
+ need maximum performance, you should disable the DEBUG define. To
+ aid in debugging in the field, I'm leaving the compile-time debug
+ features enabled, and disable them "runtime". That allows me to
+ instruct people with problems to enable debugging without requiring
+ them to recompile... -- REW
+*/
+#define DEBUG
+
+#ifdef DEBUG
+#define fs_dprintk(f, str...) if (fs_debug & f) printk (str)
+#else
+#define fs_dprintk(f, str...) /* nothing */
+#endif
+
+
+#ifdef DEBUG
+/* I didn't forget to set this to zero before shipping. Hit me with a stick
+ if you get this with the debug default not set to zero again. -- REW */
+static int fs_debug = 0;
+#else
+#define fs_debug 0
+#endif
+
+#ifdef MODULE
+#ifdef DEBUG
+MODULE_PARM(fs_debug, "i");
+#endif
+MODULE_PARM(loopback, "i");
+MODULE_PARM(num, "i");
+/* XXX Add rx_buf_sizes, and rx_pool_sizes As per request Amar. -- REW */
+#endif
+
+
+#define FS_DEBUG_FLOW 0x00000001
+#define FS_DEBUG_OPEN 0x00000002
+#define FS_DEBUG_QUEUE 0x00000004
+#define FS_DEBUG_IRQ 0x00000008
+#define FS_DEBUG_INIT 0x00000010
+#define FS_DEBUG_SEND 0x00000020
+#define FS_DEBUG_PHY 0x00000040
+#define FS_DEBUG_CLEANUP 0x00000080
+#define FS_DEBUG_QOS 0x00000100
+#define FS_DEBUG_TXQ 0x00000200
+#define FS_DEBUG_ALLOC 0x00000400
+#define FS_DEBUG_TXMEM 0x00000800
+#define FS_DEBUG_QSIZE 0x00001000
+
+
+#define func_enter() fs_dprintk (FS_DEBUG_FLOW, "fs: enter " __FUNCTION__ "\n")
+#define func_exit() fs_dprintk (FS_DEBUG_FLOW, "fs: exit " __FUNCTION__ "\n")
+
+
+struct fs_dev *fs_boards = NULL;
+
+#ifdef DEBUG
+
+static void my_hd (void *addr, int len)
+{
+ int j, ch;
+ unsigned char *ptr = addr;
+
+ while (len > 0) {
+ printk ("%p ", ptr);
+ for (j=0;j < ((len < 16)?len:16);j++) {
+ printk ("%02x %s", ptr[j], (j==7)?" ":"");
+ }
+ for ( ;j < 16;j++) {
+ printk (" %s", (j==7)?" ":"");
+ }
+ for (j=0;j < ((len < 16)?len:16);j++) {
+ ch = ptr[j];
+ printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ }
+ printk ("\n");
+ ptr += 16;
+ len -= 16;
+ }
+}
+#else /* DEBUG */
+static void my_hd (void *addr, int len){}
+#endif /* DEBUG */
+
+/********** free an skb (as per ATM device driver documentation) **********/
+
+/* Hmm. If this is ATM specific, why isn't there an ATM routine for this?
+ * I copied it over from the ambassador driver. -- REW */
+
+static inline void fs_kfree_skb (struct sk_buff * skb)
+{
+ if (ATM_SKB(skb)->vcc->pop)
+ ATM_SKB(skb)->vcc->pop (ATM_SKB(skb)->vcc, skb);
+ else
+ dev_kfree_skb_any (skb);
+}
+
+
+
+
+/* It seems the ATM forum recomends this horribly complicated 16bit
+ * floating point format. Turns out the Ambassador uses the exact same
+ * encoding. I just copied it over. If Mitch agrees, I'll move it over
+ * to the atm_misc file or something like that. (and remove it from
+ * here and the ambassador driver) -- REW
+ */
+
+/* The good thing about this format is that it is monotonic. So,
+ a conversion routine need not be very complicated. To be able to
+ round "nearest" we need to take along a few extra bits. Lets
+ put these after 16 bits, so that we can just return the top 16
+ bits of the 32bit number as the result:
+
+ int mr (unsigned int rate, int r)
+ {
+ int e = 16+9;
+ static int round[4]={0, 0, 0xffff, 0x8000};
+ if (!rate) return 0;
+ while (rate & 0xfc000000) {
+ rate >>= 1;
+ e++;
+ }
+ while (! (rate & 0xfe000000)) {
+ rate <<= 1;
+ e--;
+ }
+
+// Now the mantissa is in positions bit 16-25. Excepf for the "hidden 1" that's in bit 26.
+ rate &= ~0x02000000;
+// Next add in the exponent
+ rate |= e << (16+9);
+// And perform the rounding:
+ return (rate + round[r]) >> 16;
+ }
+
+ 14 lines-of-code. Compare that with the 120 that the Ambassador
+ guys needed. (would be 8 lines shorter if I'd try to really reduce
+ the number of lines:
+
+ int mr (unsigned int rate, int r)
+ {
+ int e = 16+9;
+ static int round[4]={0, 0, 0xffff, 0x8000};
+ if (!rate) return 0;
+ for (; rate & 0xfc000000 ;rate >>= 1, e++);
+ for (;!(rate & 0xfe000000);rate <<= 1, e--);
+ return ((rate & ~0x02000000) | (e << (16+9)) + round[r]) >> 16;
+ }
+
+ Exercise for the reader: Remove one more line-of-code, without
+ cheating. (Just joining two lines is cheating). (I know it's
+ possible, don't think you've beat me if you found it... If you
+ manage to lose two lines or more, keep me updated! ;-)
+
+ -- REW */
+
+
+#define ROUND_UP 1
+#define ROUND_DOWN 2
+#define ROUND_NEAREST 3
+/********** make rate (not quite as much fun as Horizon) **********/
+
+static unsigned int make_rate (unsigned int rate, int r,
+ u16 * bits, unsigned int * actual)
+{
+ unsigned char exp = -1; /* hush gcc */
+ unsigned int man = -1; /* hush gcc */
+
+ fs_dprintk (FS_DEBUG_QOS, "make_rate %u", rate);
+
+ /* rates in cells per second, ITU format (nasty 16-bit floating-point)
+ given 5-bit e and 9-bit m:
+ rate = EITHER (1+m/2^9)*2^e OR 0
+ bits = EITHER 1<<14 | e<<9 | m OR 0
+ (bit 15 is "reserved", bit 14 "non-zero")
+ smallest rate is 0 (special representation)
+ largest rate is (1+511/512)*2^31 = 4290772992 (< 2^32-1)
+ smallest non-zero rate is (1+0/512)*2^0 = 1 (> 0)
+ simple algorithm:
+ find position of top bit, this gives e
+ remove top bit and shift (rounding if feeling clever) by 9-e
+ */
+ /* Ambassador ucode bug: please don't set bit 14! so 0 rate not
+ representable. // This should move into the ambassador driver
+ when properly merged. -- REW */
+
+ if (rate > 0xffc00000U) {
+ /* larger than largest representable rate */
+
+ if (r == ROUND_UP) {
+ return -EINVAL;
+ } else {
+ exp = 31;
+ man = 511;
+ }
+
+ } else if (rate) {
+ /* representable rate */
+
+ exp = 31;
+ man = rate;
+
+ /* invariant: rate = man*2^(exp-31) */
+ while (!(man & (1<<31))) {
+ exp = exp - 1;
+ man = man<<1;
+ }
+
+ /* man has top bit set
+ rate = (2^31+(man-2^31))*2^(exp-31)
+ rate = (1+(man-2^31)/2^31)*2^exp
+ */
+ man = man<<1;
+ man &= 0xffffffffU; /* a nop on 32-bit systems */
+ /* rate = (1+man/2^32)*2^exp
+
+ exp is in the range 0 to 31, man is in the range 0 to 2^32-1
+ time to lose significance... we want m in the range 0 to 2^9-1
+ rounding presents a minor problem... we first decide which way
+ we are rounding (based on given rounding direction and possibly
+ the bits of the mantissa that are to be discarded).
+ */
+
+ switch (r) {
+ case ROUND_DOWN: {
+ /* just truncate */
+ man = man>>(32-9);
+ break;
+ }
+ case ROUND_UP: {
+ /* check all bits that we are discarding */
+ if (man & (-1>>9)) {
+ man = (man>>(32-9)) + 1;
+ if (man == (1<<9)) {
+ /* no need to check for round up outside of range */
+ man = 0;
+ exp += 1;
+ }
+ } else {
+ man = (man>>(32-9));
+ }
+ break;
+ }
+ case ROUND_NEAREST: {
+ /* check msb that we are discarding */
+ if (man & (1<<(32-9-1))) {
+ man = (man>>(32-9)) + 1;
+ if (man == (1<<9)) {
+ /* no need to check for round up outside of range */
+ man = 0;
+ exp += 1;
+ }
+ } else {
+ man = (man>>(32-9));
+ }
+ break;
+ }
+ }
+
+ } else {
+ /* zero rate - not representable */
+
+ if (r == ROUND_DOWN) {
+ return -EINVAL;
+ } else {
+ exp = 0;
+ man = 0;
+ }
+ }
+
+ fs_dprintk (FS_DEBUG_QOS, "rate: man=%u, exp=%hu", man, exp);
+
+ if (bits)
+ *bits = /* (1<<14) | */ (exp<<9) | man;
+
+ if (actual)
+ *actual = (exp >= 9)
+ ? (1 << exp) + (man << (exp-9))
+ : (1 << exp) + ((man + (1<<(9-exp-1))) >> (9-exp));
+
+ return 0;
+}
+
+
+
+
+/* FireStream access routines */
+/* For DEEP-DOWN debugging these can be rigged to intercept accesses to
+ certain registers or to just log all accesses. */
+
+static inline void write_fs (struct fs_dev *dev, int offset, u32 val)
+{
+ writel (val, dev->base + offset);
+}
+
+
+static inline u32 read_fs (struct fs_dev *dev, int offset)
+{
+ return readl (dev->base + offset);
+}
+
+
+
+static inline struct FS_QENTRY *get_qentry (struct fs_dev *dev, struct queue *q)
+{
+ return bus_to_virt (read_fs (dev, Q_WP(q->offset)) & Q_ADDR_MASK);
+}
+
+
+static void submit_qentry (struct fs_dev *dev, struct queue *q, struct FS_QENTRY *qe)
+{
+ u32 wp;
+ struct FS_QENTRY *cqe;
+
+ /* XXX Sanity check: the write pointer can be checked to be
+ still the same as the value passed as qe... -- REW */
+ /* udelay (5); */
+ while ((wp = read_fs (dev, Q_WP (q->offset))) & Q_FULL) {
+ fs_dprintk (FS_DEBUG_TXQ, "Found queue at %x full. Waiting.\n",
+ q->offset);
+ schedule ();
+ }
+
+ wp &= ~0xf;
+ cqe = bus_to_virt (wp);
+ if (qe != cqe) {
+ fs_dprintk (FS_DEBUG_TXQ, "q mismatch! %p %p\n", qe, cqe);
+ }
+
+ write_fs (dev, Q_WP(q->offset), Q_INCWRAP);
+
+ {
+ static int c;
+ if (!(c++ % 100))
+ {
+ int rp, wp;
+ rp = read_fs (dev, Q_RP(q->offset));
+ wp = read_fs (dev, Q_WP(q->offset));
+ fs_dprintk (FS_DEBUG_TXQ, "q at %d: %x-%x: %x entries.\n",
+ q->offset, rp, wp, wp-rp);
+ }
+ }
+}
+
+#ifdef DEBUG_EXTRA
+static struct FS_QENTRY pq[60];
+static int qp;
+
+static struct FS_BPENTRY dq[60];
+static int qd;
+static void *da[60];
+#endif
+
+static void submit_queue (struct fs_dev *dev, struct queue *q,
+ u32 cmd, u32 p1, u32 p2, u32 p3)
+{
+ struct FS_QENTRY *qe;
+
+ qe = get_qentry (dev, q);
+ qe->cmd = cmd;
+ qe->p0 = p1;
+ qe->p1 = p2;
+ qe->p2 = p3;
+ submit_qentry (dev, q, qe);
+
+#ifdef DEBUG_EXTRA
+ pq[qp].cmd = cmd;
+ pq[qp].p0 = p1;
+ pq[qp].p1 = p2;
+ pq[qp].p2 = p3;
+ qp++;
+ if (qp >= 60) qp = 0;
+#endif
+}
+
+/* Test the "other" way one day... -- REW */
+#if 1
+#define submit_command submit_queue
+#else
+
+static void submit_command (struct fs_dev *dev, struct queue *q,
+ u32 cmd, u32 p1, u32 p2, u32 p3)
+{
+ write_fs (dev, CMDR0, cmd);
+ write_fs (dev, CMDR1, p1);
+ write_fs (dev, CMDR2, p2);
+ write_fs (dev, CMDR3, p3);
+}
+#endif
+
+
+
+static void process_return_queue (struct fs_dev *dev, struct queue *q)
+{
+ long rq;
+ struct FS_QENTRY *qe;
+ void *tc;
+
+ while (!((rq = read_fs (dev, Q_RP(q->offset))) & Q_EMPTY)) {
+ fs_dprintk (FS_DEBUG_QUEUE, "reaping return queue entry at %lx\n", rq);
+ qe = bus_to_virt (rq);
+
+ fs_dprintk (FS_DEBUG_QUEUE, "queue entry: %08x %08x %08x %08x. (%d)\n",
+ qe->cmd, qe->p0, qe->p1, qe->p2, STATUS_CODE (qe));
+
+ switch (STATUS_CODE (qe)) {
+ case 5:
+ tc = bus_to_virt (qe->p0);
+ fs_dprintk (FS_DEBUG_ALLOC, "Free tc: %p\n", tc);
+ kfree (tc);
+ break;
+ }
+
+ write_fs (dev, Q_RP(q->offset), Q_INCWRAP);
+ }
+}
+
+
+static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
+{
+ long rq;
+ long tmp;
+ struct FS_QENTRY *qe;
+ struct sk_buff *skb;
+ struct FS_BPENTRY *td;
+
+ while (!((rq = read_fs (dev, Q_RP(q->offset))) & Q_EMPTY)) {
+ fs_dprintk (FS_DEBUG_QUEUE, "reaping txdone entry at %lx\n", rq);
+ qe = bus_to_virt (rq);
+
+ fs_dprintk (FS_DEBUG_QUEUE, "queue entry: %08x %08x %08x %08x: %d\n",
+ qe->cmd, qe->p0, qe->p1, qe->p2, STATUS_CODE (qe));
+
+ if (STATUS_CODE (qe) != 2)
+ fs_dprintk (FS_DEBUG_TXMEM, "queue entry: %08x %08x %08x %08x: %d\n",
+ qe->cmd, qe->p0, qe->p1, qe->p2, STATUS_CODE (qe));
+
+
+ switch (STATUS_CODE (qe)) {
+ case 0x02:
+ /* Process a real txdone entry. */
+ tmp = qe->p0;
+ if (tmp & 0x0f)
+ printk (KERN_WARNING "td not aligned: %ld\n", tmp);
+ tmp &= ~0x0f;
+ td = bus_to_virt (tmp);
+
+ fs_dprintk (FS_DEBUG_QUEUE, "Pool entry: %08x %08x %08x %08x %p.\n",
+ td->flags, td->next, td->bsa, td->aal_bufsize, td->skb );
+
+ skb = td->skb;
+ if (skb == FS_VCC (ATM_SKB(skb)->vcc)->last_skb) {
+ wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait);
+ FS_VCC (ATM_SKB(skb)->vcc)->last_skb = NULL;
+ }
+ td->dev->ntxpckts--;
+
+ {
+ static int c=0;
+
+ if (!(c++ % 100)) {
+ fs_dprintk (FS_DEBUG_QSIZE, "[%d]", td->dev->ntxpckts);
+ }
+ }
+
+ atomic_inc(&ATM_SKB(skb)->vcc->stats->tx);
+
+ fs_dprintk (FS_DEBUG_TXMEM, "i");
+ fs_dprintk (FS_DEBUG_ALLOC, "Free t-skb: %p\n", skb);
+ fs_kfree_skb (skb);
+
+ fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td);
+ memset (td, 0x12, sizeof (struct FS_BPENTRY));
+ kfree (td);
+ break;
+ default:
+ /* Here we get the tx purge inhibit command ... */
+ /* Action, I believe, is "don't do anything". -- REW */
+ }
+
+ write_fs (dev, Q_RP(q->offset), Q_INCWRAP);
+ }
+}
+
+
+static void process_incoming (struct fs_dev *dev, struct queue *q)
+{
+ long rq;
+ struct FS_QENTRY *qe;
+ struct FS_BPENTRY *pe;
+ struct sk_buff *skb;
+ unsigned int channo;
+ struct atm_vcc *atm_vcc;
+
+ while (!((rq = read_fs (dev, Q_RP(q->offset))) & Q_EMPTY)) {
+ fs_dprintk (FS_DEBUG_QUEUE, "reaping incoming queue entry at %lx\n", rq);
+ qe = bus_to_virt (rq);
+
+ fs_dprintk (FS_DEBUG_QUEUE, "queue entry: %08x %08x %08x %08x. ",
+ qe->cmd, qe->p0, qe->p1, qe->p2);
+
+ fs_dprintk (FS_DEBUG_QUEUE, "-> %x: %s\n",
+ STATUS_CODE (qe),
+ res_strings[STATUS_CODE(qe)]);
+
+ pe = bus_to_virt (qe->p0);
+ fs_dprintk (FS_DEBUG_QUEUE, "Pool entry: %08x %08x %08x %08x %p %p.\n",
+ pe->flags, pe->next, pe->bsa, pe->aal_bufsize,
+ pe->skb, pe->fp);
+
+ channo = qe->cmd & 0xffff;
+
+ if (channo < dev->nchannels)
+ atm_vcc = dev->atm_vccs[channo];
+ else
+ atm_vcc = NULL;
+
+ /* Single buffer packet */
+ switch (STATUS_CODE (qe)) {
+ case 0x2:/* Packet received OK.... */
+ if (atm_vcc) {
+ skb = pe->skb;
+ pe->fp->n--;
+#if 0
+ fs_dprintk (FS_DEBUG_QUEUE, "Got skb: %p\n", skb);
+ if (FS_DEBUG_QUEUE & fs_debug) my_hd (bus_to_virt (pe->bsa), 0x20);
+#endif
+ skb_put (skb, qe->p1 & 0xffff);
+ ATM_SKB(skb)->vcc = atm_vcc;
+ atomic_inc(&atm_vcc->stats->rx);
+ skb->stamp = xtime;
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p (pushed)\n", skb);
+ atm_vcc->push (atm_vcc, skb);
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", pe);
+ kfree (pe);
+ } else {
+ printk (KERN_ERR "Got a receive on a non-open channel %d.\n", channo);
+ }
+ break;
+ case 0x17:/* AAL 5 CRC32 error. IFF the length field is nonzero, a buffer
+ has been consumed and needs to be processed. -- REW */
+ if (qe->p1 & 0xffff) {
+ pe = bus_to_virt (qe->p0);
+ pe->fp->n--;
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", pe->skb);
+ dev_kfree_skb_any (pe->skb);
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", pe);
+ kfree (pe);
+ }
+ if (atm_vcc)
+ atomic_inc(&atm_vcc->stats->rx_drop);
+ break;
+ case 0x1f: /* Reassembly abort: no buffers. */
+ /* Silently increment error counter. */
+ if (atm_vcc)
+ atomic_inc(&atm_vcc->stats->rx_drop);
+ break;
+ default: /* Hmm. Haven't written the code to handle the others yet... -- REW */
+ printk (KERN_WARNING "Don't know what to do with RX status %x: %s.\n",
+ STATUS_CODE(qe), res_strings[STATUS_CODE (qe)]);
+ }
+ write_fs (dev, Q_RP(q->offset), Q_INCWRAP);
+ }
+}
+
+
+
+#define DO_DIRECTION(tp) ((tp)->traffic_class != ATM_NONE)
+
+static int fs_open(struct atm_vcc *atm_vcc, short vpi, int vci)
+{
+ struct fs_dev *dev;
+ struct fs_vcc *vcc;
+ struct fs_transmit_config *tc;
+ struct atm_trafprm * txtp;
+ struct atm_trafprm * rxtp;
+ /* struct fs_receive_config *rc;*/
+ /* struct FS_QENTRY *qe; */
+ int error;
+ int bfp;
+ int to;
+ unsigned short tmc0;
+
+ func_enter ();
+
+ dev = FS_DEV(atm_vcc->dev);
+ fs_dprintk (FS_DEBUG_OPEN, "fs: open on dev: %p, vcc at %p\n",
+ dev, atm_vcc);
+
+ error = atm_find_ci(atm_vcc, &vpi, &vci);
+ if (error) {
+ fs_dprintk (FS_DEBUG_OPEN, "fs: find_ci failed.\n");
+ return error;
+ }
+
+ atm_vcc->vpi = vpi;
+ atm_vcc->vci = vci;
+ if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
+ set_bit(ATM_VF_ADDR, &atm_vcc->flags);
+
+ if (atm_vcc->qos.aal != ATM_AAL5) return -EINVAL; /* XXX AAL0 */
+
+ fs_dprintk (FS_DEBUG_OPEN, "fs: (itf %d): open %d.%d\n",
+ atm_vcc->dev->number, atm_vcc->vpi, atm_vcc->vci);
+
+ /* XXX handle qos parameters (rate limiting) ? */
+
+ vcc = kmalloc(sizeof(struct fs_vcc), GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc VCC: %p(%d)\n", vcc, sizeof(struct fs_vcc));
+ if (!vcc) {
+ clear_bit(ATM_VF_ADDR, &atm_vcc->flags);
+ return -ENOMEM;
+ }
+
+ atm_vcc->dev_data = vcc;
+ vcc->last_skb = NULL;
+
+ init_waitqueue_head (&vcc->close_wait);
+
+ txtp = &atm_vcc->qos.txtp;
+ rxtp = &atm_vcc->qos.rxtp;
+
+ if (!test_bit(ATM_VF_PARTIAL, &atm_vcc->flags)) {
+ if (IS_FS50(dev)) {
+ /* Increment the channel numer: take a free one next time. */
+ for (to=33;to;to--, dev->channo++) {
+ /* If we need to do RX, AND the RX is inuse, try the next */
+ if (DO_DIRECTION(rxtp) && dev->atm_vccs[dev->channo])
+ continue;
+ /* If we need to do TX, AND the TX is inuse, try the next */
+ if (DO_DIRECTION(txtp) && test_bit (dev->channo, dev->tx_inuse))
+ continue;
+ /* Ok, both are free! (or not needed) */
+ break;
+ }
+ if (!to) {
+ printk ("No more free channels for FS50..\n");
+ return -EBUSY;
+ }
+ vcc->channo = dev->channo;
+ dev->channo &= dev->channel_mask;
+
+ } else {
+ vcc->channo = (vpi << FS155_VCI_BITS) | (vci);
+ if (((DO_DIRECTION(rxtp) && dev->atm_vccs[vcc->channo])) ||
+ ( DO_DIRECTION(txtp) && test_bit (vcc->channo, dev->tx_inuse))) {
+ printk ("Channel is in use for FS155.\n");
+ return -EBUSY;
+ }
+ }
+ fs_dprintk (FS_DEBUG_OPEN, "OK. Allocated channel %x(%d).\n",
+ vcc->channo, vcc->channo);
+ }
+
+ if (DO_DIRECTION (txtp)) {
+ tc = kmalloc (sizeof (struct fs_transmit_config), GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc tc: %p(%d)\n",
+ tc, sizeof (struct fs_transmit_config));
+ if (!tc) {
+ fs_dprintk (FS_DEBUG_OPEN, "fs: can't alloc transmit_config.\n");
+ return -ENOMEM;
+ }
+
+ /* Allocate the "open" entry from the high priority txq. This makes
+ it most likely that the chip will notice it. It also prevents us
+ from having to wait for completion. On the other hand, we may
+ need to wait for completion anyway, to see if it completed
+ succesfully. */
+
+ tc->flags = 0
+ | TC_FLAGS_AAL5
+ | TC_FLAGS_PACKET /* ??? */
+ | TC_FLAGS_TYPE_CBR
+ | TC_FLAGS_CAL0;
+
+ /* Docs are vague about this atm_hdr field. By the way, the FS
+ * chip makes odd errors if lower bits are set.... -- REW */
+ tc->atm_hdr = (vpi << 20) | (vci << 4);
+ {
+ int pcr = atm_pcr_goal (txtp);
+
+ fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr);
+
+ /* XXX Hmm. officially we're only allowed to do this if rounding
+ is round_down -- REW */
+ if (IS_FS50(dev)) {
+ if (pcr > 51840000/53/8) pcr = 51840000/53/8;
+ } else {
+ if (pcr > 155520000/53/8) pcr = 155520000/53/8;
+ }
+ if (!pcr) {
+ /* no rate cap */
+ tmc0 = IS_FS50(dev)?0x61BE:0x64c9; /* Just copied over the bits from Fujitsu -- REW */
+ } else {
+ int r;
+ if (pcr < 0) {
+ r = ROUND_DOWN;
+ pcr = -pcr;
+ } else {
+ r = ROUND_UP;
+ }
+ error = make_rate (pcr, r, &tmc0, 0);
+ }
+ fs_dprintk (FS_DEBUG_OPEN, "pcr = %d.\n", pcr);
+ }
+
+ tc->TMC[0] = tmc0 | 0x4000;
+ tc->TMC[1] = 0; /* Unused */
+ tc->TMC[2] = 0; /* Unused */
+ tc->TMC[3] = 0; /* Unused */
+
+ tc->spec = 0; /* UTOPIA address, UDF, HEC: Unused -> 0 */
+ tc->rtag[0] = 0; /* What should I do with routing tags???
+ -- Not used -- AS -- Thanks -- REW*/
+ tc->rtag[1] = 0;
+ tc->rtag[2] = 0;
+
+ if (fs_debug & FS_DEBUG_OPEN) {
+ fs_dprintk (FS_DEBUG_OPEN, "TX config record:\n");
+ my_hd (tc, sizeof (*tc));
+ }
+
+ /* We now use the "submit_command" function to submit commands to
+ the firestream. There is a define up near the definition of
+ that routine that switches this routine between immediate write
+ to the immediate comamnd registers and queuing the commands in
+ the HPTXQ for execution. This last technique might be more
+ efficient if we know we're going to submit a whole lot of
+ commands in one go, but this driver is not setup to be able to
+ use such a construct. So it probably doen't matter much right
+ now. -- REW */
+
+ /* The command is IMMediate and INQueue. The parameters are out-of-line.. */
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_CONFIG_TX | QE_CMD_IMM_INQ | vcc->channo,
+ virt_to_bus (tc), 0, 0);
+
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_TX_EN | QE_CMD_IMM_INQ | vcc->channo,
+ 0, 0, 0);
+ set_bit (vcc->channo, dev->tx_inuse);
+ }
+
+ if (DO_DIRECTION (rxtp)) {
+ dev->atm_vccs[vcc->channo] = atm_vcc;
+
+ for (bfp = 0;bfp < FS_NR_FREE_POOLS; bfp++)
+ if (atm_vcc->qos.rxtp.max_sdu <= dev->rx_fp[bfp].bufsize) break;
+
+ if (bfp >= FS_NR_FREE_POOLS) {
+ fs_dprintk (FS_DEBUG_OPEN, "No free pool fits sdu: %d.\n",
+ atm_vcc->qos.rxtp.max_sdu);
+ /* XXX Cleanup? -- Would just calling fs_close work??? -- REW */
+
+ /* XXX clear tx inuse. Close TX part? */
+ dev->atm_vccs[vcc->channo] = NULL;
+ kfree (vcc);
+ return -EINVAL;
+ }
+
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_CONFIG_RX | QE_CMD_IMM_INQ | vcc->channo,
+ RC_FLAGS_AAL5 |
+ RC_FLAGS_BFPS_BFP * bfp |
+ RC_FLAGS_RXBM_PSB, 0, 0);
+
+ if (IS_FS50 (dev)) {
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_REG_WR | QE_CMD_IMM_INQ,
+ 0x80 + vcc->channo,
+ (vpi << 16) | vci, 0 ); /* XXX -- Use defines. */
+ }
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_RX_EN | QE_CMD_IMM_INQ | vcc->channo,
+ 0, 0, 0);
+ }
+
+ /* Indicate we're done! */
+ set_bit(ATM_VF_READY, &atm_vcc->flags);
+
+ func_exit ();
+ return 0;
+}
+
+
+static void fs_close(struct atm_vcc *atm_vcc)
+{
+ struct fs_dev *dev = FS_DEV (atm_vcc->dev);
+ struct fs_vcc *vcc = FS_VCC (atm_vcc);
+ struct atm_trafprm * txtp;
+ struct atm_trafprm * rxtp;
+
+ func_enter ();
+
+ clear_bit(ATM_VF_READY, &atm_vcc->flags);
+
+ fs_dprintk (FS_DEBUG_QSIZE, "--==**[%d]**==--", dev->ntxpckts);
+ if (vcc->last_skb) {
+ fs_dprintk (FS_DEBUG_QUEUE, "Waiting for skb %p to be sent.\n",
+ vcc->last_skb);
+ /* We're going to wait for the last packet to get sent on this VC. It would
+ be impolite not to send them don't you think?
+ XXX
+ We don't know which packets didn't get sent. So if we get interrupted in
+ this sleep_on, we'll lose any reference to these packets. Memory leak!
+ On the other hand, it's awfully convenient that we can abort a "close" that
+ is taking too long. Maybe just use non-interruptible sleep on? -- REW */
+ interruptible_sleep_on (& vcc->close_wait);
+ }
+
+ txtp = &atm_vcc->qos.txtp;
+ rxtp = &atm_vcc->qos.rxtp;
+
+
+ /* See App note XXX (Unpublished as of now) for the reason for the
+ removal of the "CMD_IMM_INQ" part of the TX_PURGE_INH... -- REW */
+
+ if (DO_DIRECTION (txtp)) {
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_TX_PURGE_INH | /*QE_CMD_IMM_INQ|*/ vcc->channo, 0,0,0);
+ clear_bit (vcc->channo, dev->tx_inuse);
+ }
+
+ if (DO_DIRECTION (rxtp)) {
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_RX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0);
+ dev->atm_vccs [vcc->channo] = NULL;
+
+ /* This means that this is configured as a receive channel */
+ if (IS_FS50 (dev)) {
+ /* Disable the receive filter. Is 0/0 indeed an invalid receive
+ channel? -- REW. Yes it is. -- Hang. Ok. I'll use -1
+ (0xfff...) -- REW */
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_REG_WR | QE_CMD_IMM_INQ,
+ 0x80 + vcc->channo, -1, 0 );
+ }
+ }
+
+ fs_dprintk (FS_DEBUG_ALLOC, "Free vcc: %p\n", vcc);
+ kfree (vcc);
+
+ func_exit ();
+}
+
+
+static int fs_send (struct atm_vcc *atm_vcc, struct sk_buff *skb)
+{
+ struct fs_dev *dev = FS_DEV (atm_vcc->dev);
+ struct fs_vcc *vcc = FS_VCC (atm_vcc);
+ struct FS_BPENTRY *td;
+
+ func_enter ();
+
+ fs_dprintk (FS_DEBUG_TXMEM, "I");
+ fs_dprintk (FS_DEBUG_SEND, "Send: atm_vcc %p skb %p vcc %p dev %p\n",
+ atm_vcc, skb, vcc, dev);
+
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc t-skb: %p (atm_send)\n", skb);
+
+ ATM_SKB(skb)->vcc = atm_vcc;
+
+ vcc->last_skb = skb;
+
+ td = kmalloc (sizeof (struct FS_BPENTRY), GFP_ATOMIC);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc transd: %p(%d)\n", td, sizeof (struct FS_BPENTRY));
+ if (!td) {
+ /* Oops out of mem */
+ return -ENOMEM;
+ }
+
+ fs_dprintk (FS_DEBUG_SEND, "first word in buffer: %x\n",
+ *(int *) skb->data);
+
+ td->flags = TD_EPI | TD_DATA | skb->len;
+ td->next = 0;
+ td->bsa = virt_to_bus (skb->data);
+ td->skb = skb;
+ td->dev = dev;
+ dev->ntxpckts++;
+
+#ifdef DEBUG_EXTRA
+ da[qd] = td;
+ dq[qd].flags = td->flags;
+ dq[qd].next = td->next;
+ dq[qd].bsa = td->bsa;
+ dq[qd].skb = td->skb;
+ dq[qd].dev = td->dev;
+ qd++;
+ if (qd >= 60) qd = 0;
+#endif
+
+ submit_queue (dev, &dev->hp_txq,
+ QE_TRANSMIT_DE | vcc->channo,
+ virt_to_bus (td), 0,
+ virt_to_bus (td));
+
+ fs_dprintk (FS_DEBUG_QUEUE, "in send: txq %d txrq %d\n",
+ read_fs (dev, Q_EA (dev->hp_txq.offset)) -
+ read_fs (dev, Q_SA (dev->hp_txq.offset)),
+ read_fs (dev, Q_EA (dev->tx_relq.offset)) -
+ read_fs (dev, Q_SA (dev->tx_relq.offset)));
+
+ func_exit ();
+ return 0;
+}
+
+
+/* Some function placeholders for functions we don't yet support. */
+
+#if 0
+static int fs_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
+{
+ func_enter ();
+ func_exit ();
+ return 0;
+}
+
+
+static int fs_getsockopt(struct atm_vcc *vcc,int level,int optname,
+ void *optval,int optlen)
+{
+ func_enter ();
+ func_exit ();
+ return 0;
+}
+
+
+static int fs_setsockopt(struct atm_vcc *vcc,int level,int optname,
+ void *optval,int optlen)
+{
+ func_enter ();
+ func_exit ();
+ return 0;
+}
+
+
+static void fs_phy_put(struct atm_dev *dev,unsigned char value,
+ unsigned long addr)
+{
+ func_enter ();
+ func_exit ();
+}
+
+
+static unsigned char fs_phy_get(struct atm_dev *dev,unsigned long addr)
+{
+ func_enter ();
+ func_exit ();
+ return 0;
+}
+
+
+static void fs_feedback(struct atm_vcc *vcc,struct sk_buff *skb,
+ unsigned long start,unsigned long dest,int len)
+{
+ func_enter ();
+ func_exit ();
+}
+
+
+static int fs_change_qos(struct atm_vcc *vcc,struct atm_qos *qos,int flags)
+{
+ func_enter ();
+ func_exit ();
+ return 0;
+};
+
+#endif
+
+
+static const struct atmdev_ops ops = {
+ open: fs_open,
+ close: fs_close,
+ send: fs_send,
+#if 0
+ owner: THIS_MODULE,
+#endif
+ /* fs_sg_send */
+ /* ioctl: fs_ioctl, */
+ /* getsockopt: fs_getsockopt, */
+ /* setsockopt: fs_setsockopt, */
+ /* feedback: fs_feedback, */
+ /* change_qos: fs_change_qos, */
+
+ /* For now implement these internally here... */
+ /* phy_put: fs_phy_put, */
+ /* phy_get: fs_phy_get, */
+};
+
+
+static void __init undocumented_pci_fix (struct pci_dev *pdev)
+{
+ int tint;
+
+ /* The Windows driver says: */
+ /* Switch off FireStream Retry Limit Threshold
+ */
+
+ /* The register at 0x28 is documented as "reserved", no further
+ comments. */
+
+ pci_read_config_dword (pdev, 0x28, &tint);
+ if (tint != 0x80) {
+ tint = 0x80;
+ pci_write_config_dword (pdev, 0x28, tint);
+ }
+}
+
+
+
+/**************************************************************************
+ * PHY routines *
+ **************************************************************************/
+
+static void __init write_phy (struct fs_dev *dev, int regnum, int val)
+{
+ submit_command (dev, &dev->hp_txq, QE_CMD_PRP_WR | QE_CMD_IMM_INQ,
+ regnum, val, 0);
+}
+
+static int __init init_phy (struct fs_dev *dev, struct reginit_item *reginit)
+{
+ int i;
+
+ func_enter ();
+ while (reginit->reg != PHY_EOF) {
+ if (reginit->reg == PHY_CLEARALL) {
+ /* "PHY_CLEARALL means clear all registers. Numregisters is in "val". */
+ for (i=0;i<reginit->val;i++) {
+ write_phy (dev, i, 0);
+ }
+ } else {
+ write_phy (dev, reginit->reg, reginit->val);
+ }
+ reginit++;
+ }
+ func_exit ();
+ return 0;
+}
+
+static void reset_chip (struct fs_dev *dev)
+{
+ int i;
+
+ write_fs (dev, SARMODE0, SARMODE0_SRTS0);
+
+ /* Undocumented delay */
+ udelay (128);
+
+ /* The "internal registers are documented to all reset to zero, but
+ comments & code in the Windows driver indicates that the pools are
+ NOT reset. */
+ for (i=0;i < FS_NR_FREE_POOLS;i++) {
+ write_fs (dev, FP_CNF (RXB_FP(i)), 0);
+ write_fs (dev, FP_SA (RXB_FP(i)), 0);
+ write_fs (dev, FP_EA (RXB_FP(i)), 0);
+ write_fs (dev, FP_CNT (RXB_FP(i)), 0);
+ write_fs (dev, FP_CTU (RXB_FP(i)), 0);
+ }
+
+ /* The same goes for the match channel registers, although those are
+ NOT documented that way in the Windows driver. -- REW */
+ /* The Windows driver DOES write 0 to these registers somewhere in
+ the init sequence. However, a small hardware-feature, will
+ prevent reception of data on VPI/VCI = 0/0 (Unless the channel
+ allocated happens to have no disabled channels that have a lower
+ number. -- REW */
+
+ /* Clear the match channel registers. */
+ if (IS_FS50 (dev)) {
+ for (i=0;i<FS50_NR_CHANNELS;i++) {
+ write_fs (dev, 0x200 + i * 4, -1);
+ }
+ }
+}
+
+static void __init *aligned_kmalloc (int size, int flags, int alignment)
+{
+ void *t;
+
+ if (alignment <= 0x10) {
+ t = kmalloc (size, flags);
+ if ((unsigned int)t & (alignment-1)) {
+ printk ("Kmalloc doesn't align things correctly! %p\n", t);
+ kfree (t);
+ return aligned_kmalloc (size, flags, alignment * 4);
+ }
+ return t;
+ }
+ printk (KERN_ERR "Request for > 0x10 alignment not yet implemented (hard!)\n");
+ return NULL;
+}
+
+static int __init init_q (struct fs_dev *dev,
+ struct queue *txq, int queue, int nentries, int is_rq)
+{
+ int sz = nentries * sizeof (struct FS_QENTRY);
+ struct FS_QENTRY *p;
+
+ func_enter ();
+
+ fs_dprintk (FS_DEBUG_INIT, "Inititing queue at %x: %d entries:\n",
+ queue, nentries);
+
+ p = aligned_kmalloc (sz, GFP_KERNEL, 0x10);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc queue: %p(%d)\n", p, sz);
+
+ if (!p) return 0;
+
+ write_fs (dev, Q_SA(queue), virt_to_bus(p));
+ write_fs (dev, Q_EA(queue), virt_to_bus(p+nentries-1));
+ write_fs (dev, Q_WP(queue), virt_to_bus(p));
+ write_fs (dev, Q_RP(queue), virt_to_bus(p));
+ if (is_rq) {
+ /* Configuration for the receive queue: 0: interrupt immediately,
+ no pre-warning to empty queues: We do our best to keep the
+ queue filled anyway. */
+ write_fs (dev, Q_CNF(queue), 0 );
+ }
+
+ txq->sa = p;
+ txq->ea = p;
+ txq->offset = queue;
+
+ func_exit ();
+ return 1;
+}
+
+
+static int __init init_fp (struct fs_dev *dev,
+ struct freepool *fp, int queue, int bufsize, int nr_buffers)
+{
+ func_enter ();
+
+ fs_dprintk (FS_DEBUG_INIT, "Inititing free pool at %x:\n", queue);
+
+ write_fs (dev, FP_CNF(queue), (bufsize * RBFP_RBS) | RBFP_RBSVAL | RBFP_CME);
+ write_fs (dev, FP_SA(queue), 0);
+ write_fs (dev, FP_EA(queue), 0);
+ write_fs (dev, FP_CTU(queue), 0);
+ write_fs (dev, FP_CNT(queue), 0);
+
+ fp->offset = queue;
+ fp->bufsize = bufsize;
+ fp->nr_buffers = nr_buffers;
+
+ func_exit ();
+ return 1;
+}
+
+
+static inline int nr_buffers_in_freepool (struct fs_dev *dev, struct freepool *fp)
+{
+#if 0
+ /* This seems to be unreliable.... */
+ return read_fs (dev, FP_CNT (fp->offset));
+#else
+ return fp->n;
+#endif
+}
+
+
+/* Check if this gets going again if a pool ever runs out. -- Yes, it
+ does. I've seen "recieve abort: no buffers" and things started
+ working again after that... -- REW */
+
+static void top_off_fp (struct fs_dev *dev, struct freepool *fp, int gfp_flags)
+{
+ struct FS_BPENTRY *qe, *ne;
+ struct sk_buff *skb;
+ int n = 0;
+
+ fs_dprintk (FS_DEBUG_QUEUE, "Topping off queue at %x (%d-%d/%d)\n",
+ fp->offset, read_fs (dev, FP_CNT (fp->offset)), fp->n,
+ fp->nr_buffers);
+ while (nr_buffers_in_freepool(dev, fp) < fp->nr_buffers) {
+
+ skb = alloc_skb (fp->bufsize, gfp_flags);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc rec-skb: %p(%d)\n", skb, fp->bufsize);
+ if (!skb) break;
+ ne = kmalloc (sizeof (struct FS_BPENTRY), gfp_flags);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc rec-d: %p(%d)\n", ne, sizeof (struct FS_BPENTRY));
+ if (!ne) {
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", skb);
+ dev_kfree_skb_any (skb);
+ break;
+ }
+
+ fs_dprintk (FS_DEBUG_QUEUE, "Adding skb %p desc %p -> %p(%p) ",
+ skb, ne, skb->data, skb->head);
+ n++;
+ ne->flags = FP_FLAGS_EPI | fp->bufsize;
+ ne->next = virt_to_bus (NULL);
+ ne->bsa = virt_to_bus (skb->data);
+ ne->aal_bufsize = fp->bufsize;
+ ne->skb = skb;
+ ne->fp = fp;
+
+ qe = (struct FS_BPENTRY *) (read_fs (dev, FP_EA(fp->offset)));
+ fs_dprintk (FS_DEBUG_QUEUE, "link at %p\n", qe);
+ if (qe) {
+ qe = bus_to_virt ((long) qe);
+ qe->next = virt_to_bus(ne);
+ qe->flags &= ~FP_FLAGS_EPI;
+ } else
+ write_fs (dev, FP_SA(fp->offset), virt_to_bus(ne));
+
+ write_fs (dev, FP_EA(fp->offset), virt_to_bus (ne));
+ fp->n++; /* XXX Atomic_inc? */
+ write_fs (dev, FP_CTU(fp->offset), 1);
+ }
+
+ fs_dprintk (FS_DEBUG_QUEUE, "Added %d entries. \n", n);
+}
+
+static void __exit free_queue (struct fs_dev *dev, struct queue *txq)
+{
+ func_enter ();
+
+ write_fs (dev, Q_SA(txq->offset), 0);
+ write_fs (dev, Q_EA(txq->offset), 0);
+ write_fs (dev, Q_RP(txq->offset), 0);
+ write_fs (dev, Q_WP(txq->offset), 0);
+ /* Configuration ? */
+
+ fs_dprintk (FS_DEBUG_ALLOC, "Free queue: %p\n", txq->sa);
+ kfree (txq->sa);
+
+ func_exit ();
+}
+
+static void __exit free_freepool (struct fs_dev *dev, struct freepool *fp)
+{
+ func_enter ();
+
+ write_fs (dev, FP_CNF(fp->offset), 0);
+ write_fs (dev, FP_SA (fp->offset), 0);
+ write_fs (dev, FP_EA (fp->offset), 0);
+ write_fs (dev, FP_CNT(fp->offset), 0);
+ write_fs (dev, FP_CTU(fp->offset), 0);
+
+ func_exit ();
+}
+
+
+
+static void fs_irq (int irq, void *dev_id, struct pt_regs * pt_regs)
+{
+ int i;
+ u32 status;
+ struct fs_dev *dev = dev_id;
+
+ status = read_fs (dev, ISR);
+ if (!status) return;
+
+ func_enter ();
+
+#ifdef IRQ_RATE_LIMIT
+ /* Aaargh! I'm ashamed. This costs more lines-of-code than the actual
+ interrupt routine!. (Well, used to when I wrote that comment) -- REW */
+ {
+ static int lastjif;
+ static int nintr=0;
+
+ if (lastjif == jiffies) {
+ if (++nintr > IRQ_RATE_LIMIT) {
+ free_irq (dev->irq, dev_id);
+ printk (KERN_ERR "fs: Too many interrupts. Turning off interrupt %d.\n",
+ dev->irq);
+ }
+ } else {
+ lastjif = jiffies;
+ nintr = 0;
+ }
+ }
+#endif
+ fs_dprintk (FS_DEBUG_QUEUE, "in intr: txq %d txrq %d\n",
+ read_fs (dev, Q_EA (dev->hp_txq.offset)) -
+ read_fs (dev, Q_SA (dev->hp_txq.offset)),
+ read_fs (dev, Q_EA (dev->tx_relq.offset)) -
+ read_fs (dev, Q_SA (dev->tx_relq.offset)));
+
+ /* print the bits in the ISR register. */
+ if (fs_debug & FS_DEBUG_IRQ) {
+ /* The FS_DEBUG things are unneccesary here. But this way it is
+ clear for grep that these are debug prints. */
+ fs_dprintk (FS_DEBUG_IRQ, "IRQ status:");
+ for (i=0;i<27;i++)
+ if (status & (1 << i))
+ fs_dprintk (FS_DEBUG_IRQ, " %s", irq_bitname[i]);
+ fs_dprintk (FS_DEBUG_IRQ, "\n");
+ }
+
+ if (status & ISR_RBRQ0_W) {
+ fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (0)!!!!\n");
+ process_incoming (dev, &dev->rx_rq[0]);
+ /* items mentioned on RBRQ0 are from FP 0 or 1. */
+ top_off_fp (dev, &dev->rx_fp[0], GFP_ATOMIC);
+ top_off_fp (dev, &dev->rx_fp[1], GFP_ATOMIC);
+ }
+
+ if (status & ISR_RBRQ1_W) {
+ fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (1)!!!!\n");
+ process_incoming (dev, &dev->rx_rq[1]);
+ top_off_fp (dev, &dev->rx_fp[2], GFP_ATOMIC);
+ top_off_fp (dev, &dev->rx_fp[3], GFP_ATOMIC);
+ }
+
+ if (status & ISR_RBRQ2_W) {
+ fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (2)!!!!\n");
+ process_incoming (dev, &dev->rx_rq[2]);
+ top_off_fp (dev, &dev->rx_fp[4], GFP_ATOMIC);
+ top_off_fp (dev, &dev->rx_fp[5], GFP_ATOMIC);
+ }
+
+ if (status & ISR_RBRQ3_W) {
+ fs_dprintk (FS_DEBUG_IRQ, "Iiiin-coming (3)!!!!\n");
+ process_incoming (dev, &dev->rx_rq[3]);
+ top_off_fp (dev, &dev->rx_fp[6], GFP_ATOMIC);
+ top_off_fp (dev, &dev->rx_fp[7], GFP_ATOMIC);
+ }
+
+ if (status & ISR_CSQ_W) {
+ fs_dprintk (FS_DEBUG_IRQ, "Command executed ok!\n");
+ process_return_queue (dev, &dev->st_q);
+ }
+
+ if (status & ISR_TBRQ_W) {
+ fs_dprintk (FS_DEBUG_IRQ, "Data tramsitted!\n");
+ process_txdone_queue (dev, &dev->tx_relq);
+ }
+
+ func_exit ();
+}
+
+
+#ifdef FS_POLL_FREQ
+static void fs_poll (unsigned long data)
+{
+ struct fs_dev *dev = (struct fs_dev *) data;
+
+ fs_irq (0, dev, NULL);
+ dev->timer.expires = jiffies + FS_POLL_FREQ;
+ add_timer (&dev->timer);
+}
+#endif
+
+static int __init fs_init (struct fs_dev *dev)
+{
+ struct pci_dev *pci_dev;
+ int isr, to;
+ int i;
+
+ func_enter ();
+ pci_dev = dev->pci_dev;
+
+ printk (KERN_INFO "found a FireStream %d card, base %08lx, irq%d.\n",
+ IS_FS50(dev)?50:155,
+ pci_resource_start(pci_dev, 0), dev->pci_dev->irq);
+
+ if (fs_debug & FS_DEBUG_INIT)
+ my_hd ((unsigned char *) dev, sizeof (*dev));
+
+ undocumented_pci_fix (pci_dev);
+
+ dev->hw_base = pci_resource_start(pci_dev, 0);
+
+ dev->base = (ulong) ioremap(dev->hw_base, 0x1000);
+
+ reset_chip (dev);
+
+ write_fs (dev, SARMODE0, 0
+ | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */
+ | (1 * SARMODE0_INTMODE_READCLEAR)
+ | (1 * SARMODE0_CWRE)
+ | IS_FS50(dev)?SARMODE0_PRPWT_FS50_5:
+ SARMODE0_PRPWT_FS155_3
+ | (1 * SARMODE0_CALSUP_1)
+ | IS_FS50 (dev)?(0
+ | SARMODE0_RXVCS_32
+ | SARMODE0_ABRVCS_32
+ | SARMODE0_TXVCS_32):
+ (0
+ | SARMODE0_RXVCS_1k
+ | SARMODE0_ABRVCS_1k
+ | SARMODE0_TXVCS_1k));
+
+ /* 10ms * 100 is 1 second. That should be enough, as AN3:9 says it takes
+ 1ms. */
+ to = 100;
+ while (--to) {
+ isr = read_fs (dev, ISR);
+
+ /* This bit is documented as "RESERVED" */
+ if (isr & ISR_INIT_ERR) {
+ printk (KERN_ERR "Error initializing the FS... \n");
+ return 1;
+ }
+ if (isr & ISR_INIT) {
+ fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
+ break;
+ }
+
+ /* Try again after 10ms. */
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout ((HZ+99)/100);
+ }
+
+ if (!to) {
+ printk (KERN_ERR "timeout initializing the FS... \n");
+ return 1;
+ }
+
+ /* XXX fix for fs155 */
+ dev->channel_mask = 0x1f;
+ dev->channo = 0;
+
+ /* AN3: 10 */
+ write_fs (dev, SARMODE1, 0
+ | (0 * SARMODE1_DEFHEC) /* XXX PHY */
+ | ((loopback == 1) * SARMODE1_TSTLP) /* XXX Loopback mode enable... */
+ | (1 * SARMODE1_DCRM)
+ | (1 * SARMODE1_DCOAM)
+ | (0 * SARMODE1_OAMCRC)
+ | (0 * SARMODE1_DUMPE)
+ | (0 * SARMODE1_GPLEN)
+ | (0 * SARMODE1_GNAM)
+ | (0 * SARMODE1_GVAS)
+ | (0 * SARMODE1_GPAS)
+ | (1 * SARMODE1_GPRI)
+ | (0 * SARMODE1_PMS)
+ | (0 * SARMODE1_GFCR)
+ | (1 * SARMODE1_HECM2)
+ | (1 * SARMODE1_HECM1)
+ | (1 * SARMODE1_HECM0)
+ | (1 << 12) /* That's what hang's driver does. Program to 0 */
+ | (0 * 0xff) /* XXX FS155 */);
+
+
+ /* Cal prescale etc */
+
+ /* AN3: 11 */
+ write_fs (dev, TMCONF, 0x0000000f);
+ write_fs (dev, CALPRESCALE, 0x01010101 * num);
+ write_fs (dev, 0x80, 0x000F00E4);
+
+ /* AN3: 12 */
+ write_fs (dev, CELLOSCONF, 0
+ | ( 0 * CELLOSCONF_CEN)
+ | ( CELLOSCONF_SC1)
+ | (0x80 * CELLOSCONF_COBS)
+ | (num * CELLOSCONF_COPK) /* Changed from 0xff to 0x5a */
+ | (num * CELLOSCONF_COST));/* after a hint from Hang.
+ * performance jumped 50->70... */
+
+ /* Magic value by Hang */
+ write_fs (dev, CELLOSCONF_COST, 0x0B809191);
+
+ if (IS_FS50 (dev)) {
+ write_fs (dev, RAS0, RAS0_DCD_XHLT);
+ dev->atm_dev->ci_range.vpi_bits = 12;
+ dev->atm_dev->ci_range.vci_bits = 16;
+ dev->nchannels = FS50_NR_CHANNELS;
+ } else {
+ write_fs (dev, RAS0, RAS0_DCD_XHLT
+ | (((1 << FS155_VPI_BITS) - 1) * RAS0_VPSEL)
+ | (((1 << FS155_VCI_BITS) - 1) * RAS0_VCSEL));
+ /* We can chose the split arbitarily. We might be able to
+ support more. Whatever. This should do for now. */
+ dev->atm_dev->ci_range.vpi_bits = FS155_VPI_BITS;
+ dev->atm_dev->ci_range.vci_bits = FS155_VCI_BITS;
+
+ /* Address bits we can't use should be compared to 0. */
+ write_fs (dev, RAC, 0);
+
+ /* Manual (AN9, page 6) says ASF1=0 means compare Utopia address
+ * too. I can't find ASF1 anywhere. Anyway, we AND with just hte
+ * other bits, then compare with 0, which is exactly what we
+ * want. */
+ write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1);
+ dev->nchannels = FS155_NR_CHANNELS;
+ }
+ dev->atm_vccs = kmalloc (dev->nchannels * sizeof (struct atm_vcc *),
+ GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%d)\n",
+ dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *));
+
+ if (!dev->atm_vccs) {
+ printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
+ /* XXX Clean up..... */
+ return 1;
+ }
+ memset (dev->atm_vccs, 0, dev->nchannels * sizeof (struct atm_vcc *));
+
+ dev->tx_inuse = kmalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n",
+ dev->atm_vccs, dev->nchannels / 8);
+
+ if (!dev->tx_inuse) {
+ printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
+ /* XXX Clean up..... */
+ return 1;
+ }
+ memset (dev->tx_inuse, 0, dev->nchannels / 8);
+
+ /* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
+ /* -- RAS2 : FS50 only: Default is OK. */
+
+ /* DMAMODE, default should be OK. -- REW */
+ write_fs (dev, DMAMR, DMAMR_TX_MODE_FULL);
+
+ init_q (dev, &dev->hp_txq, TX_PQ(TXQ_HP), TXQ_NENTRIES, 0);
+ init_q (dev, &dev->lp_txq, TX_PQ(TXQ_LP), TXQ_NENTRIES, 0);
+ init_q (dev, &dev->tx_relq, TXB_RQ, TXQ_NENTRIES, 1);
+ init_q (dev, &dev->st_q, ST_Q, TXQ_NENTRIES, 1);
+
+ for (i=0;i < FS_NR_FREE_POOLS;i++) {
+ init_fp (dev, &dev->rx_fp[i], RXB_FP(i),
+ rx_buf_sizes[i], rx_pool_sizes[i]);
+ top_off_fp (dev, &dev->rx_fp[i], GFP_KERNEL);
+ }
+
+
+ for (i=0;i < FS_NR_RX_QUEUES;i++)
+ init_q (dev, &dev->rx_rq[i], RXB_RQ(i), RXRQ_NENTRIES, 1);
+
+ dev->irq = pci_dev->irq;
+ if (request_irq (dev->irq, fs_irq, SA_SHIRQ, "firestream", dev)) {
+ printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
+ /* XXX undo all previous stuff... */
+ return 1;
+ }
+ fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
+
+ /* We want to be notified of most things. Just the statistics count
+ overflows are not interesting */
+ write_fs (dev, IMR, 0
+ | ISR_RBRQ0_W
+ | ISR_RBRQ1_W
+ | ISR_RBRQ2_W
+ | ISR_RBRQ3_W
+ | ISR_TBRQ_W
+ | ISR_CSQ_W);
+
+ write_fs (dev, SARMODE0, 0
+ | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */
+ | (1 * SARMODE0_GINT)
+ | (1 * SARMODE0_INTMODE_READCLEAR)
+ | (0 * SARMODE0_CWRE)
+ | (IS_FS50(dev)?SARMODE0_PRPWT_FS50_5:
+ SARMODE0_PRPWT_FS155_3)
+ | (1 * SARMODE0_CALSUP_1)
+ | (IS_FS50 (dev)?(0
+ | SARMODE0_RXVCS_32
+ | SARMODE0_ABRVCS_32
+ | SARMODE0_TXVCS_32):
+ (0
+ | SARMODE0_RXVCS_1k
+ | SARMODE0_ABRVCS_1k
+ | SARMODE0_TXVCS_1k))
+ | (1 * SARMODE0_RUN));
+
+ init_phy (dev, PHY_NTC_INIT);
+
+ if (loopback == 2) {
+ write_phy (dev, 0x39, 0x000e);
+ }
+
+#ifdef FS_POLL_FREQ
+ init_timer (&dev->timer);
+ dev->timer.data = (unsigned long) dev;
+ dev->timer.function = fs_poll;
+ dev->timer.expires = jiffies + FS_POLL_FREQ;
+ add_timer (&dev->timer);
+#endif
+
+ dev->atm_dev->dev_data = dev;
+
+ func_exit ();
+ return 0;
+}
+
+static int __init firestream_init_one (struct pci_dev *pci_dev,
+ const struct pci_device_id *ent)
+{
+ struct atm_dev *atm_dev;
+ struct fs_dev *fs_dev;
+
+ if (pci_enable_device(pci_dev))
+ goto err_out;
+
+ fs_dev = kmalloc (sizeof (struct fs_dev), GFP_KERNEL);
+ fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%d)\n",
+ fs_dev, sizeof (struct fs_dev));
+ if (!fs_dev)
+ goto err_out;
+
+ memset (fs_dev, 0, sizeof (struct fs_dev));
+
+ atm_dev = atm_dev_register("fs", &ops, -1, NULL);
+ if (!atm_dev)
+ goto err_out_free_fs_dev;
+
+ fs_dev->pci_dev = pci_dev;
+ fs_dev->atm_dev = atm_dev;
+ fs_dev->flags = ent->driver_data;
+
+ if (fs_init(fs_dev))
+ goto err_out_free_atm_dev;
+
+ fs_dev->next = fs_boards;
+ fs_boards = fs_dev;
+ return 0;
+
+ err_out_free_atm_dev:
+ atm_dev_deregister(atm_dev);
+ err_out_free_fs_dev:
+ kfree(fs_dev);
+ err_out:
+ return -ENODEV;
+}
+
+void __devexit firestream_remove_one (struct pci_dev *pdev)
+{
+ int i;
+ struct fs_dev *dev, *nxtdev;
+ struct fs_vcc *vcc;
+ struct FS_BPENTRY *fp, *nxt;
+
+ func_enter ();
+
+#if 0
+ printk ("hptxq:\n");
+ for (i=0;i<60;i++) {
+ printk ("%d: %08x %08x %08x %08x \n",
+ i, pq[qp].cmd, pq[qp].p0, pq[qp].p1, pq[qp].p2);
+ qp++;
+ if (qp >= 60) qp = 0;
+ }
+
+ printk ("descriptors:\n");
+ for (i=0;i<60;i++) {
+ printk ("%d: %p: %08x %08x %p %p\n",
+ i, da[qd], dq[qd].flags, dq[qd].bsa, dq[qd].skb, dq[qd].dev);
+ qd++;
+ if (qd >= 60) qd = 0;
+ }
+#endif
+
+ for (dev = fs_boards;dev != NULL;dev=nxtdev) {
+ fs_dprintk (FS_DEBUG_CLEANUP, "Releasing resources for dev at %p.\n", dev);
+
+ /* XXX Hit all the tx channels too! */
+
+ for (i=0;i < dev->nchannels;i++) {
+ if (dev->atm_vccs[i]) {
+ vcc = FS_VCC (dev->atm_vccs[i]);
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_TX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0);
+ submit_command (dev, &dev->hp_txq,
+ QE_CMD_RX_PURGE_INH | QE_CMD_IMM_INQ | vcc->channo, 0,0,0);
+
+ }
+ }
+
+ /* XXX Wait a while for the chip to release all buffers. */
+
+ for (i=0;i < FS_NR_FREE_POOLS;i++) {
+ for (fp=bus_to_virt (read_fs (dev, FP_SA(dev->rx_fp[i].offset)));
+ !(fp->flags & FP_FLAGS_EPI);fp = nxt) {
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", fp->skb);
+ dev_kfree_skb_any (fp->skb);
+ nxt = bus_to_virt (fp->next);
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", fp);
+ kfree (fp);
+ }
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-skb: %p\n", fp->skb);
+ dev_kfree_skb_any (fp->skb);
+ fs_dprintk (FS_DEBUG_ALLOC, "Free rec-d: %p\n", fp);
+ kfree (fp);
+ }
+
+ /* Hang the chip in "reset", prevent it clobbering memory that is
+ no longer ours. */
+ reset_chip (dev);
+
+ fs_dprintk (FS_DEBUG_CLEANUP, "Freeing irq%d.\n", dev->irq);
+ free_irq (dev->irq, dev);
+ del_timer (&dev->timer);
+
+ atm_dev_deregister(dev->atm_dev);
+ free_queue (dev, &dev->hp_txq);
+ free_queue (dev, &dev->lp_txq);
+ free_queue (dev, &dev->tx_relq);
+ free_queue (dev, &dev->st_q);
+
+ fs_dprintk (FS_DEBUG_ALLOC, "Free atmvccs: %p\n", dev->atm_vccs);
+ kfree (dev->atm_vccs);
+
+ for (i=0;i< FS_NR_FREE_POOLS;i++)
+ free_freepool (dev, &dev->rx_fp[i]);
+
+ for (i=0;i < FS_NR_RX_QUEUES;i++)
+ free_queue (dev, &dev->rx_rq[i]);
+
+ fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
+ nxtdev = dev->next;
+ kfree (dev);
+ }
+
+ func_exit ();
+}
+
+
+#if 0
+int __init fs_detect(void)
+{
+ struct pci_dev *pci_dev;
+ int devs = 0;
+
+ func_enter ();
+ pci_dev = NULL;
+ while ((pci_dev = pci_find_device(PCI_VENDOR_ID_FUJITSU_ME,
+ PCI_DEVICE_ID_FUJITSU_FS50,
+ pci_dev))) {
+ if (fs_register_and_init (pci_dev, &fs_pci_tbl[0]))
+ break;
+ devs++;
+ }
+
+ while ((pci_dev = pci_find_device(PCI_VENDOR_ID_FUJITSU_ME,
+ PCI_DEVICE_ID_FUJITSU_FS155,
+ pci_dev))) {
+ if (fs_register_and_init (pci_dev, FS_IS155))
+ break;
+ devs++;
+ }
+ func_exit ();
+ return devs;
+}
+#else
+
+#if 0
+int __init init_PCI (void)
+{ /* Begin init_PCI */
+
+ int pci_count;
+ printk ("init_PCI\n");
+ /*
+ memset (&firestream_driver, 0, sizeof (firestream_driver));
+ firestream_driver.name = "firestream";
+ firestream_driver.id_table = firestream_pci_tbl;
+ firestream_driver.probe = fs_register_and_init;
+ */
+ pci_count = pci_register_driver (&firestream_driver);
+
+ if (pci_count <= 0) {
+ pci_unregister_driver (&firestream_driver);
+ pci_count = 0;
+ }
+
+ return(pci_count);
+
+} /* End init_PCI */
+#endif
+#endif
+
+/*
+#ifdef MODULE
+#define firestream_init init_module
+#endif
+*/
+
+const static struct pci_device_id firestream_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS50,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS50},
+ { PCI_VENDOR_ID_FUJITSU_ME, PCI_DEVICE_ID_FUJITSU_FS155,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, FS_IS155},
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, firestream_pci_tbl);
+
+static struct pci_driver firestream_driver = {
+ name: "firestream",
+ id_table: firestream_pci_tbl,
+ probe: firestream_init_one,
+ remove: firestream_remove_one,
+};
+
+static int __init firestream_init_module (void)
+{
+ int error;
+
+ func_enter ();
+ error = pci_module_init(&firestream_driver);
+ func_exit ();
+ return error;
+}
+
+static void __exit firestream_cleanup_module(void)
+{
+ pci_unregister_driver(&firestream_driver);
+}
+
+module_init(firestream_init_module);
+module_exit(firestream_cleanup_module);
+
--- /dev/null
+/* drivers/atm/firestream.h - FireStream 155 (MB86697) and
+ * FireStream 50 (MB86695) device driver
+ */
+
+/* Written & (C) 2000 by R.E.Wolff@BitWizard.nl
+ * Copied snippets from zatm.c by Werner Almesberger, EPFL LRC/ICA
+ * and ambassador.c Copyright (C) 1995-1999 Madge Networks Ltd
+ */
+
+/*
+ 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.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ The GNU GPL is contained in /usr/doc/copyright/GPL on a Debian
+ system and in the file COPYING in the Linux kernel source.
+*/
+
+
+/***********************************************************************
+ * first the defines for the chip. *
+ ***********************************************************************/
+
+
+/********************* General chip parameters. ************************/
+
+#define FS_NR_FREE_POOLS 8
+#define FS_NR_RX_QUEUES 4
+
+
+/********************* queues and queue access macros ******************/
+
+
+/* A queue entry. */
+struct FS_QENTRY {
+ u32 cmd;
+ u32 p0, p1, p2;
+};
+
+
+/* A freepool entry. */
+struct FS_BPENTRY {
+ u32 flags;
+ u32 next;
+ u32 bsa;
+ u32 aal_bufsize;
+
+ /* The hardware doesn't look at this, but we need the SKB somewhere... */
+ struct sk_buff *skb;
+ struct freepool *fp;
+ struct fs_dev *dev;
+};
+
+
+#define STATUS_CODE(qe) ((qe->cmd >> 22) & 0x3f)
+
+
+/* OFFSETS against the base of a QUEUE... */
+#define QSA 0x00
+#define QEA 0x04
+#define QRP 0x08
+#define QWP 0x0c
+#define QCNF 0x10 /* Only for Release queues! */
+/* Not for the transmit pending queue. */
+
+
+/* OFFSETS against the base of a FREE POOL... */
+#define FPCNF 0x00
+#define FPSA 0x04
+#define FPEA 0x08
+#define FPCNT 0x0c
+#define FPCTU 0x10
+
+#define Q_SA(b) (b + QSA )
+#define Q_EA(b) (b + QEA )
+#define Q_RP(b) (b + QRP )
+#define Q_WP(b) (b + QWP )
+#define Q_CNF(b) (b + QCNF)
+
+#define FP_CNF(b) (b + FPCNF)
+#define FP_SA(b) (b + FPSA)
+#define FP_EA(b) (b + FPEA)
+#define FP_CNT(b) (b + FPCNT)
+#define FP_CTU(b) (b + FPCTU)
+
+/* bits in a queue register. */
+#define Q_FULL 0x1
+#define Q_EMPTY 0x2
+#define Q_INCWRAP 0x4
+#define Q_ADDR_MASK 0xfffffff0
+
+/* bits in a FreePool config register */
+#define RBFP_RBS (0x1 << 16)
+#define RBFP_RBSVAL (0x1 << 15)
+#define RBFP_CME (0x1 << 12)
+#define RBFP_DLP (0x1 << 11)
+#define RBFP_BFPWT (0x1 << 0)
+
+
+
+
+/* FireStream commands. */
+#define QE_CMD_NULL (0x00 << 22)
+#define QE_CMD_REG_RD (0x01 << 22)
+#define QE_CMD_REG_RDM (0x02 << 22)
+#define QE_CMD_REG_WR (0x03 << 22)
+#define QE_CMD_REG_WRM (0x04 << 22)
+#define QE_CMD_CONFIG_TX (0x05 << 22)
+#define QE_CMD_CONFIG_RX (0x06 << 22)
+#define QE_CMD_PRP_RD (0x07 << 22)
+#define QE_CMD_PRP_RDM (0x2a << 22)
+#define QE_CMD_PRP_WR (0x09 << 22)
+#define QE_CMD_PRP_WRM (0x2b << 22)
+#define QE_CMD_RX_EN (0x0a << 22)
+#define QE_CMD_RX_PURGE (0x0b << 22)
+#define QE_CMD_RX_PURGE_INH (0x0c << 22)
+#define QE_CMD_TX_EN (0x0d << 22)
+#define QE_CMD_TX_PURGE (0x0e << 22)
+#define QE_CMD_TX_PURGE_INH (0x0f << 22)
+#define QE_CMD_RST_CG (0x10 << 22)
+#define QE_CMD_SET_CG (0x11 << 22)
+#define QE_CMD_RST_CLP (0x12 << 22)
+#define QE_CMD_SET_CLP (0x13 << 22)
+#define QE_CMD_OVERRIDE (0x14 << 22)
+#define QE_CMD_ADD_BFP (0x15 << 22)
+#define QE_CMD_DUMP_TX (0x16 << 22)
+#define QE_CMD_DUMP_RX (0x17 << 22)
+#define QE_CMD_LRAM_RD (0x18 << 22)
+#define QE_CMD_LRAM_RDM (0x28 << 22)
+#define QE_CMD_LRAM_WR (0x19 << 22)
+#define QE_CMD_LRAM_WRM (0x29 << 22)
+#define QE_CMD_LRAM_BSET (0x1a << 22)
+#define QE_CMD_LRAM_BCLR (0x1b << 22)
+#define QE_CMD_CONFIG_SEGM (0x1c << 22)
+#define QE_CMD_READ_SEGM (0x1d << 22)
+#define QE_CMD_CONFIG_ROUT (0x1e << 22)
+#define QE_CMD_READ_ROUT (0x1f << 22)
+#define QE_CMD_CONFIG_TM (0x20 << 22)
+#define QE_CMD_READ_TM (0x21 << 22)
+#define QE_CMD_CONFIG_TXBM (0x22 << 22)
+#define QE_CMD_READ_TXBM (0x23 << 22)
+#define QE_CMD_CONFIG_RXBM (0x24 << 22)
+#define QE_CMD_READ_RXBM (0x25 << 22)
+#define QE_CMD_CONFIG_REAS (0x26 << 22)
+#define QE_CMD_READ_REAS (0x27 << 22)
+
+#define QE_TRANSMIT_DE (0x0 << 30)
+#define QE_CMD_LINKED (0x1 << 30)
+#define QE_CMD_IMM (0x2 << 30)
+#define QE_CMD_IMM_INQ (0x3 << 30)
+
+#define TD_EPI (0x1 << 27)
+#define TD_COMMAND (0x1 << 28)
+
+#define TD_DATA (0x0 << 29)
+#define TD_RM_CELL (0x1 << 29)
+#define TD_OAM_CELL (0x2 << 29)
+#define TD_OAM_CELL_SEGMENT (0x3 << 29)
+
+#define TD_BPI (0x1 << 20)
+
+#define FP_FLAGS_EPI (0x1 << 27)
+
+
+#define TX_PQ(i) (0x00 + (i) * 0x10)
+#define TXB_RQ (0x20)
+#define ST_Q (0x48)
+#define RXB_FP(i) (0x90 + (i) * 0x14)
+#define RXB_RQ(i) (0x134 + (i) * 0x14)
+
+
+#define TXQ_HP 0
+#define TXQ_LP 1
+
+/* Phew. You don't want to know how many revisions these simple queue
+ * address macros went through before I got them nice and compact as
+ * they are now. -- REW
+ */
+
+
+/* And now for something completely different:
+ * The rest of the registers... */
+
+
+#define CMDR0 0x34
+#define CMDR1 0x38
+#define CMDR2 0x3c
+#define CMDR3 0x40
+
+
+#define SARMODE0 0x5c
+
+#define SARMODE0_TXVCS_0 (0x0 << 0)
+#define SARMODE0_TXVCS_1k (0x1 << 0)
+#define SARMODE0_TXVCS_2k (0x2 << 0)
+#define SARMODE0_TXVCS_4k (0x3 << 0)
+#define SARMODE0_TXVCS_8k (0x4 << 0)
+#define SARMODE0_TXVCS_16k (0x5 << 0)
+#define SARMODE0_TXVCS_32k (0x6 << 0)
+#define SARMODE0_TXVCS_64k (0x7 << 0)
+#define SARMODE0_TXVCS_32 (0x8 << 0)
+
+#define SARMODE0_ABRVCS_0 (0x0 << 4)
+#define SARMODE0_ABRVCS_512 (0x1 << 4)
+#define SARMODE0_ABRVCS_1k (0x2 << 4)
+#define SARMODE0_ABRVCS_2k (0x3 << 4)
+#define SARMODE0_ABRVCS_4k (0x4 << 4)
+#define SARMODE0_ABRVCS_8k (0x5 << 4)
+#define SARMODE0_ABRVCS_16k (0x6 << 4)
+#define SARMODE0_ABRVCS_32k (0x7 << 4)
+#define SARMODE0_ABRVCS_32 (0x9 << 4) /* The others are "8", this one really has to
+ be 9. Tell me you don't believe me. -- REW */
+
+#define SARMODE0_RXVCS_0 (0x0 << 8)
+#define SARMODE0_RXVCS_1k (0x1 << 8)
+#define SARMODE0_RXVCS_2k (0x2 << 8)
+#define SARMODE0_RXVCS_4k (0x3 << 8)
+#define SARMODE0_RXVCS_8k (0x4 << 8)
+#define SARMODE0_RXVCS_16k (0x5 << 8)
+#define SARMODE0_RXVCS_32k (0x6 << 8)
+#define SARMODE0_RXVCS_64k (0x7 << 8)
+#define SARMODE0_RXVCS_32 (0x8 << 8)
+
+#define SARMODE0_CALSUP_1 (0x0 << 12)
+#define SARMODE0_CALSUP_2 (0x1 << 12)
+#define SARMODE0_CALSUP_3 (0x2 << 12)
+#define SARMODE0_CALSUP_4 (0x3 << 12)
+
+#define SARMODE0_PRPWT_FS50_0 (0x0 << 14)
+#define SARMODE0_PRPWT_FS50_2 (0x1 << 14)
+#define SARMODE0_PRPWT_FS50_5 (0x2 << 14)
+#define SARMODE0_PRPWT_FS50_11 (0x3 << 14)
+
+#define SARMODE0_PRPWT_FS155_0 (0x0 << 14)
+#define SARMODE0_PRPWT_FS155_1 (0x1 << 14)
+#define SARMODE0_PRPWT_FS155_2 (0x2 << 14)
+#define SARMODE0_PRPWT_FS155_3 (0x3 << 14)
+
+#define SARMODE0_SRTS0 (0x1 << 23)
+#define SARMODE0_SRTS1 (0x1 << 24)
+
+#define SARMODE0_RUN (0x1 << 25)
+
+#define SARMODE0_UNLOCK (0x1 << 26)
+#define SARMODE0_CWRE (0x1 << 27)
+
+
+#define SARMODE0_INTMODE_READCLEAR (0x0 << 28)
+#define SARMODE0_INTMODE_READNOCLEAR (0x1 << 28)
+#define SARMODE0_INTMODE_READNOCLEARINHIBIT (0x2 << 28)
+#define SARMODE0_INTMODE_READCLEARINHIBIT (0x3 << 28) /* Tell me you don't believe me. */
+
+#define SARMODE0_GINT (0x1 << 30)
+#define SARMODE0_SHADEN (0x1 << 31)
+
+
+#define SARMODE1 0x60
+
+
+#define SARMODE1_TRTL_SHIFT 0 /* Program to 0 */
+#define SARMODE1_RRTL_SHIFT 4 /* Program to 0 */
+
+#define SARMODE1_TAGM (0x1 << 8) /* Program to 0 */
+
+#define SARMODE1_HECM0 (0x1 << 9)
+#define SARMODE1_HECM1 (0x1 << 10)
+#define SARMODE1_HECM2 (0x1 << 11)
+
+#define SARMODE1_GFCE (0x1 << 14)
+#define SARMODE1_GFCR (0x1 << 15)
+#define SARMODE1_PMS (0x1 << 18)
+#define SARMODE1_GPRI (0x1 << 19)
+#define SARMODE1_GPAS (0x1 << 20)
+#define SARMODE1_GVAS (0x1 << 21)
+#define SARMODE1_GNAM (0x1 << 22)
+#define SARMODE1_GPLEN (0x1 << 23)
+#define SARMODE1_DUMPE (0x1 << 24)
+#define SARMODE1_OAMCRC (0x1 << 25)
+#define SARMODE1_DCOAM (0x1 << 26)
+#define SARMODE1_DCRM (0x1 << 27)
+#define SARMODE1_TSTLP (0x1 << 28)
+#define SARMODE1_DEFHEC (0x1 << 29)
+
+
+#define ISR 0x64
+#define IUSR 0x68
+#define IMR 0x6c
+
+#define ISR_LPCO (0x1 << 0)
+#define ISR_DPCO (0x1 << 1)
+#define ISR_RBRQ0_W (0x1 << 2)
+#define ISR_RBRQ1_W (0x1 << 3)
+#define ISR_RBRQ2_W (0x1 << 4)
+#define ISR_RBRQ3_W (0x1 << 5)
+#define ISR_RBRQ0_NF (0x1 << 6)
+#define ISR_RBRQ1_NF (0x1 << 7)
+#define ISR_RBRQ2_NF (0x1 << 8)
+#define ISR_RBRQ3_NF (0x1 << 9)
+#define ISR_BFP_SC (0x1 << 10)
+#define ISR_INIT (0x1 << 11)
+#define ISR_INIT_ERR (0x1 << 12) /* Documented as "reserved" */
+#define ISR_USCEO (0x1 << 13)
+#define ISR_UPEC0 (0x1 << 14)
+#define ISR_VPFCO (0x1 << 15)
+#define ISR_CRCCO (0x1 << 16)
+#define ISR_HECO (0x1 << 17)
+#define ISR_TBRQ_W (0x1 << 18)
+#define ISR_TBRQ_NF (0x1 << 19)
+#define ISR_CTPQ_E (0x1 << 20)
+#define ISR_GFC_C0 (0x1 << 21)
+#define ISR_PCI_FTL (0x1 << 22)
+#define ISR_CSQ_W (0x1 << 23)
+#define ISR_CSQ_NF (0x1 << 24)
+#define ISR_EXT_INT (0x1 << 25)
+#define ISR_RXDMA_S (0x1 << 26)
+
+
+#define TMCONF 0x78
+/* Bits? */
+
+
+#define CALPRESCALE 0x7c
+/* Bits? */
+
+#define CELLOSCONF 0x84
+#define CELLOSCONF_COTS (0x1 << 28)
+#define CELLOSCONF_CEN (0x1 << 27)
+#define CELLOSCONF_SC8 (0x3 << 24)
+#define CELLOSCONF_SC4 (0x2 << 24)
+#define CELLOSCONF_SC2 (0x1 << 24)
+#define CELLOSCONF_SC1 (0x0 << 24)
+
+#define CELLOSCONF_COBS (0x1 << 16)
+#define CELLOSCONF_COPK (0x1 << 8)
+#define CELLOSCONF_COST (0x1 << 0)
+/* Bits? */
+
+
+#define RAS0 0x1bc
+#define RAS0_DCD_XHLT (0x1 << 31)
+
+#define RAS0_VPSEL (0x1 << 16)
+#define RAS0_VCSEL (0x1 << 0)
+
+
+#define DMAMR 0x1cc
+#define DMAMR_TX_MODE_FULL (0x0 << 0)
+#define DMAMR_TX_MODE_PART (0x1 << 0)
+#define DMAMR_TX_MODE_NONE (0x2 << 0) /* And 3 */
+
+
+
+struct fs_transmit_config {
+ u32 flags;
+ u32 atm_hdr;
+ u32 TMC[4];
+ u32 spec;
+ u32 rtag[3];
+};
+
+#define TC_FLAGS_AAL5 (0x0 << 29)
+#define TC_FLAGS_PACKET (0x0)
+#define TC_FLAGS_TYPE_ABR (0x0 << 22)
+#define TC_FLAGS_TYPE_CBR (0x1 << 22)
+#define TC_FLAGS_TYPE_VBR (0x2 << 22)
+#define TC_FLAGS_TYPE_UBR (0x3 << 22)
+#define TC_FLAGS_CAL0 (0x0 << 20)
+#define TC_FLAGS_CAL1 (0x1 << 20)
+#define TC_FLAGS_CAL2 (0x2 << 20)
+#define TC_FLAGS_CAL3 (0x3 << 20)
+
+
+#define RC_FLAGS_NAM (0x1 << 13)
+#define RC_FLAGS_RXBM_PSB (0x0 << 14)
+#define RC_FLAGS_RXBM_CIF (0x1 << 14)
+#define RC_FLAGS_RXBM_PMB (0x2 << 14)
+#define RC_FLAGS_RXBM_STR (0x4 << 14)
+#define RC_FLAGS_RXBM_SAF (0x6 << 14)
+#define RC_FLAGS_RXBM_POS (0x6 << 14)
+#define RC_FLAGS_BFPS (0x1 << 17)
+
+#define RC_FLAGS_BFPS_BFP (0x1 << 17)
+
+#define RC_FLAGS_BFPS_BFP0 (0x0 << 17)
+#define RC_FLAGS_BFPS_BFP1 (0x1 << 17)
+#define RC_FLAGS_BFPS_BFP2 (0x2 << 17)
+#define RC_FLAGS_BFPS_BFP3 (0x3 << 17)
+#define RC_FLAGS_BFPS_BFP4 (0x4 << 17)
+#define RC_FLAGS_BFPS_BFP5 (0x5 << 17)
+#define RC_FLAGS_BFPS_BFP6 (0x6 << 17)
+#define RC_FLAGS_BFPS_BFP7 (0x7 << 17)
+#define RC_FLAGS_BFPS_BFP01 (0x8 << 17)
+#define RC_FLAGS_BFPS_BFP23 (0x9 << 17)
+#define RC_FLAGS_BFPS_BFP45 (0xa << 17)
+#define RC_FLAGS_BFPS_BFP67 (0xb << 17)
+#define RC_FLAGS_BFPS_BFP07 (0xc << 17)
+#define RC_FLAGS_BFPS_BFP27 (0xd << 17)
+#define RC_FLAGS_BFPS_BFP47 (0xe << 17)
+
+#define RC_FLAGS_BFPS (0x1 << 17)
+#define RC_FLAGS_BFPP (0x1 << 21)
+#define RC_FLAGS_TEVC (0x1 << 22)
+#define RC_FLAGS_TEP (0x1 << 23)
+#define RC_FLAGS_AAL5 (0x0 << 24)
+#define RC_FLAGS_TRANSP (0x1 << 24)
+#define RC_FLAGS_TRANSC (0x2 << 24)
+#define RC_FLAGS_ML (0x1 << 27)
+#define RC_FLAGS_TRBRM (0x1 << 28)
+#define RC_FLAGS_PRI (0x1 << 29)
+#define RC_FLAGS_HOAM (0x1 << 30)
+#define RC_FLAGS_CRC10 (0x1 << 31)
+
+
+#define RAC 0x1c8
+#define RAM 0x1c4
+
+
+
+/************************************************************************
+ * Then the datastructures that the DRIVER uses. *
+ ************************************************************************/
+
+#define TXQ_NENTRIES 32
+#define RXRQ_NENTRIES 1024
+
+
+struct fs_vcc {
+ int channo;
+ wait_queue_head_t close_wait;
+ struct sk_buff *last_skb;
+};
+
+
+struct queue {
+ struct FS_QENTRY *sa, *ea;
+ int offset;
+};
+
+struct freepool {
+ int offset;
+ int bufsize;
+ int nr_buffers;
+ int n;
+};
+
+
+struct fs_dev {
+ struct fs_dev *next; /* other FS devices */
+ int flags;
+
+ unsigned char irq; /* IRQ */
+ struct pci_dev *pci_dev; /* PCI stuff */
+ struct atm_dev *atm_dev;
+ struct timer_list timer;
+
+ unsigned long hw_base; /* mem base address */
+ unsigned long base; /* Mapping of base address */
+ int channo;
+ unsigned long channel_mask;
+
+ struct queue hp_txq, lp_txq, tx_relq, st_q;
+ struct freepool rx_fp[FS_NR_FREE_POOLS];
+ struct queue rx_rq[FS_NR_RX_QUEUES];
+
+ int nchannels;
+ struct atm_vcc **atm_vccs;
+ void *tx_inuse;
+ int ntxpckts;
+};
+
+
+
+
+/* Number of channesl that the FS50 supports. */
+#define FS50_CHANNEL_BITS 5
+#define FS50_NR_CHANNELS (1 << FS50_CHANNEL_BITS)
+
+
+#define FS_DEV(atm_dev) ((struct fs_dev *) (atm_dev)->dev_data)
+#define FS_VCC(atm_vcc) ((struct fs_vcc *) (atm_vcc)->dev_data)
+
+
+#define FS_IS50 0x1
+#define FS_IS155 0x2
+
+#define IS_FS50(dev) (dev->flags & FS_IS50)
+#define IS_FS155(dev) (dev->flags & FS_IS155)
+
+/* Within limits this is user-configurable. */
+/* Note: Currently the sum (10 -> 1k channels) is hardcoded in the driver. */
+#define FS155_VPI_BITS 5
+#define FS155_VCI_BITS 5
+
+#define FS155_CHANNEL_BITS (FS155_VPI_BITS + FS155_VCI_BITS)
+#define FS155_NR_CHANNELS (1 << FS155_CHANNEL_BITS)
struct fore200e* fore200e = FORE200E_DEV(vcc->dev);
struct fore200e_vcc* fore200e_vcc;
- MOD_INC_USE_COUNT;
-
/* find a free VPI/VCI */
fore200e_walk_vccs(vcc, &vpi, &vci);
vcc->vci = vci;
/* ressource checking only? */
- if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) {
- MOD_DEC_USE_COUNT;
+ if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC)
return 0;
- }
set_bit(ATM_VF_ADDR, &vcc->flags);
vcc->itf = vcc->dev->number;
down(&fore200e->rate_sf);
if (fore200e->available_cell_rate < vcc->qos.txtp.max_pcr) {
up(&fore200e->rate_sf);
- MOD_DEC_USE_COUNT;
return -EAGAIN;
}
/* reserving the pseudo-CBR bandwidth at this point grants us
down(&fore200e->rate_sf);
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
up(&fore200e->rate_sf);
- MOD_DEC_USE_COUNT;
return -ENOMEM;
}
down(&fore200e->rate_sf);
fore200e->available_cell_rate += vcc->qos.txtp.max_pcr;
up(&fore200e->rate_sf);
- MOD_DEC_USE_COUNT;
return -EBUSY;
}
fore200e_activate_vcin(fore200e, 0, vcc, 0);
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
-
kfree(FORE200E_VCC(vcc));
if ((vcc->qos.txtp.traffic_class == ATM_CBR) && (vcc->qos.txtp.max_pcr > 0)) {
printk(FORE200E "FORE Systems 200E-series driver - version " FORE200E_VERSION "\n");
- MOD_INC_USE_COUNT;
-
/* for each configured bus interface */
for (link = 0, bus = fore200e_bus; bus->model_name; bus++) {
}
}
- if (link <= 0)
- MOD_DEC_USE_COUNT;
-
return link;
}
static const struct atmdev_ops fore200e_ops =
{
- NULL, /* fore200e_dev_close */
- fore200e_open,
- fore200e_close,
- fore200e_ioctl,
- fore200e_getsockopt,
- fore200e_setsockopt,
- fore200e_send,
- NULL, /* fore200e_sg_send, */
- NULL, /* fore200e_send_oam, */
- NULL, /* fore200e_phy_put, */
- NULL, /* fore200e_phy_get, */
- NULL, /* fore200e_feedback, */
- fore200e_change_qos,
- NULL, /* fore200e_free_rx_skb */
- fore200e_proc_read
+ open: fore200e_open,
+ close: fore200e_close,
+ ioctl: fore200e_ioctl,
+ getsockopt: fore200e_getsockopt,
+ setsockopt: fore200e_setsockopt,
+ send: fore200e_send,
+ change_qos: fore200e_change_qos,
+ proc_read: fore200e_proc_read,
+ owner: THIS_MODULE,
};
return -EINVAL;
}
- // prevent module unload while sleeping (kmalloc)
- // doing this any earlier would complicate more error return paths
- MOD_INC_USE_COUNT;
-
// get space for our vcc stuff and copy parameters into it
vccp = kmalloc (sizeof(hrz_vcc), GFP_KERNEL);
if (!vccp) {
PRINTK (KERN_ERR, "out of memory!");
- MOD_DEC_USE_COUNT;
return -ENOMEM;
}
*vccp = vcc;
if (error) {
PRINTD (DBG_QOS|DBG_VCC, "insufficient cell rate resources");
kfree (vccp);
- MOD_DEC_USE_COUNT;
return error;
}
error = hrz_open_rx (dev, channel);
if (error) {
kfree (vccp);
- MOD_DEC_USE_COUNT;
return error;
}
// this link allows RX frames through
kfree (vcc);
// say the VPI/VCI is free again
clear_bit(ATM_VF_ADDR,&atm_vcc->flags);
- MOD_DEC_USE_COUNT;
}
#if 0
close: hrz_close,
send: hrz_send,
sg_send: hrz_sg_send,
- proc_read: hrz_proc_read
+ proc_read: hrz_proc_read,
+ owner: THIS_MODULE,
};
static int __init hrz_probe (void) {
phy_put: ia_phy_put,
phy_get: ia_phy_get,
change_qos: ia_change_qos,
- proc_read: ia_proc_read
+ proc_read: ia_proc_read,
+ owner: THIS_MODULE,
};
printk(KERN_ERR DEV_LABEL ": no adapter found\n");
return -ENXIO;
}
- // MOD_INC_USE_COUNT;
ia_timer.expires = jiffies + 3*HZ;
add_timer(&ia_timer);
int i, j= 0;
IF_EVENT(printk(">ia cleanup_module\n");)
- // MOD_DEC_USE_COUNT;
if (MOD_IN_USE)
printk("ia: module in use\n");
del_timer(&ia_timer);
send: ns_send,
phy_put: ns_phy_put,
phy_get: ns_phy_get,
- proc_read: ns_proc_read
+ proc_read: ns_proc_read,
+ owner: THIS_MODULE,
};
static struct timer_list ns_timer;
static char *mac[NS_MAX_CARDS];
}
set_bit(ATM_VF_READY,&vcc->flags);
- MOD_INC_USE_COUNT;
return 0;
}
vcc->dev_data = NULL;
clear_bit(ATM_VF_PARTIAL,&vcc->flags);
clear_bit(ATM_VF_ADDR,&vcc->flags);
- MOD_DEC_USE_COUNT;
#ifdef RX_DEBUG
{
static int gs_debug;
-
#ifdef DEBUG
#define gs_dprintk(f, str...) if (gs_debug & f) printk (str)
#else
}
-int block_til_ready(void *port_, struct file * filp)
+int gs_block_til_ready(void *port_, struct file * filp)
{
struct gs_port *port = port_;
DECLARE_WAITQUEUE(wait, current);
if (!tty) return 0;
- gs_dprintk (GS_DEBUG_BTR, "Entering block_till_ready.\n");
+ gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n");
/*
* If the device is in the middle of being closed, then block
* until it's done, and then try again.
EXPORT_SYMBOL(gs_start);
EXPORT_SYMBOL(gs_hangup);
EXPORT_SYMBOL(gs_do_softint);
-EXPORT_SYMBOL(block_til_ready);
+EXPORT_SYMBOL(gs_block_til_ready);
EXPORT_SYMBOL(gs_close);
EXPORT_SYMBOL(gs_set_termios);
EXPORT_SYMBOL(gs_init_port);
#define TIMER_MARGIN 50 /* steps of 0.6sec, 2<n<64. Default is 30 seconds */
static unsigned int ACPIBASE;
+static spinlock_t tco_lock; /* Guards the hardware */
static int i810_margin = TIMER_MARGIN; /* steps of 0.6sec */
{
unsigned char val;
+ spin_lock(&tco_lock);
val = inb (TCO1_CNT + 1);
val &= 0xf7;
outb (val, TCO1_CNT + 1);
val = inb (TCO1_CNT + 1);
+ spin_unlock(&tco_lock);
+
if (val & 0x08)
return -1;
return 0;
{
unsigned char val;
+ spin_lock(&tco_lock);
val = inb (TCO1_CNT + 1);
val |= 0x08;
outb (val, TCO1_CNT + 1);
val = inb (TCO1_CNT + 1);
+ spin_unlock(&tco_lock);
+
if ((val & 0x08) == 0)
return -1;
return 0;
/* "Values of 0h-3h are ignored and should not be attempted" */
if (tmrval > 0x3f || tmrval < 0x03)
return -1;
-
+
+ spin_lock(&tco_lock);
val = inb (TCO1_TMR);
val &= 0xc0;
val |= tmrval;
outb (val, TCO1_TMR);
val = inb (TCO1_TMR);
+ spin_unlock(&tco_lock);
+
if ((val & 0x3f) != tmrval)
return -1;
}
/*
- * Reload (trigger) the timer
+ * Reload (trigger) the timer. Lock is needed so we dont reload it during
+ * a reprogramming event
*/
+
static void tco_timer_reload (void)
{
+ spin_lock(&tco_lock);
outb (0x01, TCO1_RLD);
+ spin_unlock(&tco_lock);
}
/*
static int __init watchdog_init (void)
{
+ spin_lock_init(&tco_lock);
if (!i810tco_getdevice () || i810tco_pci == NULL)
return -ENODEV;
if (!request_region (TCOBASE, 0x10, "i810 TCO")) {
*/
static void pcxxdelay(int msec)
{
- while(msec-- > 0)
- __delay(loops_per_sec/1000);
+ mdelay(mseconds);
}
MOD_INC_USE_COUNT;
}
- retval = block_til_ready(port, filp);
+ retval = gs_block_til_ready(port, filp);
if (retval) {
MOD_DEC_USE_COUNT;
#include <linux/tqueue.h>
#include <linux/version.h>
#include <linux/pci.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
#include <linux/miscdevice.h>
/* The 3.0.0 version of sxboards/sxwindow.h uses BYTE and WORD.... */
static struct termios ** sx_termios;
static struct termios ** sx_termios_locked;
-struct sx_board boards[SX_NBOARDS];
-struct sx_port *sx_ports;
-int sx_refcount;
-int sx_initialized;
-int sx_nports;
-int sx_debug;
+static struct sx_board boards[SX_NBOARDS];
+static struct sx_port *sx_ports;
+static int sx_refcount;
+static int sx_initialized;
+static int sx_nports;
+static int sx_debug;
/* You can have the driver poll your card.
the driver misses an interrupt (report this if it DOES happen to you!)
everything will continue to work....
*/
-int sx_poll = 1;
-int sx_slowpoll;
+static int sx_poll = 1;
+static int sx_slowpoll;
/* The card limits the number of interrupts per second.
At 115k2 "100" should be sufficient.
If you're using higher baudrates, you can increase this...
*/
-int sx_maxints = 100;
+static int sx_maxints = 100;
/* These are the only open spaces in my computer. Yours may have more
or less.... -- REW
duh: Card at 0xa0000 is possible on HP Netserver?? -- pvdl
*/
-int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
- 0xc8000, 0xd8000, 0xe8000};
-int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
- 0xc8000, 0xd8000, 0xe8000, 0xa0000};
+static int sx_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000};
+static int si_probe_addrs[]= {0xc0000, 0xd0000, 0xe0000,
+ 0xc8000, 0xd8000, 0xe8000, 0xa0000};
#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int))
#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int))
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
Some architectures may need more. */
-int sx_irqmask = -1;
+static int sx_irqmask = -1;
-#ifndef TWO_ZERO
-#ifdef MODULE
MODULE_PARM(sx_probe_addrs, "i");
MODULE_PARM(si_probe_addrs, "i");
MODULE_PARM(sx_poll, "i");
MODULE_PARM(sx_maxints, "i");
MODULE_PARM(sx_debug, "i");
MODULE_PARM(sx_irqmask, "i");
-#endif
-#endif
static struct real_driver sx_real_driver = {
sx_disable_tx_interrupts,
sx_chars_in_buffer,
sx_close,
sx_hungup,
- NULL
};
ioctl: sx_fw_ioctl,
};
-struct miscdevice sx_fw_device = {
+static struct miscdevice sx_fw_device = {
SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
};
/* This needs redoing for Alpha -- REW -- Done. */
-inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
+static inline void write_sx_byte (struct sx_board *board, int offset, u8 byte)
{
writeb (byte, board->base+offset);
}
-inline u8 read_sx_byte (struct sx_board *board, int offset)
+static inline u8 read_sx_byte (struct sx_board *board, int offset)
{
return readb (board->base+offset);
}
-inline void write_sx_word (struct sx_board *board, int offset, u16 word)
+static inline void write_sx_word (struct sx_board *board, int offset, u16 word)
{
writew (word, board->base+offset);
}
-inline u16 read_sx_word (struct sx_board *board, int offset)
+static inline u16 read_sx_word (struct sx_board *board, int offset)
{
return readw (board->base + offset);
}
-int sx_busy_wait_eq (struct sx_board *board,
- int offset,
- int mask,
- int correctval)
+static int sx_busy_wait_eq (struct sx_board *board,
+ int offset, int mask, int correctval)
{
int i;
}
-int sx_busy_wait_neq (struct sx_board *board,
- int offset,
- int mask,
- int badval)
+static int sx_busy_wait_neq (struct sx_board *board,
+ int offset, int mask, int badval)
{
int i;
/* 5.6.4 of 6210028 r2.3 */
-int sx_reset (struct sx_board *board)
+static int sx_reset (struct sx_board *board)
{
func_enter ();
read_sx_word (board, BRD_OFFSET (board, elem))
-int sx_start_board (struct sx_board *board)
+static int sx_start_board (struct sx_board *board)
{
if (IS_SX_BOARD (board)) {
write_sx_byte (board, SX_CONFIG, SX_CONF_BUSEN);
/* Note. The SX register is write-only. Therefore, we have to enable the
bus too. This is a no-op, if you don't mess with this driver... */
-int sx_start_interrupts (struct sx_board *board)
+static int sx_start_interrupts (struct sx_board *board)
{
/* Don't call this with board->irq == 0 */
}
-int sx_send_command (struct sx_port *port,
- int command,
- int mask,
- int newstat)
+static int sx_send_command (struct sx_port *port,
+ int command, int mask, int newstat)
{
func_enter2 ();
write_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat), command);
}
-char *mod_type_s (int module_type)
+static char *mod_type_s (int module_type)
{
switch (module_type) {
case TA4: return "TA4";
}
-char *pan_type_s (int pan_type)
+static char *pan_type_s (int pan_type)
{
switch (pan_type) {
case MOD_RS232DB25: return "MOD_RS232DB25";
}
-int mod_compat_type (int module_type)
+static int mod_compat_type (int module_type)
{
return module_type >> 4;
}
case. */
-void sx_transmit_chars (struct sx_port *port)
+static void sx_transmit_chars (struct sx_port *port)
{
int c;
int tx_ip;
a transmit buffer. */
/* Inlined: Called only once. Remove the inline when you add another call */
-inline void sx_receive_chars (struct sx_port *port)
+static inline void sx_receive_chars (struct sx_port *port)
{
int c;
int rx_op;
/* Inlined: it is called only once. Remove the inline if you add another
call */
-inline void sx_check_modem_signals (struct sx_port *port)
+static inline void sx_check_modem_signals (struct sx_port *port)
{
int hi_state;
int c_dcd;
return -EIO;
}
- retval = block_til_ready(port, filp);
+ retval = gs_block_til_ready(port, filp);
sx_dprintk (SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
retval, port->gs.count);
/* This memtest takes a human-noticable time. You normally only do it
once a boot, so I guess that it is worth it. */
-int do_memtest (struct sx_board *board, int min, int max)
+static int do_memtest (struct sx_board *board, int min, int max)
{
int i;
/* This memtest takes a human-noticable time. You normally only do it
once a boot, so I guess that it is worth it. */
-int do_memtest_w (struct sx_board *board, int min, int max)
+static int do_memtest_w (struct sx_board *board, int min, int max)
{
int i;
sx_initialized++;
break;
case SXIO_SETDEBUG:
- case SXIO_SETGSDEBUG:
sx_debug = arg;
break;
case SXIO_GETDEBUG:
- case SXIO_GETGSDEBUG:
rc = sx_debug;
break;
+ case SXIO_GETGSDEBUG:
+ case SXIO_SETGSDEBUG:
+ rc = -EINVAL;
+ break;
case SXIO_GETNPORTS:
rc = sx_nports;
break;
}
-void printheader(void)
+static void printheader(void)
{
static int header_printed;
}
-int probe_sx (struct sx_board *board)
+static int probe_sx (struct sx_board *board)
{
struct vpd_prom vpdp;
char *p;
card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves
0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
-int probe_si (struct sx_board *board)
+static int probe_si (struct sx_board *board)
{
int i;
}
-void * ckmalloc (int size)
+static void * ckmalloc (int size)
{
void *p;
return 0;
}
-#ifdef MODULE
-static void sx_release_drivers(void)
+static void __exit sx_release_drivers(void)
{
func_enter();
tty_unregister_driver(&sx_driver);
tty_unregister_driver(&sx_callout_driver);
func_exit();
}
-#endif
#ifdef TWO_ZERO
#define PDEV unsigned char pci_bus, unsigned pci_fun
EEprom. As the bit is read/write for the CPU, we can fix it here,
if we detect that it isn't set correctly. -- REW */
-void fix_sx_pci (PDEV, struct sx_board *board)
+static void fix_sx_pci (PDEV, struct sx_board *board)
{
unsigned int hwbase;
unsigned long rebase;
#endif
-#ifdef MODULE
-#define sx_init init_module
-#endif
-
-int sx_init(void)
+static int __init sx_init(void)
{
int i;
int found = 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit sx_exit (void)
{
int i;
struct sx_board *board;
kfree (sx_termios_locked);
func_exit();
}
-#endif
+
+module_init(sx_init);
+module_exit(sx_exit);
+
Frodo Looijaard <frodol@dds.nl> ,and also from Martin Bailey
<mbailey@littlefeet-inc.com> */
-/* $Id: i2c-algo-pcf.c,v 1.24 2000/07/09 15:16:16 frodo Exp $ */
+/* $Id: i2c-algo-pcf.c,v 1.25 2000/11/10 13:43:32 frodo Exp $ */
#include <linux/kernel.h>
#include <linux/module.h>
int rdcount=0, i, status, timeout, dummy=1;
struct i2c_algo_pcf_data *adap = i2c_adap->algo_data;
- for (i=0; i<count-1; ++i) {
+ for (i=0; i<count; ++i) {
buf[rdcount] = i2c_inb(adap);
if (dummy) {
dummy = 0;
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl> */
-/* $Id: i2c-core.c,v 1.56 2000/07/09 15:13:05 frodo Exp $ */
+/* $Id: i2c-core.c,v 1.58 2000/10/29 22:57:38 frodo Exp $ */
#include <linux/module.h>
#include <linux/kernel.h>
};
#endif
-static int i2cproc_initialized;
+static int i2cproc_initialized = 0;
#else /* undef CONFIG_PROC_FS */
I2C_SMBUS_BLOCK_DATA,&data);
}
+extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
+ u8 command, u8 length, u8 *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (length > 32)
+ length = 32;
+ for (i = 1; i <= length; i++)
+ data.block[i] = values[i-1];
+ data.block[0] = length;
+ return i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_I2C_BLOCK_DATA,&data);
+}
+
/* Simulate a SMBus command using the i2c protocol
No checking of parameters is done! */
static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
need to use only one message; when reading, we need two. We initialize
most things with sane defaults, to keep the code below somewhat
simpler. */
- unsigned char msgbuf0[33];
- unsigned char msgbuf1[33];
+ unsigned char msgbuf0[34];
+ unsigned char msgbuf1[34];
int num = read_write == I2C_SMBUS_READ?2:1;
struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
{ addr, flags | I2C_M_RD, 0, msgbuf1 }
"I2C emulation!\n");
return -1;
} else {
- msg[1].len = data->block[0] + 1;
- if (msg[1].len > 32) {
+ msg[0].len = data->block[0] + 2;
+ if (msg[0].len > 34) {
printk("i2c-core.o: smbus_access called with "
"invalid block write size (%d)\n",
- msg[1].len);
+ msg[0].len);
return -1;
}
- for (i = 1; i <= msg[1].len; i++)
- msgbuf0[i] = data->block[i];
+ for (i = 1; i <= msg[0].len; i++)
+ msgbuf0[i] = data->block[i-1];
}
break;
default:
/* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
-/* $Id: i2c-dev.c,v 1.32 2000/07/25 23:52:17 frodo Exp $ */
+/* The devfs code is contributed by Philipp Matthias Hahn
+ <pmhahn@titan.lahn.de> */
+/* $Id: i2c-dev.c,v 1.36 2000/09/22 02:19:35 mds Exp $ */
+
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/malloc.h>
#include <linux/version.h>
+#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
#include <linux/smp_lock.h>
+#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+
/* If you want debugging uncomment: */
/* #define DEBUG */
static int i2cdev_cleanup(void);
static struct file_operations i2cdev_fops = {
+#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
owner: THIS_MODULE,
+#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
llseek: i2cdev_lseek,
read: i2cdev_read,
write: i2cdev_write,
#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
+#ifdef CONFIG_DEVFS_FS
+static devfs_handle_t devfs_i2c[I2CDEV_ADAPS_MAX];
+static devfs_handle_t devfs_handle = NULL;
+#endif
static struct i2c_driver i2cdev_driver = {
- /* name */ "i2c-dev dummy driver",
- /* id */ I2C_DRIVERID_I2CDEV,
- /* flags */ I2C_DF_DUMMY,
- /* attach_adapter */ i2cdev_attach_adapter,
- /* detach_client */ i2cdev_detach_client,
- /* command */ i2cdev_command,
- /* inc_use */ NULL,
- /* dec_use */ NULL,
+ name: "i2c-dev dummy driver",
+ id: I2C_DRIVERID_I2CDEV,
+ flags: I2C_DF_DUMMY,
+ attach_adapter: i2cdev_attach_adapter,
+ detach_client: i2cdev_detach_client,
+ command: i2cdev_command,
+/* inc_use: NULL,
+ dec_use: NULL, */
};
static struct i2c_client i2cdev_client_template = {
- /* name */ "I2C /dev entry",
- /* id */ 1,
- /* flags */ 0,
- /* addr */ -1,
- /* adapter */ NULL,
- /* driver */ &i2cdev_driver,
- /* data */ NULL
+ name: "I2C /dev entry",
+ id: 1,
+ flags: 0,
+ addr: -1,
+/* adapter: NULL, */
+ driver: &i2cdev_driver,
+/* data: NULL */
};
static int i2cdev_initialized;
{
#ifdef DEBUG
struct inode *inode = file->f_dentry->d_inode;
- printk("i2c-dev,o: i2c-%d lseek to %ld bytes relative to %d.\n",
+ printk("i2c-dev.o: i2c-%d lseek to %ld bytes relative to %d.\n",
MINOR(inode->i_rdev),(long) offset,origin);
#endif /* DEBUG */
return -ESPIPE;
return -ENOMEM;
#ifdef DEBUG
- printk("i2c-dev,o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
+ printk("i2c-dev.o: i2c-%d reading %d bytes.\n",MINOR(inode->i_rdev),
count);
#endif
}
#ifdef DEBUG
- printk("i2c-dev,o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
+ printk("i2c-dev.o: i2c-%d writing %d bytes.\n",MINOR(inode->i_rdev),
count);
#endif
ret = i2c_master_send(client,tmp,count);
(data_arg.size != I2C_SMBUS_BYTE_DATA) &&
(data_arg.size != I2C_SMBUS_WORD_DATA) &&
(data_arg.size != I2C_SMBUS_PROC_CALL) &&
- (data_arg.size != I2C_SMBUS_BLOCK_DATA)) {
+ (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
+ (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA)) {
#ifdef DEBUG
printk("i2c-dev.o: size out of range (%x) in ioctl I2C_SMBUS.\n",
data_arg.size);
if (i2cdev_adaps[minor]->inc_use)
i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]);
+#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0)
+ MOD_INC_USE_COUNT;
+#endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */
#ifdef DEBUG
printk("i2c-dev.o: opened i2c-%d\n",minor);
#ifdef DEBUG
printk("i2c-dev.o: Closed: i2c-%d\n", minor);
#endif
+#if LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0)
+ MOD_DEC_USE_COUNT;
+#else /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
lock_kernel();
+#endif /* LINUX_KERNEL_VERSION < KERNEL_VERSION(2,4,0) */
if (i2cdev_adaps[minor]->dec_use)
i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]);
+#if LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0)
unlock_kernel();
+#endif /* LINUX_KERNEL_VERSION >= KERNEL_VERSION(2,4,0) */
return 0;
}
int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
int i;
+ char name[8];
if ((i = i2c_adapter_id(adap)) < 0) {
printk("i2c-dev.o: Unknown adapter ?!?\n");
return -ENODEV;
}
+ sprintf (name, "%d", i);
if (! i2cdev_adaps[i]) {
i2cdev_adaps[i] = adap;
+#ifdef CONFIG_DEVFS_FS
+ devfs_i2c[i] = devfs_register (devfs_handle, name,
+ DEVFS_FL_DEFAULT, I2C_MAJOR, i,
+ S_IFCHR | S_IRUSR | S_IWUSR,
+ &i2cdev_fops, NULL);
+#endif
printk("i2c-dev.o: Registered '%s' as minor %d\n",adap->name,i);
} else {
/* This is actually a detach_adapter call! */
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(devfs_i2c[i]);
+#endif
i2cdev_adaps[i] = NULL;
#ifdef DEBUG
printk("i2c-dev.o: Adapter unregistered: %s\n",adap->name);
printk("i2c-dev.o: i2c /dev entries driver module\n");
i2cdev_initialized = 0;
+#ifdef CONFIG_DEVFS_FS
+ if (devfs_register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops)) {
+#else
if (register_chrdev(I2C_MAJOR,"i2c",&i2cdev_fops)) {
+#endif
printk("i2c-dev.o: unable to get major %d for i2c bus\n",
I2C_MAJOR);
return -EIO;
}
+#ifdef CONFIG_DEVFS_FS
+ devfs_handle = devfs_mk_dir(NULL, "i2c", NULL);
+#endif
i2cdev_initialized ++;
if ((res = i2c_add_driver(&i2cdev_driver))) {
}
if (i2cdev_initialized >= 1) {
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(devfs_handle);
+ if ((res = devfs_unregister_chrdev(I2C_MAJOR, "i2c"))) {
+#else
if ((res = unregister_chrdev(I2C_MAJOR,"i2c"))) {
+#endif
printk("i2c-dev.o: unable to release major %d for i2c bus\n",
I2C_MAJOR);
return res;
#
# ISDN device configuration
#
+
+# only included if CONFIG_ISDN != n
+
if [ "$CONFIG_INET" != "n" ]; then
bool ' Support synchronous PPP' CONFIG_ISDN_PPP
if [ "$CONFIG_ISDN_PPP" != "n" ]; then
- bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
- bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
- tristate ' Support BSD compression with sync PPP' CONFIG_ISDN_PPP_BSDCOMP
+ bool ' Use VJ-compression with synchronous PPP' CONFIG_ISDN_PPP_VJ
+ bool ' Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
+ dep_tristate ' Support BSD compression (module only)' CONFIG_ISDN_PPP_BSDCOMP m
fi
fi
bool ' Support audio via ISDN' CONFIG_ISDN_AUDIO
mainmenu_option next_comment
comment 'ISDN feature submodules'
dep_tristate 'isdnloop support' CONFIG_ISDN_DRV_LOOP $CONFIG_ISDN
- bool 'Support isdn diversion services' CONFIG_ISDN_DIVERSION
+ dep_tristate 'Support isdn diversion services' CONFIG_ISDN_DIVERSION $CONFIG_ISDN
endmenu
comment 'low-level hardware drivers'
mainmenu_option next_comment
comment 'Active ISDN cards'
-dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
-dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
-if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
- dep_tristate 'Spellcaster support (EXPERIMENTAL)' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
- dep_tristate 'IBM Active 2000 support (EXPERIMENTAL)' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
-fi
+dep_tristate 'ICN 2B and 4B support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
+dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
+dep_tristate 'Spellcaster support' CONFIG_ISDN_DRV_SC $CONFIG_ISDN
+dep_tristate 'IBM Active 2000 support' CONFIG_ISDN_DRV_ACT2000 $CONFIG_ISDN
-dep_tristate 'Eicon active card support' CONFIG_ISDN_DRV_EICON $CONFIG_ISDN
+bool 'Eicon active card support' CONFIG_ISDN_DRV_EICON
if [ "$CONFIG_ISDN_DRV_EICON" != "n" ]; then
- tristate ' Old Eicon driver' CONFIG_ISDN_DRV_EICON_OLD
- if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
- dep_bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
- bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "y" ]; then
+ dep_tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS $CONFIG_ISDN
+ fi
+ if [ "$CONFIG_ISDN_DRV_EICON_DIVAS" != "y" ]; then
+ dep_tristate ' Legacy Eicon driver' CONFIG_ISDN_DRV_EICON_OLD $CONFIG_ISDN
+ if [ "$CONFIG_ISDN_DRV_EICON_OLD" != "n" ]; then
+ dep_bool ' Eicon PCI DIVA Server BRI/PRI/4BRI support' CONFIG_ISDN_DRV_EICON_PCI $CONFIG_PCI
+ bool ' Eicon S,SX,SCOM,Quadro,S2M support' CONFIG_ISDN_DRV_EICON_ISA
+ fi
fi
- tristate ' Build Eicon driver type standalone' CONFIG_ISDN_DRV_EICON_DIVAS
fi
# CAPI subsystem
-tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI
+tristate 'CAPI2.0 support' CONFIG_ISDN_CAPI
if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
- dep_bool ' CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL
- dep_tristate ' CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_MIDDLEWARE
- dep_tristate ' CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPIFS
- dep_tristate ' CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN
- bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+ bool ' Verbose reason code reporting (kernel size +=7K)' CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
+ dep_bool ' CAPI2.0 Middleware support (EXPERIMENTAL)' CONFIG_ISDN_CAPI_MIDDLEWARE $CONFIG_EXPERIMENTAL
+ dep_tristate ' CAPI2.0 /dev/capi support' CONFIG_ISDN_CAPI_CAPI20 $CONFIG_ISDN_CAPI
+ if [ "$CONFIG_ISDN_CAPI_MIDDLEWARE" = "y" ]; then
+ dep_mbool ' CAPI2.0 filesystem support' CONFIG_ISDN_CAPI_CAPIFS_BOOL $CONFIG_ISDN_CAPI_CAPI20
+ if [ "$CONFIG_ISDN_CAPI_CAPIFS_BOOL" = "y" ]; then
+ define_tristate CONFIG_ISDN_CAPI_CAPIFS $CONFIG_ISDN_CAPI_CAPI20
+ else
+ define_tristate CONFIG_ISDN_CAPI_CAPIFS n
+ fi
+ fi
+ dep_tristate ' CAPI2.0 capidrv interface support' CONFIG_ISDN_CAPI_CAPIDRV $CONFIG_ISDN_CAPI $CONFIG_ISDN
fi
# CAPI drivers
if [ "$CONFIG_ISDN_CAPI" != "n" ]; then
- tristate ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA
- dep_tristate ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_PCI
+ dep_tristate ' AVM B1 ISA support' CONFIG_ISDN_DRV_AVMB1_B1ISA $CONFIG_ISDN_CAPI
+ dep_tristate ' AVM B1 PCI support' CONFIG_ISDN_DRV_AVMB1_B1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
dep_mbool ' AVM B1 PCI V4 support' CONFIG_ISDN_DRV_AVMB1_B1PCIV4 $CONFIG_ISDN_DRV_AVMB1_B1PCI
- tristate ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA
- dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_PCMCIA
+ dep_tristate ' AVM T1/T1-B ISA support' CONFIG_ISDN_DRV_AVMB1_T1ISA $CONFIG_ISDN_CAPI
+ dep_tristate ' AVM B1/M1/M2 PCMCIA support' CONFIG_ISDN_DRV_AVMB1_B1PCMCIA $CONFIG_ISDN_CAPI $CONFIG_PCMCIA
dep_tristate ' AVM B1/M1/M2 PCMCIA cs module' CONFIG_ISDN_DRV_AVMB1_AVM_CS $CONFIG_ISDN_DRV_AVMB1_B1PCMCIA
- dep_tristate ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_PCI
- dep_tristate ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_PCI
+ dep_tristate ' AVM T1/T1-B PCI support' CONFIG_ISDN_DRV_AVMB1_T1PCI $CONFIG_ISDN_CAPI $CONFIG_PCI
+ dep_tristate ' AVM C4 support' CONFIG_ISDN_DRV_AVMB1_C4 $CONFIG_ISDN_CAPI $CONFIG_PCI
fi
# HYSDN
-dep_tristate ' Hypercope HYSDN cards (Champ, Ergo, Metro) support (module)' CONFIG_HYSDN m $CONFIG_PROC_FS
+dep_tristate ' Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)' CONFIG_HYSDN m $CONFIG_PROC_FS
dep_mbool ' HYSDN CAPI 2.0 support' CONFIG_HYSDN_CAPI $CONFIG_HYSDN $CONFIG_ISDN_CAPI
endmenu
isdn-objs += $(isdn-objs-y)
-# Object file lists.
+# Ordering constraints: isdn.o first, rest doesn't matter
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN) += isdn.o
+obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Object files in subdirectories
+mod-subdirs := avmb1 eicon
subdir-$(CONFIG_ISDN_DIVERSION) += divert
subdir-$(CONFIG_ISDN_DRV_HISAX) += hisax
-subobj-$(CONFIG_ISDN_DRV_HISAX) += hisax/hisax_drv.o
subdir-$(CONFIG_ISDN_DRV_ICN) += icn
-subobj-$(CONFIG_ISDN_DRV_ICN) += icn/icn_drv.o
subdir-$(CONFIG_ISDN_DRV_PCBIT) += pcbit
-subobj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit/pcbit_drv.o
subdir-$(CONFIG_ISDN_DRV_SC) += sc
-subobj-$(CONFIG_ISDN_DRV_SC) += sc/sc_drv.o
subdir-$(CONFIG_ISDN_CAPI) += avmb1
-subobj-$(CONFIG_ISDN_CAPI) += avmb1/avmb1.o
subdir-$(CONFIG_ISDN_DRV_LOOP) += isdnloop
-subobj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/isdnloop_drv.o
subdir-$(CONFIG_ISDN_DRV_ACT2000) += act2000
-subobj-$(CONFIG_ISDN_DRV_ACT2000) += act2000/act2000_drv.o
subdir-$(CONFIG_ISDN_DRV_EICON) += eicon
-subobj-$(CONFIG_ISDN_DRV_EICON) += eicon/eicon_drv.o
subdir-$(CONFIG_HYSDN) += hysdn
-subobj-$(CONFIG_HYSDN) += hysdn/hysdn_drv.o
-
-obj-y += $(subobj-y)
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN) += isdn.o
-obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
+obj-y += $(addsuffix /vmlinux-obj.o, $(subdir-y))
# The global Rules.make.
# The target object and module list name.
-O_TARGET := act2000_drv.o
-
-# Objects that export symbols.
-
-export-objs :=
+O_TARGET := vmlinux-obj.o
# Multipart objects.
list-multi := act2000.o
act2000-objs := module.o capi.o act2000_isa.o
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
# The target object and module list name.
-O_TARGET := avmb1.o
+O_TARGET := vmlinux-obj.o
# Objects that export symbols.
list-multi := kernelcapi.o
kernelcapi-objs := kcapi.o
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
+# Ordering constraints: kernelcapi.o first
# Each configuration option enables a list of files.
# The target object and module list name.
-O_TARGET :=
-
-# Objects that export symbols.
-
-export-objs :=
+O_TARGET := vmlinux-obj.o
# Multipart objects.
list-multi := dss1_divert.o
dss1_divert-objs := isdn_divert.o divert_procfs.o divert_init.o
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
-obj-m += dss1_divert.o
+obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
include $(TOPDIR)/Rules.make
# The target object and module list name.
-O_TARGET := eicon_drv.o
+O_TARGET := vmlinux-obj.o
# Objects that export symbols.
eicon-objs += $(eicon-objs-y)
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
-obj-$(CONFIG_ISDN_DRV_EICON_OLD) += eicon.o
+obj-$(CONFIG_ISDN_DRV_EICON_OLD) += eicon.o
obj-$(CONFIG_ISDN_DRV_EICON_DIVAS) += divas.o
include $(TOPDIR)/Rules.make
# The target object and module list name.
-O_TARGET := hisax_drv.o
+O_TARGET := vmlinux-obj.o
# Objects that export symbols.
hisax-objs += $(sort $(hisax-objs-y))
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o
+MD5FILES := isac.c isdnl1.c isdnl2.c isdnl3.c \
+ tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
+ elsa.c diva.c sedlbauer.c
+CERT := $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
+CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
+
include $(TOPDIR)/Rules.make
# Link rules for multi-part drivers.
hisax.o: $(hisax-objs)
$(LD) -r -o $@ $(hisax-objs)
-
-MD5FILES += isac.c isdnl1.c isdnl2.c isdnl3.c \
- tei.c callc.c cert.c l3dss1.c l3_1tr6.c \
- elsa.c diva.c sedlbauer.c
-
-CERT = $(shell md5sum -c md5sums.asc >> /dev/null;echo $$?)
-
-cert.o: $(MD5FILES) md5sums.asc
- $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -D CERTIFICATION=$(CERT) -c -o cert.o cert.c
# The target object and module list name.
-O_TARGET := hysdn_drv.o
-
-# Objects that export symbols.
-
-export-objs :=
+O_TARGET := vmlinux-obj.o
# Multipart objects.
hysdn-objs += $(hysdn-objs-y)
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
obj-$(CONFIG_HYSDN) += hysdn.o
# The target object and module list name.
-O_TARGET := icn_drv.o
-
-# Objects that export symbols.
-
-export-objs :=
-
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
+O_TARGET := vmlinux-obj.o
# Each configuration option enables a list of files.
extern void pcbit_init(void);
#endif
-#ifdef CONFIG_ISDN_DRV_EICON
+#if defined(CONFIG_ISDN_DRV_EICON_OLD) || defined(CONFIG_ISDN_DRV_EICON_DIVAS)
extern void eicon_init(void);
#endif
#if CONFIG_ISDN_DRV_ACT2000
act2000_init();
#endif
-#if CONFIG_ISDN_DRV_EICON
+#if defined(CONFIG_ISDN_DRV_EICON_OLD) || defined(CONFIG_ISDN_DRV_EICON_DIVAS)
eicon_init();
#endif
}
#ifdef CONFIG_ISDN_AUDIO
#include "isdn_audio.h"
#endif
+#ifdef CONFIG_ISDN_DIVERSION_MODULE
+#define CONFIG_ISDN_DIVERSION
+#endif
#ifdef CONFIG_ISDN_DIVERSION
#include <linux/isdn_divertif.h>
#endif CONFIG_ISDN_DIVERSION
# The target object and module list name.
-O_TARGET := isdnloop_drv.o
-
-# Objects that export symbols.
-
-export-objs :=
-
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
+O_TARGET := vmlinux-obj.o
# Each configuration option enables a list of files.
# The target object and module list name.
-O_TARGET := pcbit_drv.o
-
-# Objects that export symbols.
-
-export-objs :=
+O_TARGET := vmlinux-obj.o
# Multipart objects.
list-multi := pcbit.o
pcbit-objs := module.o edss1.o drv.o layer2.o capi.o callbacks.o
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o
# The target object and module list name.
-O_TARGET := sc_drv.o
-
-# Objects that export symbols.
-
-export-objs :=
+O_TARGET := vmlinux-obj.o
# Multipart objects.
sc-objs := shmem.o init.o debug.o packet.o command.o event.o \
ioctl.o interrupt.o message.o timer.o
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN_DRV_SC) += sc.o
MODULE_DESCRIPTION ("RealTek RTL-8139 Fast Ethernet driver");
MODULE_PARM (multicast_filter_limit, "i");
MODULE_PARM (max_interrupt_work, "i");
-MODULE_PARM (debug, "i");
MODULE_PARM (media, "1-" __MODULE_STRING(8) "i");
static int read_eeprom (void *ioaddr, int location, int addr_len);
/*
- * G8BPQ compatible "AX.25 via ethernet" driver release 003
+ * G8BPQ compatible "AX.25 via ethernet" driver release 004
*
* This code REQUIRES 2.0.0 or higher/ NET3.029
*
#include <net/ax25.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
+#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <linux/bpqether.h>
+static const char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
+
static unsigned char ax25_bcast[AX25_ADDR_LEN] =
{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
static unsigned char ax25_defaddr[AX25_ADDR_LEN] =
static char *bpq_print_ethaddr(unsigned char *);
static struct packet_type bpq_packet_type = {
- 0, /* ntohs(ETH_P_BPQ),*/
- 0, /* copy */
- bpq_rcv,
- NULL,
- NULL,
+ type: __constant_htons(ETH_P_BPQ),
+ func: bpq_rcv,
};
static struct notifier_block bpq_dev_notifier = {
- bpq_device_event,
- 0
+ notifier_call: bpq_device_event,
};
struct net_device_stats stats; /* some statistics */
char dest_addr[6]; /* ether destination address */
char acpt_addr[6]; /* accept ether frames from this address only */
-} *bpq_devices = NULL;
+} *bpq_devices;
/* ------------------------------------------------------------------------ */
/*
* Get the ethernet device for a BPQ device
*/
-static __inline__ struct net_device *bpq_get_ether_dev(struct net_device *dev)
+static inline struct net_device *bpq_get_ether_dev(struct net_device *dev)
{
- struct bpqdev *bpq;
-
- bpq = (struct bpqdev *)dev->priv;
+ struct bpqdev *bpq = (struct bpqdev *) dev->priv;
- return (bpq != NULL) ? bpq->ethdev : NULL;
+ return bpq ? bpq->ethdev : NULL;
}
/*
* Get the BPQ device for the ethernet device
*/
-static __inline__ struct net_device *bpq_get_ax25_dev(struct net_device *dev)
+static inline struct net_device *bpq_get_ax25_dev(struct net_device *dev)
{
struct bpqdev *bpq;
return NULL;
}
-static __inline__ int dev_is_ethdev(struct net_device *dev)
+static inline int dev_is_ethdev(struct net_device *dev)
{
return (
dev->type == ARPHRD_ETHER
skb_pull(skb, 2); /* Remove the length bytes */
skb_trim(skb, len); /* Set the length of the data */
- ((struct bpqdev *)dev->priv)->stats.rx_packets++;
- ((struct bpqdev *)dev->priv)->stats.rx_bytes+=len;
+ bpq->stats.rx_packets++;
+ bpq->stats.rx_bytes += len;
ptr = skb_push(skb, 1);
*ptr = 0;
*/
static struct net_device_stats *bpq_get_stats(struct net_device *dev)
{
- struct bpqdev *bpq;
-
- bpq = (struct bpqdev *)dev->priv;
+ struct bpqdev *bpq = (struct bpqdev *) dev->priv;
return &bpq->stats;
}
*/
static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- int err;
struct bpq_ethaddr *ethaddr = (struct bpq_ethaddr *)ifr->ifr_data;
struct bpqdev *bpq = dev->priv;
struct bpq_req req;
switch (cmd) {
case SIOCSBPQETHOPT:
- if ((err = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct bpq_req))) != 0)
- return err;
- copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req));
+ if (copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req)))
+ return -EFAULT;
switch (req.cmd) {
case SIOCGBPQETHPARAM:
case SIOCSBPQETHPARAM:
break;
case SIOCSBPQETHADDR:
- if ((err = verify_area(VERIFY_READ, ethaddr, sizeof(struct bpq_ethaddr))) != 0)
- return err;
- copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN);
- copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN);
+ if (copy_from_user(bpq->dest_addr, ethaddr->destination, ETH_ALEN))
+ return -EFAULT;
+ if (copy_from_user(bpq->acpt_addr, ethaddr->accept, ETH_ALEN))
+ return -EFAULT;
break;
default:
{
struct net_device *dev;
- bpq_packet_type.type = htons(ETH_P_BPQ);
dev_add_pack(&bpq_packet_type);
register_netdevice_notifier(&bpq_dev_notifier);
- printk(KERN_INFO "AX.25: bpqether driver version 0.01\n");
+ printk(banner);
- proc_net_create ("bpqether", 0, bpq_get_info);
+ proc_net_create("bpqether", 0, bpq_get_info);
read_lock_bh(&dev_base_lock);
for (dev = dev_base; dev != NULL; dev = dev->next) {
unregister_netdevice_notifier(&bpq_dev_notifier);
- proc_net_remove ("bpqether");
+ proc_net_remove("bpqether");
for (bpq = bpq_devices; bpq != NULL; bpq = bpq->next)
unregister_netdev(&bpq->axdev);
#include <linux/netdevice.h>
#include <linux/major.h>
#include <linux/init.h>
-
-#include <linux/timer.h>
-
+#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/tcp.h>
#endif
-#ifdef MODULE
-#define AX25_VERSION "AX25-MODULAR-NET3.019-NEWTTY"
-#define min(a,b) (a < b ? a : b)
-#else
-#define AX25_VERSION "AX25-NET3.019-NEWTTY"
-#endif
+static const char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
#define NR_MKISS 4
#define MKISS_SERIAL_TYPE_NORMAL 1
struct net_device dev; /* the device */
} ax25_ctrl_t;
-static ax25_ctrl_t **ax25_ctrls = NULL;
+static ax25_ctrl_t **ax25_ctrls;
int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */
static struct tty_ldisc ax_ldisc;
-static struct tty_driver mkiss_driver;
-static int mkiss_refcount;
-static struct tty_struct *mkiss_table[NR_MKISS];
-static struct termios *mkiss_termios[NR_MKISS];
-static struct termios *mkiss_termios_locked[NR_MKISS];
-struct mkiss_channel MKISS_Info[NR_MKISS];
static int ax25_init(struct net_device *);
-static int mkiss_init(void);
-static int mkiss_write(struct tty_struct *, int, const unsigned char *, int);
static int kiss_esc(unsigned char *, unsigned char *, int);
static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int);
static void kiss_unesc(struct ax_disp *, unsigned char);
/*---------------------------------------------------------------------------*/
-static unsigned short
-calc_crc_flex(unsigned char *cp, int size)
+static unsigned short calc_crc_flex(unsigned char *cp, int size)
{
unsigned short crc = 0xffff;
/*---------------------------------------------------------------------------*/
-static int
-check_crc_flex(unsigned char *cp, int size)
+static int check_crc_flex(unsigned char *cp, int size)
{
unsigned short crc = 0xffff;
ax25_ctrl_t *axp;
int i;
- if (ax25_ctrls == NULL) /* Master array missing ! */
- return NULL;
-
for (i = 0; i < ax25_maxdev; i++) {
axp = ax25_ctrls[i];
/* (Re-)Set the INUSE bit. Very Important! */
set_bit(AXF_INUSE, &axp->ctrl.flags);
axp->ctrl.dev = &axp->dev;
- axp->dev.priv = (void *)&axp->ctrl;
+ axp->dev.priv = (void *) &axp->ctrl;
return &axp->ctrl;
} else {
}
-/* Set the "sending" flag. This must be atomic, hence the ASM. */
+/* Set the "sending" flag. This must be atomic. */
static inline void ax_lock(struct ax_disp *ax)
{
netif_stop_queue(ax->dev);
}
-/* Clear the "sending" flag. This must be atomic, hence the ASM. */
+/* Clear the "sending" flag. This must be atomic. */
static inline void ax_unlock(struct ax_disp *ax)
{
netif_start_queue(ax->dev);
if (mkiss->magic != MKISS_DRIVER_MAGIC) {
switch (ax->crcmode) {
unsigned short crc;
-
+
case CRC_MODE_FLEX:
*p |= 0x20;
crc = calc_crc_flex(p, len);
static void ax25_write_wakeup(struct tty_struct *tty)
{
int actual;
- struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
+ struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
struct mkiss_channel *mkiss;
/* First make sure we're connected. */
if (ax->mkiss != NULL) {
mkiss= ax->mkiss->tty->driver_data;
- if (mkiss->magic == MKISS_DRIVER_MAGIC)
+ if (mkiss->magic == MKISS_DRIVER_MAGIC)
ax_unlock(ax->mkiss);
}
/* Encapsulate an AX.25 packet and kick it into a TTY queue. */
static int ax_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct ax_disp *ax = (struct ax_disp*)dev->priv;
+ struct ax_disp *ax = (struct ax_disp *) dev->priv;
struct mkiss_channel *mkiss = ax->tty->driver_data;
struct ax_disp *tmp_ax;
/* Open the low-level part of the AX25 channel. Easy! */
static int ax_open(struct net_device *dev)
{
- struct ax_disp *ax = (struct ax_disp*)dev->priv;
+ struct ax_disp *ax = (struct ax_disp *) dev->priv;
unsigned long len;
if (ax->tty == NULL)
*
* rbuff Receive buffer.
* xbuff Transmit buffer.
- * cbuff Temporary compression buffer.
*/
len = dev->mtu * 2;
netif_start_queue(dev);
return 0;
- /* Cleanup */
- kfree(ax->xbuff);
-
noxbuff:
kfree(ax->rbuff);
/* Close the low-level part of the AX25 channel. Easy! */
static int ax_close(struct net_device *dev)
{
- struct ax_disp *ax = (struct ax_disp*)dev->priv;
+ struct ax_disp *ax = (struct ax_disp *) dev->priv;
if (ax->tty == NULL)
return -EBUSY;
*/
static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
- struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
+ struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev))
return;
static int ax25_open(struct tty_struct *tty)
{
- struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
+ struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
struct ax_disp *tmp_ax;
struct mkiss_channel *mkiss;
int err, cnt;
if ((err = ax_open(ax->dev)))
return err;
- mkiss= ax->tty->driver_data;
+ mkiss = ax->tty->driver_data;
if (mkiss->magic == MKISS_DRIVER_MAGIC) {
for (cnt = 1; cnt < ax25_maxdev; cnt++) {
static void ax25_close(struct tty_struct *tty)
{
- struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
- int mkiss ;
+ struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
/* First make sure we're connected. */
if (ax == NULL || ax->magic != AX25_MAGIC)
return;
- mkiss = ax->mode;
-
dev_close(ax->dev);
tty->disc_data = 0;
ax->tty = NULL;
- /* VSV = very important to remove timers */
ax_free(ax);
unregister_netdev(ax->dev);
-
MOD_DEC_USE_COUNT;
}
static struct net_device_stats *ax_get_stats(struct net_device *dev)
{
static struct net_device_stats stats;
- struct ax_disp *ax = (struct ax_disp*)dev->priv;
+ struct ax_disp *ax = (struct ax_disp *) dev->priv;
memset(&stats, 0, sizeof(struct net_device_stats));
* STANDARD ENCAPSULATION *
************************************************************************/
-int kiss_esc(unsigned char *s, unsigned char *d, int len)
+static int kiss_esc(unsigned char *s, unsigned char *d, int len)
{
unsigned char *ptr = d;
unsigned char c;
}
-int ax_set_mac_address(struct net_device *dev, void *addr)
+static int ax_set_mac_address(struct net_device *dev, void *addr)
{
if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN))
return -EFAULT;
/* Perform I/O control on an active ax25 channel. */
static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
{
- struct ax_disp *ax = (struct ax_disp *)tty->disc_data;
+ struct ax_disp *ax = (struct ax_disp *) tty->disc_data;
unsigned int tmp;
/* First make sure we're connected. */
return 0;
case SIOCGIFENCAP:
- put_user(4, (int *)arg);
- return 0;
+ return put_user(4, (int *)arg);
case SIOCSIFENCAP:
- get_user(tmp, (int *)arg);
- ax->mode = tmp;
+ if (get_user(tmp, (int *)arg))
+ return -EFAULT;
+ ax->mode = tmp;
ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */
ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
ax->dev->type = ARPHRD_AX25;
static int ax_open_dev(struct net_device *dev)
{
- struct ax_disp *ax = (struct ax_disp*)dev->priv;
+ struct ax_disp *ax = (struct ax_disp *) dev->priv;
- if (ax->tty==NULL)
+ if (ax->tty == NULL)
return -ENODEV;
return 0;
}
-/* Initialize AX25 control device -- register AX25 line discipline */
-int __init mkiss_init_ctrl_dev(void)
-{
- int status;
-
- if (ax25_maxdev < 4) ax25_maxdev = 4; /* Sanity */
-
- if ((ax25_ctrls = kmalloc(sizeof(void*) * ax25_maxdev, GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array ! No mkiss available\n");
- return -ENOMEM;
- }
-
- /* Clear the pointer array, we allocate devices when we need them */
- memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */
-
- /* Fill in our line protocol discipline, and register it */
- memset(&ax_ldisc, 0, sizeof(ax_ldisc));
- ax_ldisc.magic = TTY_LDISC_MAGIC;
- ax_ldisc.name = "mkiss";
- ax_ldisc.flags = 0;
- ax_ldisc.open = ax25_open;
- ax_ldisc.close = ax25_close;
- ax_ldisc.read = NULL;
- ax_ldisc.write = NULL;
- ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, unsigned int, unsigned long))ax25_disp_ioctl;
- ax_ldisc.poll = NULL;
-
- ax_ldisc.receive_buf = ax25_receive_buf;
- ax_ldisc.receive_room = ax25_receive_room;
- ax_ldisc.write_wakeup = ax25_write_wakeup;
-
- if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0)
- printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status);
-
- mkiss_init();
-
- return status;
-}
-
/* Initialize the driver. Called by network startup. */
-
static int ax25_init(struct net_device *dev)
{
- struct ax_disp *ax = (struct ax_disp*)dev->priv;
+ struct ax_disp *ax = (struct ax_disp *) dev->priv;
static char ax25_bcast[AX25_ADDR_LEN] =
{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
dev->open = ax_open_dev;
dev->stop = ax_close;
dev->get_stats = ax_get_stats;
-#ifdef HAVE_SET_MAC_ADDR
dev->set_mac_address = ax_set_dev_mac_address;
-#endif
dev->hard_header_len = 0;
dev->addr_len = 0;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
+ dev->hard_header = ax_header;
+ dev->rebuild_header = ax_rebuild_header;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
- dev->hard_header = ax_header;
- dev->rebuild_header = ax_rebuild_header;
-#endif
-
dev_init_buffers(dev);
/* New-style flags. */
return 0;
}
-static int mkiss_open(struct tty_struct *tty, struct file *filp)
-{
- struct mkiss_channel *mkiss;
- int chan;
-
- chan = MINOR(tty->device) - tty->driver.minor_start;
-
- if (chan < 0 || chan >= NR_MKISS)
- return -ENODEV;
-
- mkiss = &MKISS_Info[chan];
-
- mkiss->magic = MKISS_DRIVER_MAGIC;
- mkiss->init = 1;
- mkiss->tty = tty;
-
- tty->driver_data = mkiss;
-
- tty->termios->c_iflag = IGNBRK | IGNPAR;
- tty->termios->c_cflag = B9600 | CS8 | CLOCAL;
- tty->termios->c_cflag &= ~CBAUD;
-
- return 0;
-}
-
-static void mkiss_close(struct tty_struct *tty, struct file * filp)
-{
- struct mkiss_channel *mkiss = tty->driver_data;
-
- if (mkiss == NULL || mkiss->magic != MKISS_DRIVER_MAGIC)
- return;
-
- mkiss->tty = NULL;
- mkiss->init = 0;
- tty->stopped = 0;
-}
-
-static int mkiss_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
-{
- return 0;
-}
-
-static int mkiss_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
-{
- /* Ignore serial ioctl's */
- switch (cmd) {
- case TCSBRK:
- case TIOCMGET:
- case TIOCMBIS:
- case TIOCMBIC:
- case TIOCMSET:
- case TCSETS:
- case TCSETSF: /* should flush first, but... */
- case TCSETSW: /* should wait until flush, but... */
- return 0;
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-
-static void mkiss_dummy(struct tty_struct *tty)
-{
- struct mkiss_channel *mkiss = tty->driver_data;
-
- if (tty == NULL)
- return;
-
- if (mkiss == NULL)
- return;
-}
-
-static void mkiss_dummy2(struct tty_struct *tty, unsigned char ch)
-{
- struct mkiss_channel *mkiss = tty->driver_data;
-
- if (tty == NULL)
- return;
-
- if (mkiss == NULL)
- return;
-}
-
-
-static int mkiss_write_room(struct tty_struct * tty)
-{
- struct mkiss_channel *mkiss = tty->driver_data;
-
- if (tty == NULL)
- return 0;
-
- if (mkiss == NULL)
- return 0;
-
- return 65536; /* We can handle an infinite amount of data. :-) */
-}
-
-
-static int mkiss_chars_in_buffer(struct tty_struct *tty)
-{
- struct mkiss_channel *mkiss = tty->driver_data;
-
- if (tty == NULL)
- return 0;
-
- if (mkiss == NULL)
- return 0;
-
- return 0;
-}
-
-
-static void mkiss_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
- /* we don't do termios */
-}
/* ******************************************************************** */
-/* * Init MKISS driver * */
+/* * Init MKISS driver * */
/* ******************************************************************** */
-static int __init mkiss_init(void)
+static int __init mkiss_init_driver(void)
{
- memset(&mkiss_driver, 0, sizeof(struct tty_driver));
-
- mkiss_driver.magic = MKISS_DRIVER_MAGIC;
- mkiss_driver.name = "mkiss";
- mkiss_driver.major = MKISS_MAJOR;
- mkiss_driver.minor_start = 0;
- mkiss_driver.num = NR_MKISS;
- mkiss_driver.type = TTY_DRIVER_TYPE_SERIAL;
- mkiss_driver.subtype = MKISS_SERIAL_TYPE_NORMAL; /* not needed */
-
- mkiss_driver.init_termios = tty_std_termios;
- mkiss_driver.init_termios.c_iflag = IGNBRK | IGNPAR;
- mkiss_driver.init_termios.c_cflag = B9600 | CS8 | CLOCAL;
-
- mkiss_driver.flags = TTY_DRIVER_REAL_RAW;
- mkiss_driver.refcount = &mkiss_refcount;
- mkiss_driver.table = mkiss_table;
- mkiss_driver.termios = (struct termios **)mkiss_termios;
- mkiss_driver.termios_locked = (struct termios **)mkiss_termios_locked;
-
- mkiss_driver.ioctl = mkiss_ioctl;
- mkiss_driver.open = mkiss_open;
- mkiss_driver.close = mkiss_close;
- mkiss_driver.write = mkiss_write;
- mkiss_driver.write_room = mkiss_write_room;
- mkiss_driver.chars_in_buffer = mkiss_chars_in_buffer;
- mkiss_driver.set_termios = mkiss_set_termios;
-
- /* some unused functions */
- mkiss_driver.flush_buffer = mkiss_dummy;
- mkiss_driver.throttle = mkiss_dummy;
- mkiss_driver.unthrottle = mkiss_dummy;
- mkiss_driver.stop = mkiss_dummy;
- mkiss_driver.start = mkiss_dummy;
- mkiss_driver.hangup = mkiss_dummy;
- mkiss_driver.flush_chars = mkiss_dummy;
- mkiss_driver.put_char = mkiss_dummy2;
-
- if (tty_register_driver(&mkiss_driver)) {
- printk(KERN_ERR "mkiss: couldn't register Mkiss device\n");
- return -EIO;
- }
+ int status;
- printk(KERN_INFO "AX.25 Multikiss device enabled\n");
+ printk(banner);
- return 0;
-}
-
-#ifdef MODULE
-EXPORT_NO_SYMBOLS;
+ if (ax25_maxdev < 4)
+ ax25_maxdev = 4; /* Sanity */
-MODULE_PARM(ax25_maxdev, "i");
-MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices");
+ if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) {
+ printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n");
+ return -ENOMEM;
+ }
-MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>");
-MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
+ /* Clear the pointer array, we allocate devices when we need them */
+ memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */
-int init_module(void)
-{
- return mkiss_init_ctrl_dev();
+ /* Fill in our line protocol discipline, and register it */
+ ax_ldisc.magic = TTY_LDISC_MAGIC;
+ ax_ldisc.name = "mkiss";
+ ax_ldisc.open = ax25_open;
+ ax_ldisc.close = ax25_close;
+ ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *,
+ unsigned int, unsigned long))ax25_disp_ioctl;
+ ax_ldisc.receive_buf = ax25_receive_buf;
+ ax_ldisc.receive_room = ax25_receive_room;
+ ax_ldisc.write_wakeup = ax25_write_wakeup;
+
+ if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) {
+ printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status);
+ kfree(ax25_ctrls);
+ }
+ return status;
}
-void cleanup_module(void)
+static void __exit mkiss_exit_driver(void)
{
int i;
- if (ax25_ctrls != NULL) {
- for (i = 0; i < ax25_maxdev; i++) {
- if (ax25_ctrls[i]) {
- /*
- * VSV = if dev->start==0, then device
- * unregistred while close proc.
- */
- if (netif_running(&ax25_ctrls[i]->dev))
- unregister_netdev(&(ax25_ctrls[i]->dev));
-
- kfree(ax25_ctrls[i]);
- ax25_ctrls[i] = NULL;
- }
+ for (i = 0; i < ax25_maxdev; i++) {
+ if (ax25_ctrls[i]) {
+ /*
+ * VSV = if dev->start==0, then device
+ * unregistered while close proc.
+ */
+ if (netif_running(&ax25_ctrls[i]->dev))
+ unregister_netdev(&ax25_ctrls[i]->dev);
+ kfree(ax25_ctrls[i]);
}
-
- kfree(ax25_ctrls);
- ax25_ctrls = NULL;
}
+ kfree(ax25_ctrls);
+ ax25_ctrls = NULL;
+
if ((i = tty_register_ldisc(N_AX25, NULL)))
printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i);
-
- if (tty_unregister_driver(&mkiss_driver)) /* remove devive */
- printk(KERN_ERR "mkiss: can't unregister MKISS device\n");
}
-#endif /* MODULE */
+MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>");
+MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs");
+MODULE_PARM(ax25_maxdev, "i");
+MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices");
+
+module_init(mkiss_init_driver);
+module_exit(mkiss_exit_driver);
+
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
/* prototypes for ax25_encapsulate and ax25_rebuild_header */
#include <net/ax25.h>
-#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
+#endif /* CONFIG_AX25 || CONFIG_AX25_MODULE */
/* make genksyms happy */
#include <linux/ip.h>
/* --------------------------------------------------------------------- */
static const char yam_drvname[] = "yam";
-static const char yam_drvinfo[] = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
+static const char yam_drvinfo[] __initdata = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
/* --------------------------------------------------------------------- */
#define YAM_9600 1
#define YAM_1200 2
-#define NR_PORTS 4
+#define NR_PORTS 4
#define YAM_MAGIC 0xF10A7654
/* Transmitter states */
-#define TX_OFF 0
+#define TX_OFF 0
#define TX_HEAD 1
-#define TX_DATA 2
-#define TX_CRC1 3
-#define TX_CRC2 4
-#define TX_TAIL 5
+#define TX_DATA 2
+#define TX_CRC1 3
+#define TX_CRC2 4
+#define TX_TAIL 5
#define YAM_MAX_FRAME 1024
-#define DEFAULT_BITRATE 9600 /* bps */
-#define DEFAULT_HOLDD 10 /* sec */
-#define DEFAULT_TXD 300 /* ms */
-#define DEFAULT_TXTAIL 10 /* ms */
-#define DEFAULT_SLOT 100 /* ms */
-#define DEFAULT_PERS 64 /* 0->255 */
+#define DEFAULT_BITRATE 9600 /* bps */
+#define DEFAULT_HOLDD 10 /* sec */
+#define DEFAULT_TXD 300 /* ms */
+#define DEFAULT_TXTAIL 10 /* ms */
+#define DEFAULT_SLOT 100 /* ms */
+#define DEFAULT_PERS 64 /* 0->255 */
struct yam_port {
int magic;
/* Parameters section */
- int txd; /* tx delay */
- int holdd; /* duplex ptt delay */
- int txtail; /* txtail delay */
- int slot; /* slottime */
- int pers; /* persistence */
+ int txd; /* tx delay */
+ int holdd; /* duplex ptt delay */
+ int txtail; /* txtail delay */
+ int slot; /* slottime */
+ int pers; /* persistence */
/* Tx section */
static struct yam_port yam_ports[NR_PORTS];
-static struct yam_mcs *yam_data = NULL;
-
-static unsigned irqs[16];
+static struct yam_mcs *yam_data;
static char ax25_bcast[7] =
{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
/* --------------------------------------------------------------------- */
-#define RBR(iobase) (iobase+0)
-#define THR(iobase) (iobase+0)
-#define IER(iobase) (iobase+1)
-#define IIR(iobase) (iobase+2)
-#define FCR(iobase) (iobase+2)
-#define LCR(iobase) (iobase+3)
-#define MCR(iobase) (iobase+4)
-#define LSR(iobase) (iobase+5)
-#define MSR(iobase) (iobase+6)
-#define SCR(iobase) (iobase+7)
-#define DLL(iobase) (iobase+0)
-#define DLM(iobase) (iobase+1)
-
-#define YAM_EXTENT 8
+#define RBR(iobase) (iobase+0)
+#define THR(iobase) (iobase+0)
+#define IER(iobase) (iobase+1)
+#define IIR(iobase) (iobase+2)
+#define FCR(iobase) (iobase+2)
+#define LCR(iobase) (iobase+3)
+#define MCR(iobase) (iobase+4)
+#define LSR(iobase) (iobase+5)
+#define MSR(iobase) (iobase+6)
+#define SCR(iobase) (iobase+7)
+#define DLL(iobase) (iobase+0)
+#define DLM(iobase) (iobase+1)
+
+#define YAM_EXTENT 8
/* Interrupt Identification Register Bit Masks */
-#define IIR_NOPEND 1
-#define IIR_MSR 0
-#define IIR_TX 2
-#define IIR_RX 4
-#define IIR_LSR 6
+#define IIR_NOPEND 1
+#define IIR_MSR 0
+#define IIR_TX 2
+#define IIR_RX 4
+#define IIR_LSR 6
#define IIR_TIMEOUT 12 /* Fifo mode only */
#define IIR_MASK 0x0F
/* Interrupt Enable Register Bit Masks */
-#define IER_RX 1 /* enable rx interrupt */
-#define IER_TX 2 /* enable tx interrupt */
-#define IER_LSR 4 /* enable line status interrupts */
-#define IER_MSR 8 /* enable modem status interrupts */
+#define IER_RX 1 /* enable rx interrupt */
+#define IER_TX 2 /* enable tx interrupt */
+#define IER_LSR 4 /* enable line status interrupts */
+#define IER_MSR 8 /* enable modem status interrupts */
/* Modem Control Register Bit Masks */
-#define MCR_DTR 0x01 /* DTR output */
-#define MCR_RTS 0x02 /* RTS output */
-#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */
-#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */
-#define MCR_LOOP 0x10 /* Loopback enable */
+#define MCR_DTR 0x01 /* DTR output */
+#define MCR_RTS 0x02 /* RTS output */
+#define MCR_OUT1 0x04 /* OUT1 output (not accessible in RS232) */
+#define MCR_OUT2 0x08 /* Master Interrupt enable (must be set on PCs) */
+#define MCR_LOOP 0x10 /* Loopback enable */
/* Modem Status Register Bit Masks */
-#define MSR_DCTS 0x01 /* Delta CTS input */
-#define MSR_DDSR 0x02 /* Delta DSR */
-#define MSR_DRIN 0x04 /* Delta RI */
-#define MSR_DDCD 0x08 /* Delta DCD */
-#define MSR_CTS 0x10 /* CTS input */
-#define MSR_DSR 0x20 /* DSR input */
-#define MSR_RING 0x40 /* RI input */
-#define MSR_DCD 0x80 /* DCD input */
+#define MSR_DCTS 0x01 /* Delta CTS input */
+#define MSR_DDSR 0x02 /* Delta DSR */
+#define MSR_DRIN 0x04 /* Delta RI */
+#define MSR_DDCD 0x08 /* Delta DCD */
+#define MSR_CTS 0x10 /* CTS input */
+#define MSR_DSR 0x20 /* DSR input */
+#define MSR_RING 0x40 /* RI input */
+#define MSR_DCD 0x80 /* DCD input */
/* line status register bit mask */
-#define LSR_RXC 0x01
-#define LSR_OE 0x02
-#define LSR_PE 0x04
-#define LSR_FE 0x08
-#define LSR_BREAK 0x10
-#define LSR_THRE 0x20
-#define LSR_TSRE 0x40
+#define LSR_RXC 0x01
+#define LSR_OE 0x02
+#define LSR_PE 0x04
+#define LSR_FE 0x08
+#define LSR_BREAK 0x10
+#define LSR_THRE 0x20
+#define LSR_TSRE 0x40
/* Line Control Register Bit Masks */
-#define LCR_DLAB 0x80
-#define LCR_BREAK 0x40
-#define LCR_PZERO 0x28
-#define LCR_PEVEN 0x18
-#define LCR_PODD 0x08
-#define LCR_STOP1 0x00
-#define LCR_STOP2 0x04
-#define LCR_BIT5 0x00
-#define LCR_BIT6 0x02
-#define LCR_BIT7 0x01
-#define LCR_BIT8 0x03
+#define LCR_DLAB 0x80
+#define LCR_BREAK 0x40
+#define LCR_PZERO 0x28
+#define LCR_PEVEN 0x18
+#define LCR_PODD 0x08
+#define LCR_STOP1 0x00
+#define LCR_STOP2 0x04
+#define LCR_BIT5 0x00
+#define LCR_BIT6 0x02
+#define LCR_BIT7 0x01
+#define LCR_BIT8 0x03
/* YAM Modem <-> UART Port mapping */
-#define TX_RDY MSR_DCTS /* transmitter ready to send */
-#define RX_DCD MSR_DCD /* carrier detect */
-#define RX_FLAG MSR_RING /* hdlc flag received */
-#define FPGA_DONE MSR_DSR /* FPGA is configured */
-#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */
-#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */
+#define TX_RDY MSR_DCTS /* transmitter ready to send */
+#define RX_DCD MSR_DCD /* carrier detect */
+#define RX_FLAG MSR_RING /* hdlc flag received */
+#define FPGA_DONE MSR_DSR /* FPGA is configured */
+#define PTT_ON (MCR_RTS|MCR_OUT2) /* activate PTT */
+#define PTT_OFF (MCR_DTR|MCR_OUT2) /* release PTT */
-#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */
-#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */
-#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */
+#define ENABLE_RXINT IER_RX /* enable uart rx interrupt during rx */
+#define ENABLE_TXINT IER_MSR /* enable uart ms interrupt during tx */
+#define ENABLE_RTXINT (IER_RX|IER_MSR) /* full duplex operations */
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/*************************************************************************
* CRC Tables
return 0;
}
-#ifdef MODULE
-static void free_mcs(void)
-{
- struct yam_mcs *p;
-
- while (yam_data) {
- p = yam_data;
- yam_data = yam_data->next;
- kfree(p);
- }
-}
-#endif
-
-static unsigned char *
- add_mcs(unsigned char *bits, int bitrate)
+static unsigned char *add_mcs(unsigned char *bits, int bitrate)
{
struct yam_mcs *p;
}
/* Allocate a new mcs */
- p = kmalloc(sizeof(struct yam_mcs), GFP_ATOMIC);
- if (p == NULL) {
+ if ((p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "YAM: no memory to allocate mcs\n");
return NULL;
}
/*
* download bitstream to FPGA
- * data is contained in bits[] array in fpgaconf.h
+ * data is contained in bits[] array in yam1200.h resp. yam9600.h
*/
static int fpga_download(int iobase, int bitrate)
fpga_reset(iobase);
for (i = 0; i < YAM_FPGA_SIZE; i++) {
if (fpga_write(iobase, pbits[i])) {
- printk("yam: error in write cycle\n");
+ printk(KERN_ERR "yam: error in write cycle\n");
return -1; /* write... */
}
}
/******************************************************************************
* Rx Section
******************************************************************************/
-static void inline
- yam_rx_flag(struct net_device *dev, struct yam_port *yp)
+static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp)
{
if (yp->dcd && yp->rx_len >= 3 && yp->rx_len < YAM_MAX_FRAME) {
int pkt_len = yp->rx_len - 2 + 1; /* -CRC + kiss */
/* Bad crc */
} else {
if (!(skb = dev_alloc_skb(pkt_len))) {
- printk("%s: memory squeeze, dropping packet\n", dev->name);
+ printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name);
++yp->stats.rx_dropped;
} else {
unsigned char *cp;
yp->rx_crch = 0xf3;
}
-static void inline
- yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb)
+static inline void yam_rx_byte(struct net_device *dev, struct yam_port *yp, unsigned char rxb)
{
if (yp->rx_len < YAM_MAX_FRAME) {
unsigned char c = yp->rx_crcl;
{
struct yam_port *yp = dev->priv;
- if (skb == NULL) {
- return 0;
- }
skb_queue_tail(&yp->send_queue, skb);
dev->trans_start = jiffies;
return 0;
yp->dcd = (msr & RX_DCD) ? 1 : 0;
if (--counter <= 0) {
- printk("%s: too many irq iir=%d\n", dev->name, iir);
+ printk(KERN_ERR "%s: too many irq iir=%d\n", dev->name, iir);
return;
}
if (msr & TX_RDY) {
return len;
}
-#ifdef CONFIG_INET
-#ifdef CONFIG_PROC_FS
-#define yam_net_procfs_init() proc_net_create("yam",0,yam_net_get_info)
-#define yam_net_procfs_remove() proc_net_remove("yam")
-#else
-#define yam_net_procfs_init()
-#define yam_net_procfs_remove()
-#endif /* CONFIG_PROC_FS */
-#else
-#define yam_net_procfs_init()
-#define yam_net_procfs_remove()
-#endif /* CONFIG_INET */
-
/* --------------------------------------------------------------------- */
static struct net_device_stats *yam_get_stats(struct net_device *dev)
return -ENXIO;
}
if (check_region(dev->base_addr, YAM_EXTENT)) {
- printk("%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
+ printk(KERN_ERR "%s: cannot 0x%lx busy\n", dev->name, dev->base_addr);
return -EACCES;
}
if ((u = yam_check_uart(dev->base_addr)) == c_uart_unknown) {
- printk("%s: cannot find uart type\n", dev->name);
+ printk(KERN_ERR "%s: cannot find uart type\n", dev->name);
return -EIO;
}
if (fpga_download(dev->base_addr, yp->bitrate)) {
- printk("%s: cannot init FPGA\n", dev->name);
+ printk(KERN_ERR "%s: cannot init FPGA\n", dev->name);
return -EIO;
}
outb(0, IER(dev->base_addr));
if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, NULL)) {
- printk("%s: irq %d busy\n", dev->name, dev->irq);
+ printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq);
return -EBUSY;
}
request_region(dev->base_addr, YAM_EXTENT, dev->name);
case SIOCYAMSMCS:
if (netif_running(dev))
return -EINVAL; /* Cannot change this parameter when up */
- ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
+ ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_KERNEL);
if(ym==NULL)
return -ENOBUFS;
ym->bitrate = 9600;
/* --------------------------------------------------------------------- */
-int __init yam_init(void)
+static int __init yam_init_driver(void)
{
struct net_device *dev;
int i;
printk(yam_drvinfo);
- /* Clears the IRQ table */
- memset(irqs, 0, sizeof(irqs));
- memset(yam_ports, 0, sizeof(yam_ports));
-
for (i = 0; i < NR_PORTS; i++) {
sprintf(yam_ports[i].dev.name, "yam%d", i);
yam_ports[i].magic = YAM_MAGIC;
dev->if_port = 0;
if (register_netdev(dev)) {
- printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
+ printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
return -ENXIO;
}
}
yam_timer.expires = jiffies + HZ / 100;
add_timer(&yam_timer);
- yam_net_procfs_init();
- return 1;
-}
-
-/* --------------------------------------------------------------------- */
-
-#ifdef MODULE
-
-/*
- * command line settable parameters
- */
-
-
-MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
-MODULE_DESCRIPTION("Yam amateur radio modem driver");
-
-int init_module(void)
-{
- int ret = yam_init();
-
- return (ret == 1) ? 0 : ret;
+ proc_net_create("yam", 0, yam_net_get_info);
+ return 0;
}
/* --------------------------------------------------------------------- */
-void cleanup_module(void)
+static void __exit yam_cleanup_driver(void)
{
+ struct yam_mcs *p;
int i;
del_timer(&yam_timer);
yam_close(dev);
unregister_netdev(dev);
}
- free_mcs();
- yam_net_procfs_remove();
+
+ while (yam_data) {
+ p = yam_data;
+ yam_data = yam_data->next;
+ kfree(p);
+ }
+
+ proc_net_remove("yam");
}
-#endif /* MODULE */
/* --------------------------------------------------------------------- */
+
+MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
+MODULE_DESCRIPTION("Yam amateur radio modem driver");
+
+module_init(yam_init_driver);
+module_exit(yam_cleanup_driver);
+
+/* --------------------------------------------------------------------- */
+
{
int i;
- for (i = 0; i < sockets; i++) {
+ for (i = sockets-1; i >= 0; i-- ) {
socket_info_t *socket = socket_table[i];
if (socket->ss_entry == ss_entry)
- pcmcia_unregister_socket (socket);
- else
- i++;
+ pcmcia_unregister_socket (socket);
}
} /* unregister_ss_entry */
init_timer(&timer);
timer.data = (unsigned long) &sem;
- timer.expires = jiffies + 10000; /* 10s */
+ timer.expires = jiffies + 10 * HZ; /* 10s */
timer.function = (void (*)(unsigned long)) timer_expired;
add_timer(&timer);
if(TESTHI(DMASTAT, DFIFOFULL)) {
fifodata = 128;
} else {
- the_time=jiffies + 100;
+ the_time=jiffies + HZ;
while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
barrier();
*/
spin_lock_irqsave (&io_request_lock, flags);
- DEB(printk ("\npci2000 recieved interrupt "));
+ DEB(printk ("\npci2000 received interrupt "));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
{
if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )
static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
{
DEB (printk ("\npci2220i:RESET spigot = %X devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1]));
- udelay (100000); // just wait 100 mSec to let drives flush
+ mdelay (100); // just wait 100 mSec to let drives flush
SelectSpigot (padapter, spigot | SEL_IRQ_OFF);
outb_p (0x0E, padapter->regAltStat); // reset the suvivor
*/
spin_lock_irqsave (&io_request_lock, flags);
-// DEB (printk ("\npci2220i recieved interrupt\n"));
+// DEB (printk ("\npci2220i received interrupt\n"));
for ( z = 0; z < NumAdapters; z++ ) // scan for interrupt to process
{
{
padapter->reconOn = FALSE; // shut down the hot reconstruct
if ( padapter->reconPhase )
- udelay (300000);
+ mdelay (300);
if ( padapter->reconTimer.data ) // is the timer running?
{
del_timer (&padapter->reconTimer);
for(indx = 0; indx < no_of_boards; indx++) {
unsigned long page = __get_free_pages(GFP_ATOMIC, order);
- if(page == NULL)
+ if(page == 0UL)
{
printk(KERN_WARNING "sim710: out of memory registering board %d.\n", indx);
break;
unsigned int mask = 0;
VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
+ if (file->f_mode & FMODE_WRITE) {
+ if (!s->dma_dac.ready && prog_dmabuf(s, 0))
+ return 0;
poll_wait(file, &s->dma_dac.wait, wait);
- if (file->f_mode & FMODE_READ)
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (!s->dma_adc.ready && prog_dmabuf(s, 1))
+ return 0;
poll_wait(file, &s->dma_adc.wait, wait);
+ }
+
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
if (file->f_mode & FMODE_READ) {
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->enable & CM_CENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->enable & CM_CENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
val = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
cm_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
printk(KERN_INFO
"cs4281: cs4281_poll() wait on FMODE_WRITE\n"));
+ if (!s->dma_dac.ready && prog_dmabuf_dac(s))
+ return 0;
poll_wait(file, &s->dma_dac.wait, wait);
}
if (file->f_mode & FMODE_READ) {
CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
printk(KERN_INFO
"cs4281: cs4281_poll() wait on FMODE_READ\n"));
+ if (!s->dma_adc.ready && prog_dmabuf_adc(s))
+ return 0;
poll_wait(file, &s->dma_adc.wait, wait);
}
+
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
if (file->f_mode & FMODE_WRITE) {
} else if (file->f_mode & FMODE_READ) {
if (s->dma_adc.mapped) {
if (s->dma_adc.count >=
- (signed) s->dma_adc.fragsize) mask |=
- POLLIN | POLLRDNORM;
+ (signed) s->dma_adc.fragsize)
+ mask |= POLLIN | POLLRDNORM;
} else {
if (s->dma_adc.count > 0)
mask |= POLLIN | POLLRDNORM;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ena & FMODE_WRITE)
- && (val = prog_dmabuf_dac(s)) != 0)
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)))
return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ena & FMODE_READ)
- && (val = prog_dmabuf_adc(s)) != 0) return val;
+ if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)))
+ return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
if (s->conversion) {
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)))
+ return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
val = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)))
+ return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)))
+ return val;
spin_lock_irqsave(&s->lock, flags);
cs4281_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
+ if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_dac2.fragsize;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0)
- return val;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
count = s->dma_dac2.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1370_update_ptr(s);
cinfo.bytes = s->dma_dac2.total_bytes;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ctrl & CTRL_DAC2_EN) && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
+ if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_dac2.fragsize;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ctrl & CTRL_ADC_EN) && (val = prog_dmabuf_adc(s)) != 0)
- return val;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
count = s->dma_dac2.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
es1371_update_ptr(s);
cinfo.bytes = s->dma_dac2.total_bytes;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->ena & FMODE_WRITE) && (val = prog_dmabuf_dac(s)) != 0)
- return val;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->ena & FMODE_READ) && (val = prog_dmabuf_adc(s)) != 0)
- return val;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
count = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
solo1_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
struct ess_state *s = (struct ess_state *)file->private_data;
unsigned long flags;
unsigned int mask = 0;
- int ret;
VALIDATE_STATE(s);
/* In 0.14 prog_dmabuf always returns success anyway ... */
if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return POLLERR;
+ if (!s->dma_dac.ready && prog_dmabuf(s, 0))
+ return 0;
}
if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return POLLERR;
+ if (!s->dma_adc.ready && prog_dmabuf(s, 1))
+ return 0;
}
if (file->f_mode & FMODE_WRITE)
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
ess_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
ess_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
ess_update_ptr(s);
val = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
ess_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
ess_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!(s->enable & SV_CENABLE_PE) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
abinfo.fragsize = s->dma_dac.fragsize;
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!(s->enable & SV_CENABLE_RE) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
abinfo.fragsize = s->dma_adc.fragsize;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
count = s->dma_dac.count;
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
cinfo.bytes = s->dma_adc.total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
+ return ret;
spin_lock_irqsave(&s->lock, flags);
sv_update_ptr(s);
cinfo.bytes = s->dma_dac.total_bytes;
unsigned int mask = 0;
VALIDATE_STATE(state);
- if (file->f_mode & FMODE_WRITE)
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (!dmabuf->ready && prog_dmabuf(state, 0))
+ return 0;
poll_wait(file, &dmabuf->wait, wait);
- if (file->f_mode & FMODE_READ)
+ }
+ if (file->f_mode & FMODE_READ) {
+ if (!dmabuf->ready && prog_dmabuf(state, 1))
+ return 0;
poll_wait(file, &dmabuf->wait, wait);
+ }
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
case SNDCTL_DSP_GETOSPACE:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
- if (!dmabuf->enable && (val = prog_dmabuf(state, 0)) != 0)
+ if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
return val;
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
case SNDCTL_DSP_GETISPACE:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
- if (!dmabuf->enable && (val = prog_dmabuf(state, 1)) != 0)
+ if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
return val;
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
case SNDCTL_DSP_GETIPTR:
if (!(file->f_mode & FMODE_READ))
return -EINVAL;
+ if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
+ return val;
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
cinfo.bytes = dmabuf->total_bytes;
case SNDCTL_DSP_GETOPTR:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+ return val;
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
cinfo.bytes = dmabuf->total_bytes;
case SNDCTL_DSP_GETODELAY:
if (!(file->f_mode & FMODE_WRITE))
return -EINVAL;
+ if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
+ return val;
spin_lock_irqsave(&state->card->lock, flags);
trident_update_ptr(state);
val = dmabuf->count;
if (j->m_DAAShadowRegs.XOP_REGS.XOP.xr0.bitreg.Caller_ID) {
if (j->daa_mode == SOP_PU_RINGING && j->flags.pstn_ringing) {
j->pstn_cid_intr = 1;
- j->pstn_cid_recieved = jiffies;
+ j->pstn_cid_received = jiffies;
}
}
} else {
daa_int_read(board);
}
j->ex.bits.pstn_ring = 0;
- if (j->pstn_cid_intr && jiffies > j->pstn_cid_recieved + (hertz * 3)) {
+ if (j->pstn_cid_intr && jiffies > j->pstn_cid_received + (hertz * 3)) {
if (j->daa_mode == SOP_PU_RINGING) {
ixj_daa_cid_read(board);
j->ex.bits.caller_id = 1;
unsigned char fskz;
unsigned char fskphase;
unsigned char fskcnt;
- unsigned pstn_cid_recieved;
+ unsigned pstn_cid_received;
PHONE_CID cid;
PHONE_CID cid_send;
unsigned long pstn_ring_start;
static int adfs_prepare_write(struct file *file, struct page *page, unsigned int from, unsigned int to)
{
return cont_prepare_write(page, from, to, adfs_get_block,
- &((struct inode *)page->mapping->host)->u.adfs_i.mmu_private);
+ &page->mapping->host->u.adfs_i.mmu_private);
}
static int _adfs_bmap(struct address_space *mapping, long block)
static int affs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,affs_get_block,
- &((struct inode*)page->mapping->host)->u.affs_i.mmu_private);
+ &page->mapping->host->u.affs_i.mmu_private);
}
static int _affs_bmap(struct address_space *mapping, long block)
{
static int affs_symlink_readpage(struct file *file, struct page *page)
{
struct buffer_head *bh;
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
char *link = kmap(page);
struct slink_front *lf;
int err;
/* We need to protect against concurrent writers.. */
down(&inode->i_sem);
+ filemap_fdatasync(inode->i_mapping);
err = file->f_op->fsync(file, dentry, 0);
+ filemap_fdatawait(inode->i_mapping);
up(&inode->i_sem);
out_putf:
goto out_putf;
down(&inode->i_sem);
+ filemap_fdatasync(inode->i_mapping);
err = file->f_op->fsync(file, dentry, 1);
+ filemap_fdatawait(inode->i_mapping);
up(&inode->i_sem);
out_putf:
*/
int block_read_full_page(struct page *page, get_block_t *get_block)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
int cont_prepare_write(struct page *page, unsigned offset, unsigned to, get_block_t *get_block, unsigned long *bytes)
{
struct address_space *mapping = page->mapping;
- struct inode *inode = (struct inode*)mapping->host;
+ struct inode *inode = mapping->host;
struct page *new_page;
unsigned long pgpos;
long status;
int block_prepare_write(struct page *page, unsigned from, unsigned to,
get_block_t *get_block)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
int err = __block_prepare_write(inode, page, from, to, get_block);
if (err) {
ClearPageUptodate(page);
int generic_commit_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
__block_commit_write(inode,page,from,to);
kunmap(page);
unsigned long index = from >> PAGE_CACHE_SHIFT;
unsigned offset = from & (PAGE_CACHE_SIZE-1);
unsigned blocksize, iblock, length, pos;
- struct inode *inode = (struct inode *)mapping->host;
+ struct inode *inode = mapping->host;
struct page *page;
struct buffer_head *bh;
int err;
int block_write_full_page(struct page *page, get_block_t *get_block)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
unsigned offset;
int err;
int generic_block_bmap(struct address_space *mapping, long block, get_block_t *get_block)
{
struct buffer_head tmp;
- struct inode *inode = (struct inode*)mapping->host;
+ struct inode *inode = mapping->host;
tmp.b_state = 0;
tmp.b_blocknr = 0;
get_block(inode, block, &tmp, 0);
return -EIO;
}
- container = (struct inode *)inode->i_mapping->host;
+ container = inode->i_mapping->host;
coda_prepare_fakefile(inode, file, container, &open_file, &open_dentry);
f->private_data = cred;
if ( i->i_mapping != &i->i_data ) {
- old_container = (struct inode *)i->i_mapping->host;
+ old_container = i->i_mapping->host;
i->i_mapping = &i->i_data;
iput(old_container);
}
cred = (struct coda_cred *)f->private_data;
if (i->i_mapping != &i->i_data)
- container = (struct inode *)i->i_mapping->host;
+ container = i->i_mapping->host;
cii = ITOC(i);
CDEBUG(D_FILE, "RELEASE coda (ino %ld, ct %d, cc %d) cache (ino %ld, ct %d)\n",
return_bad_inode:
if ( inode->i_mapping != &inode->i_data ) {
- container = (struct inode *)inode->i_mapping->host;
+ container = inode->i_mapping->host;
inode->i_mapping = &inode->i_data;
iput(container);
}
coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
{
struct inode *inode = file->f_dentry->d_inode;
- struct inode *container = (struct inode*)inode->i_mapping->host;
+ struct inode *container = inode->i_mapping->host;
ssize_t n;
down(&container->i_sem);
return -1;
}
- cont_dentry.d_inode = (struct inode *)inode->i_mapping->host;
+ cont_dentry.d_inode = inode->i_mapping->host;
down(&cont_dentry.d_inode->i_sem);
result = file_fsync(NULL, &cont_dentry, datasync);
goto out;
if ( inode->i_mapping != &inode->i_data ) {
- open_inode = (struct inode *)inode->i_mapping->host;
+ open_inode = inode->i_mapping->host;
CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n",
open_inode->i_ino, atomic_read(&open_inode->i_count));
inode->i_mapping = &inode->i_data;
static int coda_symlink_filler(struct file *file, struct page *page)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
int error;
struct coda_inode_info *cnp;
unsigned int len = PAGE_SIZE;
static int cramfs_readpage(struct file *file, struct page * page)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
u32 maxblock, bytes_filled;
maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
{
char *link = kmap(page);
struct buffer_head * bh;
- struct inode * inode = (struct inode*)page->mapping->host;
+ struct inode * inode = page->mapping->host;
efs_block_t size = inode->i_size;
int err;
EXT2_BLOCKS_PER_GROUP(sb), map);
}
-static int test_root(int a, int b)
+static inline int test_root(int a, int b)
{
if (a == 0)
return 1;
test_root(group, 7));
}
+/**
+ * ext2_bg_has_super - number of blocks used by the superblock in group
+ * @sb: superblock for filesystem
+ * @group: group number to check
+ *
+ * Return the number of blocks used by the superblock (primary or backup)
+ * in this group. Currently this will be only 0 or 1.
+ */
+int ext2_bg_has_super(struct super_block *sb, int group)
+{
+ if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
+ !ext2_group_sparse(group))
+ return 0;
+ return 1;
+}
+
+/**
+ * ext2_bg_num_gdb - number of blocks used by the group table in group
+ * @sb: superblock for filesystem
+ * @group: group number to check
+ *
+ * Return the number of blocks used by the group descriptor table
+ * (primary or backup) in this group. In the future there may be a
+ * different number of descriptor blocks in each group.
+ */
+unsigned long ext2_bg_num_gdb(struct super_block *sb, int group)
+{
+ if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&&
+ !ext2_group_sparse(group))
+ return 0;
+ return EXT2_SB(sb)->s_gdb_count;
+}
+
#ifdef CONFIG_EXT2_CHECK
/* Called at mount-time, super-block is locked */
void ext2_check_blocks_bitmap (struct super_block * sb)
{
struct buffer_head * bh;
struct ext2_super_block * es;
- unsigned long desc_count, bitmap_count, x;
+ unsigned long desc_count, bitmap_count, x, j;
unsigned long desc_blocks;
int bitmap_nr;
struct ext2_group_desc * gdp;
- int i, j;
+ int i;
es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
- desc_blocks = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
- EXT2_DESC_PER_BLOCK(sb);
for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
gdp = ext2_get_group_desc (sb, i, NULL);
if (!gdp)
bitmap_nr = load_block_bitmap (sb, i);
if (bitmap_nr < 0)
continue;
-
- bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr];
- if (!(sb->u.ext2_sb.s_feature_ro_compat &
- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
- ext2_group_sparse(i)) {
- if (!ext2_test_bit (0, bh->b_data))
- ext2_error (sb, "ext2_check_blocks_bitmap",
- "Superblock in group %d "
- "is marked free", i);
-
- for (j = 0; j < desc_blocks; j++)
- if (!ext2_test_bit (j + 1, bh->b_data))
- ext2_error (sb,
- "ext2_check_blocks_bitmap",
- "Descriptor block #%d in group "
- "%d is marked free", j, i);
- }
+ bh = EXT2_SB(sb)->s_block_bitmap[bitmap_nr];
+
+ if (ext2_bg_has_super(sb, i) && !ext2_test_bit(0, bh->b_data))
+ ext2_error(sb, __FUNCTION__,
+ "Superblock in group %d is marked free", i);
+
+ desc_blocks = ext2_bg_num_gdb(sb, i);
+ for (j = 0; j < desc_blocks; j++)
+ if (!ext2_test_bit(j + 1, bh->b_data))
+ ext2_error(sb, __FUNCTION__,
+ "Descriptor block #%ld in group "
+ "%d is marked free", j, i);
if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data))
ext2_error (sb, "ext2_check_blocks_bitmap",
raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
if (raw_inode->i_size_high) {
struct super_block *sb = inode->i_sb;
- struct ext2_super_block *es = sb->u.ext2_sb.s_es;
- if (!(es->s_feature_ro_compat & cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) {
+ if (!EXT2_HAS_RO_COMPAT_FEATURE(sb,
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE) ||
+ EXT2_SB(sb)->s_es->s_rev_level ==
+ cpu_to_le32(EXT2_GOOD_OLD_REV)) {
/* If this is the first large file
* created, add a flag to the superblock.
*/
lock_kernel();
- es->s_feature_ro_compat |= cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
+ ext2_update_dynamic_rev(sb);
+ EXT2_SET_RO_COMPAT_FEATURE(sb,
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
unlock_kernel();
ext2_write_super(sb);
}
bdevname(sb->s_dev), function, error_buf);
}
+void ext2_update_dynamic_rev(struct super_block *sb)
+{
+ struct ext2_super_block *es = EXT2_SB(sb)->s_es;
+
+ if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV)
+ return;
+
+ ext2_warning(sb, __FUNCTION__,
+ "updating to rev %d because of new feature flag, "
+ "running e2fsck is recommended",
+ EXT2_DYNAMIC_REV);
+
+ es->s_first_ino = cpu_to_le32(EXT2_GOOD_OLD_FIRST_INO);
+ es->s_inode_size = cpu_to_le16(EXT2_GOOD_OLD_INODE_SIZE);
+ es->s_rev_level = cpu_to_le32(EXT2_DYNAMIC_REV);
+ /* leave es->s_feature_*compat flags alone */
+ /* es->s_uuid will be set by e2fsck if empty */
+
+ /*
+ * The rest of the superblock fields should be zero, and if not it
+ * means they are likely already in use, so leave them alone. We
+ * can leave it up to e2fsck to clean up any inconsistencies there.
+ */
+}
+
void ext2_put_super (struct super_block * sb)
{
int db_count;
sb->u.ext2_sb.s_es->s_state = le16_to_cpu(sb->u.ext2_sb.s_mount_state);
mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
}
- db_count = sb->u.ext2_sb.s_db_per_group;
+ db_count = EXT2_SB(sb)->s_gdb_count;
for (i = 0; i < db_count; i++)
if (sb->u.ext2_sb.s_group_desc[i])
brelse (sb->u.ext2_sb.s_group_desc[i]);
{
int res = 0;
if (le32_to_cpu(es->s_rev_level) > EXT2_MAX_SUPP_REV) {
- printk ("EXT2-fs warning: revision level too high, "
- "forcing read/only mode\n");
- res = MS_RDONLY;
+ printk ("EXT2-fs warning: revision level too high, "
+ "forcing read-only mode\n");
+ res = MS_RDONLY;
}
if (read_only)
return res;
brelse(bh);
return NULL;
}
- if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) {
- if (le32_to_cpu(es->s_feature_incompat) & ~EXT2_FEATURE_INCOMPAT_SUPP) {
- printk("EXT2-fs: %s: couldn't mount because of "
- "unsupported optional features.\n",
- bdevname(dev));
- goto failed_mount;
- }
- if (!(sb->s_flags & MS_RDONLY) &&
- (le32_to_cpu(es->s_feature_ro_compat) & ~EXT2_FEATURE_RO_COMPAT_SUPP)) {
- printk("EXT2-fs: %s: couldn't mount RDWR because of "
- "unsupported optional features.\n",
- bdevname(dev));
- goto failed_mount;
- }
+ if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
+ (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
+ EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
+ EXT2_HAS_INCOMPAT_FEATURE(sb, ~0U)))
+ printk("EXT2-fs warning: feature flags set on rev 0 fs, "
+ "running e2fsck is recommended\n");
+ /*
+ * Check feature flags regardless of the revision level, since we
+ * previously didn't change the revision level when setting the flags,
+ * so there is a chance incompat flags are set on a rev 0 filesystem.
+ */
+ if ((i = EXT2_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))) {
+ printk("EXT2-fs: %s: couldn't mount because of "
+ "unsupported optional features (%x).\n",
+ bdevname(dev), i);
+ goto failed_mount;
+ }
+ if (!(sb->s_flags & MS_RDONLY) &&
+ (i = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))){
+ printk("EXT2-fs: %s: couldn't mount RDWR because of "
+ "unsupported optional features (%x).\n",
+ bdevname(dev), i);
+ goto failed_mount;
}
- sb->s_blocksize_bits = le32_to_cpu(sb->u.ext2_sb.s_es->s_log_block_size) + 10;
+ sb->s_blocksize_bits =
+ le32_to_cpu(EXT2_SB(sb)->s_es->s_log_block_size) + 10;
sb->s_blocksize = 1 << sb->s_blocksize_bits;
if (sb->s_blocksize != BLOCK_SIZE &&
(sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||
goto failed_mount;
}
}
- sb->u.ext2_sb.s_feature_compat = le32_to_cpu(es->s_feature_compat);
- sb->u.ext2_sb.s_feature_incompat = le32_to_cpu(es->s_feature_incompat);
- sb->u.ext2_sb.s_feature_ro_compat = le32_to_cpu(es->s_feature_ro_compat);
sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE <<
le32_to_cpu(es->s_log_frag_size);
if (sb->u.ext2_sb.s_frag_size)
}
sb->u.ext2_sb.s_loaded_inode_bitmaps = 0;
sb->u.ext2_sb.s_loaded_block_bitmaps = 0;
- sb->u.ext2_sb.s_db_per_group = db_count;
+ sb->u.ext2_sb.s_gdb_count = db_count;
/*
* set up enough so that it can read an inode
*/
ext2_commit_super (sb, es);
}
else {
+ int ret;
+ if ((ret = EXT2_HAS_RO_COMPAT_FEATURE(sb,
+ ~EXT2_FEATURE_RO_COMPAT_SUPP))) {
+ printk("EXT2-fs: %s: couldn't remount RDWR because of "
+ "unsupported optional features (%x).\n",
+ bdevname(sb->s_dev), ret);
+ return -EROFS;
+ }
/*
* Mounting a RDONLY partition read-write, so reread and
* store the current valid flag. (It may have been changed
int ext2_statfs (struct super_block * sb, struct statfs * buf)
{
unsigned long overhead;
- int ngroups, i;
+ int i;
if (test_opt (sb, MINIX_DF))
overhead = 0;
/*
* Add the overhead attributed to the superblock and
- * block group descriptors. If this is sparse
- * superblocks is turned on, then not all groups have
- * this.
+ * block group descriptors. If the sparse superblocks
+ * feature is turned on, then not all groups have this.
*/
- if (sb->u.ext2_sb.s_feature_ro_compat &
- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) {
- ngroups = 0;
- for (i=0 ; i < sb->u.ext2_sb.s_groups_count; i++)
- if (ext2_group_sparse(i))
- ngroups++;
- } else
- ngroups = sb->u.ext2_sb.s_groups_count;
- overhead += ngroups * (1 + sb->u.ext2_sb.s_db_per_group);
+ for (i = 0; i < EXT2_SB(sb)->s_groups_count; i++)
+ overhead += ext2_bg_has_super(sb, i) +
+ ext2_bg_num_gdb(sb, i);
/*
* Every block group has an inode bitmap, a block
static int fat_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,fat_get_block,
- &MSDOS_I((struct inode*)page->mapping->host)->mmu_private);
+ &MSDOS_I(page->mapping->host)->mmu_private);
}
static int _fat_bmap(struct address_space *mapping, long block)
{
static int hfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,hfs_get_block,
- &((struct inode*)page->mapping->host)->u.hfs_i.mmu_private);
+ &page->mapping->host->u.hfs_i.mmu_private);
}
static int hfs_bmap(struct address_space *mapping, long block)
{
static int hpfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,hpfs_get_block,
- &((struct inode*)page->mapping->host)->u.hpfs_i.mmu_private);
+ &page->mapping->host->u.hpfs_i.mmu_private);
}
static int _hpfs_bmap(struct address_space *mapping, long block)
{
int hpfs_symlink_readpage(struct file *file, struct page *page)
{
char *link = kmap(page);
- struct inode *i = (struct inode*)page->mapping->host;
+ struct inode *i = page->mapping->host;
struct fnode *fnode;
struct buffer_head *bh;
int err;
memset(inode, 0, sizeof(*inode));
init_waitqueue_head(&inode->i_wait);
INIT_LIST_HEAD(&inode->i_hash);
- INIT_LIST_HEAD(&inode->i_data.pages);
+ INIT_LIST_HEAD(&inode->i_data.clean_pages);
+ INIT_LIST_HEAD(&inode->i_data.dirty_pages);
+ INIT_LIST_HEAD(&inode->i_data.locked_pages);
INIT_LIST_HEAD(&inode->i_dentry);
INIT_LIST_HEAD(&inode->i_dirty_buffers);
sema_init(&inode->i_sem, 1);
iput(inode);
spin_lock(&inode_lock);
} else {
+ unsigned dirty;
+
list_del(&inode->i_list);
list_add(&inode->i_list, atomic_read(&inode->i_count)
? &inode_in_use
: &inode_unused);
/* Set I_LOCK, reset I_DIRTY */
+ dirty = inode->i_state & I_DIRTY;
inode->i_state |= I_LOCK;
inode->i_state &= ~I_DIRTY;
spin_unlock(&inode_lock);
- write_inode(inode, sync);
+ filemap_fdatasync(inode->i_mapping);
+
+ /* Don't write the inode if only I_DIRTY_PAGES was set */
+ if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC))
+ write_inode(inode, sync);
+
+ filemap_fdatawait(inode->i_mapping);
spin_lock(&inode_lock);
inode->i_state &= ~I_LOCK;
inode->i_pipe = NULL;
inode->i_bdev = NULL;
inode->i_data.a_ops = &empty_aops;
- inode->i_data.host = (void*)inode;
+ inode->i_data.host = inode;
inode->i_mapping = &inode->i_data;
}
static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
char *link = kmap(page);
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
void *buf;
unsigned long read_len;
int result = -EIO;
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip;
struct jffs_control *c = (struct jffs_control *)inode->i_sb->u.generic_sbp;
int r;
|| (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
return NULL;
+ *p++ = htonl(fl->fl_pid);
+
start = loff_t_to_s64(fl->fl_start);
if (fl->fl_end == OFFSET_MAX)
len = 0;
else
len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);
- *p++ = htonl(fl->fl_pid);
p = xdr_encode_hyper(p, start);
p = xdr_encode_hyper(p, len);
static int ncp_symlink_readpage(struct file *file, struct page *page)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
int error, length, len, cnt;
char *link;
char *buf = kmap(page);
{
long status;
loff_t pos = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + to;
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
kunmap(page);
lock_kernel();
mapping = page->mapping;
if (!mapping)
return 0;
- inode = (struct inode *)mapping->host;
+ inode = mapping->host;
if (!inode)
return 0;
struct address_space *mapping = page->mapping;
if (!mapping)
BUG();
- inode = (struct inode *)mapping->host;
+ inode = mapping->host;
} else
inode = file->f_dentry->d_inode;
if (!inode)
if (!mapping)
BUG();
- inode = (struct inode *)mapping->host;
+ inode = mapping->host;
if (!inode)
BUG();
end_index = inode->i_size >> PAGE_CACHE_SHIFT;
# Native language support configuration
#
+# smb wants NLS
+if [ "$CONFIG_SMB_FS" = "m" -o "$CONFIG_SMB_FS" = "y" ]; then
+ define_bool CONFIG_SMB_NLS y
+else
+ define_bool CONFIG_SMB_NLS n
+fi
+
# msdos and Joliet want NLS
if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
-o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \
- -o "$CONFIG_SMB_FS" != "n" ]; then
+ -o "$CONFIG_SMB_NLS" = "y" ]; then
define_bool CONFIG_NLS y
else
define_bool CONFIG_NLS n
static int ntfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,ntfs_get_block,
- &((struct inode*)page->mapping->host)->u.ntfs_i.mmu_private);
+ &page->mapping->host->u.ntfs_i.mmu_private);
}
static int _ntfs_bmap(struct address_space *mapping, long block)
{
static int qnx4_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
{
return cont_prepare_write(page,from,to,qnx4_get_block,
- &((struct inode*)page->mapping->host)->u.qnx4_i.mmu_private);
+ &page->mapping->host->u.qnx4_i.mmu_private);
}
static int qnx4_bmap(struct address_space *mapping, long block)
{
static int ramfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
kunmap(page);
static int
romfs_readpage(struct file *file, struct page * page)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
unsigned long offset, avail, readlen;
void *buf;
int result = -EIO;
if (!mapping)
BUG();
- inode = (struct inode *)mapping->host;
+ inode = mapping->host;
if (!inode)
BUG();
static int udf_adinicb_readpage(struct file *file, struct page * page)
{
- struct inode *inode = (struct inode *)page->mapping->host;
+ struct inode *inode = page->mapping->host;
struct buffer_head *bh;
int block;
static int udf_adinicb_writepage(struct page *page)
{
- struct inode *inode = (struct inode *)page->mapping->host;
+ struct inode *inode = page->mapping->host;
struct buffer_head *bh;
int block;
static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to)
{
- struct inode *inode = (struct inode *)page->mapping->host;
+ struct inode *inode = page->mapping->host;
struct buffer_head *bh;
int block;
static int udf_symlink_filler(struct file *file, struct page *page)
{
- struct inode *inode = (struct inode*)page->mapping->host;
+ struct inode *inode = page->mapping->host;
struct buffer_head *bh = NULL;
char *symlink;
int err = -EIO;
int (*attach)(struct atm_vcc *vcc,int itf);
int (*create_persistent)(int itf);
int (*remove_persistent)(int itf);
+ struct module *owner;
};
extern struct atm_tcp_ops atm_tcp_ops;
void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
/* @@@ temporary hack */
int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
+ struct module *owner;
};
*/
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
- ( EXT2_SB(sb)->s_feature_compat & (mask) )
+ ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
- ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+ ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
- ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+ ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT2_SET_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
extern int ext2_permission (struct inode *, int);
/* balloc.c */
-extern int ext2_group_sparse(int group);
+extern int ext2_bg_has_super(struct super_block *sb, int group);
+extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
extern int ext2_new_block (const struct inode *, unsigned long,
__u32 *, __u32 *, int *);
extern void ext2_free_blocks (const struct inode *, unsigned long,
__attribute__ ((NORET_AND format (printf, 3, 4)));
extern void ext2_warning (struct super_block *, const char *, const char *, ...)
__attribute__ ((format (printf, 3, 4)));
+extern void ext2_update_dynamic_rev (struct super_block *sb);
extern void ext2_put_super (struct super_block *);
extern void ext2_write_super (struct super_block *);
extern int ext2_remount (struct super_block *, int *, char *);
unsigned long s_blocks_per_group;/* Number of blocks in a group */
unsigned long s_inodes_per_group;/* Number of inodes in a group */
unsigned long s_itb_per_group; /* Number of inode table blocks per group */
- unsigned long s_db_per_group; /* Number of descriptor blocks per group */
+ unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */
struct buffer_head * s_sbh; /* Buffer containing the super block */
int s_desc_per_block_bits;
int s_inode_size;
int s_first_ino;
- int s_feature_compat;
- int s_feature_incompat;
- int s_feature_ro_compat;
};
#endif /* _LINUX_EXT2_FS_SB */
};
struct address_space {
- struct list_head pages; /* list of pages */
- unsigned long nrpages; /* number of pages */
+ struct list_head clean_pages; /* list of clean pages */
+ struct list_head dirty_pages; /* list of dirty pages */
+ struct list_head locked_pages; /* list of locked pages */
+ unsigned long nrpages; /* number of total pages */
struct address_space_operations *a_ops; /* methods */
- void *host; /* owner: inode, block_device */
+ struct inode *host; /* owner: inode, block_device */
struct vm_area_struct *i_mmap; /* list of private mappings */
struct vm_area_struct *i_mmap_shared; /* list of shared mappings */
spinlock_t i_shared_lock; /* and spinlock protecting it */
/* Inode state bits.. */
#define I_DIRTY_SYNC 1 /* Not dirty enough for O_DATASYNC */
#define I_DIRTY_DATASYNC 2 /* Data-related inode changes pending */
-#define I_LOCK 4
-#define I_FREEING 8
-#define I_CLEAR 16
+#define I_DIRTY_PAGES 4 /* Data-related inode changes pending */
+#define I_LOCK 8
+#define I_FREEING 16
+#define I_CLEAR 32
-#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC)
+#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES)
extern void __mark_inode_dirty(struct inode *, int);
static inline void mark_inode_dirty(struct inode *inode)
__mark_inode_dirty(inode, I_DIRTY_SYNC);
}
+static inline void mark_inode_dirty_pages(struct inode *inode)
+{
+ if (inode && !(inode->i_state & I_DIRTY_PAGES))
+ __mark_inode_dirty(inode, I_DIRTY_PAGES);
+}
+
struct fown_struct {
int pid; /* pid or -pgrp where SIGIO should be sent */
uid_t uid, euid; /* uid/euid of process setting the owner */
extern int fsync_inode_buffers(struct inode *);
extern int osync_inode_buffers(struct inode *);
extern int inode_has_buffers(struct inode *);
+extern void filemap_fdatasync(struct address_space *);
+extern void filemap_fdatawait(struct address_space *);
extern void sync_supers(kdev_t);
extern int bmap(struct inode *, int);
extern int notify_change(struct dentry *, struct iattr *);
void gs_start(struct tty_struct *tty);
void gs_hangup(struct tty_struct *tty);
void gs_do_softint(void *private_);
-int block_til_ready(void *port, struct file *filp);
+int gs_block_til_ready(void *port, struct file *filp);
void gs_close(struct tty_struct *tty, struct file *filp);
void gs_set_termios (struct tty_struct * tty,
struct termios * old_termios);
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id: i2c-dev.h,v 1.7 2000/02/15 17:57:27 frodo Exp $ */
+/* $Id: i2c-dev.h,v 1.8 2000/08/12 16:37:15 mds Exp $ */
#ifndef I2C_DEV_H
#define I2C_DEV_H
I2C_SMBUS_BLOCK_DATA, &data);
}
+extern inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
+ __u8 length, __u8 *values)
+{
+ union i2c_smbus_data data;
+ int i;
+ if (length > 32)
+ length = 32;
+ for (i = 1; i <= length; i++)
+ data.block[i] = values[i-1];
+ data.block[0] = length;
+ return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
+ I2C_SMBUS_I2C_BLOCK_DATA, &data);
+}
+
#endif /* ndef __KERNEL__ */
#endif
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* ------------------------------------------------------------------------- */
-/* $Id: i2c-id.h,v 1.16 2000/04/03 18:57:42 frodo Exp $ */
+/* $Id: i2c-id.h,v 1.25 2000/10/12 07:27:29 simon Exp $ */
#ifndef I2C_ID_H
#define I2C_ID_H
#define I2C_DRIVERID_PCF8583 25 /* real time clock */
#define I2C_DRIVERID_SAB3036 26 /* SAB3036 tuner */
#define I2C_DRIVERID_TDA7432 27 /* Stereo sound processor */
+#define I2C_DRIVERID_TVMIXER 28 /* Mixer driver for tv cards */
+#define I2C_DRIVERID_TVAUDIO 29 /* Generic TV sound driver */
+#define I2C_DRIVERID_DPL3518 30 /* Dolby decoder chip */
+#define I2C_DRIVERID_TDA9873 31 /* TV sound decoder chip */
+#define I2C_DRIVERID_TDA9875 32 /* TV sound decoder chip */
+#define I2C_DRIVERID_PIC16C54_PV9 33 /* Audio mux/ir receiver */
+
+#define I2C_DRIVERID_SBATT 34 /* Smart Battery Device */
+#define I2C_DRIVERID_SBS 35 /* SB System Manager */
+#define I2C_DRIVERID_VES1893 36 /* VLSI DVB-S decoder */
+#define I2C_DRIVERID_VES1820 37 /* VLSI DVB-C decoder */
+#define I2C_DRIVERID_SAA7113 38 /* video decoder */
+#define I2C_DRIVERID_TDA8444 39 /* octuple 6-bit DAC */
+
#define I2C_DRIVERID_EXP0 0xF0 /* experimental use id's */
#define I2C_DRIVERID_EXP1 0xF1
#define I2C_ALGO_SMBUS 0x040000
#define I2C_ALGO_ISA 0x050000 /* lm_sensors ISA pseudo-adapter */
#define I2C_ALGO_SAA7146 0x060000 /* SAA 7146 video decoder bus */
+#define I2C_ALGO_ACB 0x070000 /* ACCESS.bus algorithm */
+
+#define I2C_ALGO_EC 0x100000 /* ACPI embedded controller */
+
+#define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */
#define I2C_ALGO_EXP 0x800000 /* experimental */
#define I2C_HW_P_ISA 0x01 /* generic ISA Bus inteface card */
#define I2C_HW_P_ELEK 0x02 /* Elektor ISA Bus inteface card */
+/* --- ACPI Embedded controller algorithms */
+#define I2C_HW_ACPI_EC 0x00
+
+/* --- MPC8xx PowerPC adapters */
+#define I2C_HW_MPC8XX_EPON 0x00 /* Eponymous MPC8xx I2C adapter */
+
/* --- SMBus only adapters */
#define I2C_HW_SMBUS_PIIX4 0x00
#define I2C_HW_SMBUS_ALI15X3 0x01
#define I2C_HW_SMBUS_I801 0x04
#define I2C_HW_SMBUS_AMD756 0x05
#define I2C_HW_SMBUS_SIS5595 0x06
+#define I2C_HW_SMBUS_ALI1535 0x07
/* --- ISA pseudo-adapter */
#define I2C_HW_ISA 0x00
/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and
Frodo Looijaard <frodol@dds.nl> */
-/* $Id: i2c.h,v 1.40 2000/07/19 19:55:45 frodo Exp $ */
+/* $Id: i2c.h,v 1.42 2000/09/06 20:14:06 frodo Exp $ */
#ifndef I2C_H
#define I2C_H
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
u8 command, u8 length,
u8 *values);
+extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client,
+ u8 command, u8 length,
+ u8 *values);
/*
/* SMBus transaction types (size parameter in the above functions)
Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */
-#define I2C_SMBUS_QUICK 0
-#define I2C_SMBUS_BYTE 1
-#define I2C_SMBUS_BYTE_DATA 2
-#define I2C_SMBUS_WORD_DATA 3
-#define I2C_SMBUS_PROC_CALL 4
-#define I2C_SMBUS_BLOCK_DATA 5
+#define I2C_SMBUS_QUICK 0
+#define I2C_SMBUS_BYTE 1
+#define I2C_SMBUS_BYTE_DATA 2
+#define I2C_SMBUS_WORD_DATA 3
+#define I2C_SMBUS_PROC_CALL 4
+#define I2C_SMBUS_BLOCK_DATA 5
+#define I2C_SMBUS_I2C_BLOCK_DATA 6
/* ----- commands for the ioctl like i2c_command call:
#define _LVM_KERNEL_H_VERSION "LVM 0.9 (13/11/2000)"
+#include <linux/config.h>
#include <linux/version.h>
#include <endian.h>
#define PG_arch_1 30
#define PG_reserved 31
-
/* Make it prettier to test the above... */
#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
#define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags)
#define PageLocked(page) test_bit(PG_locked, &(page)->flags)
#define LockPage(page) set_bit(PG_locked, &(page)->flags)
#define TryLockPage(page) test_and_set_bit(PG_locked, &(page)->flags)
+
+extern void __set_page_dirty(struct page *);
+
+static inline void set_page_dirty(struct page * page)
+{
+ if (!test_and_set_bit(PG_dirty, &page->flags))
+ __set_page_dirty(page);
+}
+
/*
* The first mb is necessary to safely close the critical section opened by the
* TryLockPage(), the second mb is necessary to enforce ordering between
extern void ax25_uid_free(void);
/* sysctl_net_ax25.c */
+#ifdef CONFIG_SYSCTL
extern void ax25_register_sysctl(void);
extern void ax25_unregister_sysctl(void);
+#else
+extern inline void ax25_register_sysctl(void) {};
+extern inline void ax25_unregister_sysctl(void) {};
+#endif /* CONFIG_SYSCTL */
#endif
*
*/
+#include <linux/config.h>
#include <linux/malloc.h>
#include <linux/shm.h>
#include <linux/init.h>
static inline void add_page_to_inode_queue(struct address_space *mapping, struct page * page)
{
- struct list_head *head = &mapping->pages;
+ struct list_head *head = &mapping->clean_pages;
mapping->nrpages++;
list_add(&page->list, head);
return 0;
}
+/*
+ * Add a page to the dirty page list.
+ */
+void __set_page_dirty(struct page *page)
+{
+ struct address_space *mapping = page->mapping;
+
+ spin_lock(&pagecache_lock);
+ list_del(&page->list);
+ list_add(&page->list, &mapping->dirty_pages);
+ spin_unlock(&pagecache_lock);
+
+ mark_inode_dirty_pages(mapping->host);
+}
+
/**
* invalidate_inode_pages - Invalidate all the unlocked pages of one inode
* @inode: the inode which pages we want to invalidate
struct list_head *head, *curr;
struct page * page;
- head = &inode->i_mapping->pages;
+ head = &inode->i_mapping->clean_pages;
spin_lock(&pagecache_lock);
spin_lock(&pagemap_lru_lock);
page_cache_release(page);
}
-/**
- * truncate_inode_pages - truncate *all* the pages from an offset
- * @mapping: mapping to truncate
- * @lstart: offset from with to truncate
- *
- * Truncate the page cache at a set offset, removing the pages
- * that are beyond that offset (and zeroing out partial pages).
- * If any page is locked we wait for it to become unlocked.
- */
-void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
+void truncate_list_pages(struct list_head *head, unsigned long start, unsigned partial)
{
- struct list_head *head, *curr;
+ struct list_head *curr;
struct page * page;
- unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
- unsigned long start;
-
- start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
repeat:
- head = &mapping->pages;
spin_lock(&pagecache_lock);
curr = head->next;
while (curr != head) {
spin_unlock(&pagecache_lock);
}
+
+/**
+ * truncate_inode_pages - truncate *all* the pages from an offset
+ * @mapping: mapping to truncate
+ * @lstart: offset from with to truncate
+ *
+ * Truncate the page cache at a set offset, removing the pages
+ * that are beyond that offset (and zeroing out partial pages).
+ * If any page is locked we wait for it to become unlocked.
+ */
+void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
+{
+ unsigned long start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ unsigned partial = lstart & (PAGE_CACHE_SIZE - 1);
+
+ truncate_list_pages(&mapping->clean_pages, start, partial);
+ truncate_list_pages(&mapping->dirty_pages, start, partial);
+ truncate_list_pages(&mapping->locked_pages, start, partial);
+}
+
static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
{
goto inside;
return error;
}
-static int do_buffer_fdatasync(struct inode *inode, unsigned long start, unsigned long end, int (*fn)(struct page *))
+static int do_buffer_fdatasync(struct list_head *head, unsigned long start, unsigned long end, int (*fn)(struct page *))
{
- struct list_head *head, *curr;
+ struct list_head *curr;
struct page *page;
int retval = 0;
- head = &inode->i_mapping->pages;
-
spin_lock(&pagecache_lock);
curr = head->next;
while (curr != head) {
{
int retval;
- retval = do_buffer_fdatasync(inode, start_idx, end_idx, writeout_one_page);
- retval |= do_buffer_fdatasync(inode, start_idx, end_idx, waitfor_one_page);
+ /* writeout dirty buffers on pages from both clean and dirty lists */
+ retval = do_buffer_fdatasync(&inode->i_mapping->dirty_pages, start_idx, end_idx, writeout_one_page);
+ retval |= do_buffer_fdatasync(&inode->i_mapping->clean_pages, start_idx, end_idx, writeout_one_page);
+ retval |= do_buffer_fdatasync(&inode->i_mapping->locked_pages, start_idx, end_idx, writeout_one_page);
+
+ /* now wait for locked buffers on pages from both clean and dirty lists */
+ retval |= do_buffer_fdatasync(&inode->i_mapping->dirty_pages, start_idx, end_idx, writeout_one_page);
+ retval |= do_buffer_fdatasync(&inode->i_mapping->clean_pages, start_idx, end_idx, waitfor_one_page);
+ retval |= do_buffer_fdatasync(&inode->i_mapping->locked_pages, start_idx, end_idx, waitfor_one_page);
+
return retval;
}
+/**
+ * filemap_fdatasync - walk the list of dirty pages of the given address space
+ * and writepage() all of them.
+ *
+ * @mapping: address space structure to write
+ *
+ */
+void filemap_fdatasync(struct address_space * mapping)
+{
+ int (*writepage)(struct page *) = mapping->a_ops->writepage;
+
+ spin_lock(&pagecache_lock);
+
+ while (!list_empty(&mapping->dirty_pages)) {
+ struct page *page = list_entry(mapping->dirty_pages.next, struct page, list);
+
+ list_del(&page->list);
+ list_add(&page->list, &mapping->locked_pages);
+
+ if (!PageDirty(page))
+ continue;
+
+ page_cache_get(page);
+ spin_unlock(&pagecache_lock);
+
+ lock_page(page);
+
+ if (PageDirty(page)) {
+ ClearPageDirty(page);
+ writepage(page);
+ } else
+ UnlockPage(page);
+
+ page_cache_release(page);
+ spin_lock(&pagecache_lock);
+ }
+ spin_unlock(&pagecache_lock);
+}
+
+/**
+ * filemap_fdatawait - walk the list of locked pages of the given address space
+ * and wait for all of them.
+ *
+ * @mapping: address space structure to wait for
+ *
+ */
+void filemap_fdatawait(struct address_space * mapping)
+{
+ spin_lock(&pagecache_lock);
+
+ while (!list_empty(&mapping->locked_pages)) {
+ struct page *page = list_entry(mapping->locked_pages.next, struct page, list);
+
+ list_del(&page->list);
+ list_add(&page->list, &mapping->clean_pages);
+
+ if (!PageLocked(page))
+ continue;
+
+ page_cache_get(page);
+ spin_unlock(&pagecache_lock);
+
+ ___wait_on_page(page);
+
+ page_cache_release(page);
+ spin_lock(&pagecache_lock);
+ }
+ spin_unlock(&pagecache_lock);
+}
+
/*
* Add a page to the inode page cache.
*
return NULL;
}
-/*
- * If a task terminates while we're swapping the page, the vma and
- * and file could be released: try_to_swap_out has done a get_file.
- * vma/file is guaranteed to exist in the unmap/sync cases because
- * mmap_sem is held.
- *
- * The "mapping" test takes care of somebody having truncated the
- * page and thus made this write-page a no-op..
- */
-static int filemap_write_page(struct page * page, int wait)
-{
- struct address_space * mapping = page->mapping;
- int error = 0;
-
- if (mapping && mapping->a_ops->writepage) {
- ClearPageDirty(page);
- error = mapping->a_ops->writepage(page);
- }
- return error;
-}
-
-
/* Called with mm->page_table_lock held to protect against other
* threads/the swapper from ripping pte's out from under us.
*/
static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
unsigned long address, unsigned int flags)
{
- pte_t pte;
- struct page *page;
- int error;
-
- pte = *ptep;
+ pte_t pte = *ptep;
- if (!pte_present(pte))
- goto out;
- if (!ptep_test_and_clear_dirty(ptep))
- goto out;
-
- flush_page_to_ram(pte_page(pte));
- flush_cache_page(vma, address);
- flush_tlb_page(vma, address);
- page = pte_page(pte);
- page_cache_get(page);
- spin_unlock(&vma->vm_mm->page_table_lock);
-
- lock_page(page);
- error = filemap_write_page(page, 1);
- page_cache_free(page);
-
- spin_lock(&vma->vm_mm->page_table_lock);
- return error;
-
-out:
+ if (pte_present(pte) && ptep_test_and_clear_dirty(ptep)) {
+ struct page *page = pte_page(pte);
+ flush_tlb_page(vma, address);
+ set_page_dirty(page);
+ }
return 0;
}
if (!error && (flags & MS_SYNC)) {
struct file * file = vma->vm_file;
if (file && file->f_op && file->f_op->fsync) {
- down(&file->f_dentry->d_inode->i_sem);
+ struct inode * inode = file->f_dentry->d_inode;
+ down(&inode->i_sem);
+ filemap_fdatasync(inode->i_mapping);
error = file->f_op->fsync(file, file->f_dentry, 1);
- up(&file->f_dentry->d_inode->i_sem);
+ filemap_fdatawait(inode->i_mapping);
+ up(&inode->i_sem);
}
}
return error;
/*
* Return indicates whether a page was freed so caller can adjust rss
*/
-static inline int free_pte(pte_t page)
+static inline int free_pte(pte_t pte)
{
- if (pte_present(page)) {
- struct page *ptpage = pte_page(page);
- if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
+ if (pte_present(pte)) {
+ struct page *page = pte_page(pte);
+ if ((!VALID_PAGE(page)) || PageReserved(page))
return 0;
/*
* free_page() used to be able to clear swap cache
* entries. We may now have to do it manually.
*/
- if (pte_dirty(page))
- SetPageDirty(ptpage);
- free_page_and_swap_cache(ptpage);
+ if (pte_dirty(pte) && page->mapping)
+ set_page_dirty(page);
+ free_page_and_swap_cache(page);
return 1;
}
- swap_free(pte_to_swp_entry(page));
+ swap_free(pte_to_swp_entry(pte));
return 0;
}
#include <linux/file.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
-#include <linux/init.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <asm/smplock.h>
struct shmem_inode_info *info;
swp_entry_t *entry, swap;
- info = &((struct inode *)page->mapping->host)->u.shmem_i;
+ info = &page->mapping->host->u.shmem_i;
if (info->locked)
return 1;
swap = __get_swap_page(2);
/* Add it to the swap cache */
add_to_swap_cache(page, swap);
page_cache_release(page);
- SetPageDirty(page);
+ set_page_dirty(page);
info->swapped++;
out:
spin_unlock(&info->lock);
spin_unlock (&info->lock);
return 0;
found:
- add_to_page_cache (page, inode->i_mapping, offset + idx);
- SetPageDirty (page);
- SetPageUptodate (page);
- UnlockPage (page);
+ add_to_page_cache(page, inode->i_mapping, offset + idx);
+ set_page_dirty(page);
+ SetPageUptodate(page);
+ UnlockPage(page);
info->swapped--;
- spin_unlock (&info->lock);
+ spin_unlock(&info->lock);
return 1;
}
};
struct address_space swapper_space = {
- { /* pages */
- &swapper_space.pages, /* .next */
- &swapper_space.pages /* .prev */
- },
+ LIST_HEAD_INIT(swapper_space.clean_pages),
+ LIST_HEAD_INIT(swapper_space.dirty_pages),
+ LIST_HEAD_INIT(swapper_space.locked_pages),
0, /* nrpages */
&swap_aops,
};
if (PageSwapCache(page)) {
entry.val = page->index;
if (pte_dirty(pte))
- SetPageDirty(page);
+ set_page_dirty(page);
set_swap_pte:
swap_duplicate(entry);
set_pte(page_table, swp_entry_to_pte(entry));
* entry for it, or we should write it back
* to its own backing store.
*/
- flush_cache_page(vma, address);
if (page->mapping) {
- SetPageDirty(page);
+ set_page_dirty(page);
goto drop_pte;
}
/* Add it to the swap cache and mark it dirty */
add_to_swap_cache(page, entry);
- SetPageDirty(page);
+ set_page_dirty(page);
goto set_swap_pte;
out_unlock_restore:
if (result != 1)
continue;
/* writepage refused to do anything */
- SetPageDirty(page);
+ set_page_dirty(page);
goto page_active;
}
*/
static DECLARE_MUTEX(local_lock);
-
+extern spinlock_t atm_dev_lock;
static void notify_sigd(struct atm_dev *dev)
{
struct atm_dev_addr *this;
down(&local_lock);
+ spin_lock (&atm_dev_lock);
while (dev->local) {
this = dev->local;
dev->local = this->next;
kfree(this);
}
up(&local_lock);
+ spin_unlock (&atm_dev_lock);
notify_sigd(dev);
}
#define DPRINTK(format,args...)
#endif
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
{
vcc->dev->ops->free_rx_skb(vcc,skb);
else kfree_skb(skb);
}
+ spin_lock (&atm_dev_lock);
+ fops_put (vcc->dev->ops);
if (atomic_read(&vcc->rx_inuse))
printk(KERN_WARNING "atm_release_vcc: strange ... "
"rx_inuse == %d after closing\n",
atomic_read(&vcc->rx_inuse));
bind_vcc(vcc,NULL);
- }
+ } else
+ spin_lock (&atm_dev_lock);
+
if (free_sk) free_atm_vcc_sk(sk);
+
+ spin_unlock (&atm_dev_lock);
}
vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
DPRINTK(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
+ fops_get (dev->ops);
if (dev->ops->open) {
error = dev->ops->open(vcc,vpi,vci);
if (error) {
+ fops_put (dev->ops);
bind_vcc(vcc,NULL);
return error;
}
static int atm_do_connect(struct atm_vcc *vcc,int itf,int vpi,int vci)
{
struct atm_dev *dev;
+ int return_val;
+ spin_lock (&atm_dev_lock);
dev = atm_find_dev(itf);
- if (!dev) return -ENODEV;
- return atm_do_connect_dev(vcc,dev,vpi,vci);
+ if (!dev)
+ return_val = -ENODEV;
+ else
+ return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
+
+ spin_unlock (&atm_dev_lock);
+
+ return return_val;
}
else {
struct atm_dev *dev;
+ spin_lock (&atm_dev_lock);
for (dev = atm_devs; dev; dev = dev->next)
if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+ spin_unlock (&atm_dev_lock);
if (!dev) return -ENODEV;
}
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
struct atm_vcc *vcc;
int *tmp_buf;
void *buf;
- int error,len,size,number;
+ int error,len,size,number, ret_val;
+ ret_val = 0;
+ spin_lock (&atm_dev_lock);
vcc = ATM_SD(sock);
switch (cmd) {
case SIOCOUTQ:
if (sock->state != SS_CONNECTED ||
- !test_bit(ATM_VF_READY,&vcc->flags))
- return -EINVAL;
- return put_user(vcc->sk->sndbuf-
+ !test_bit(ATM_VF_READY,&vcc->flags)) {
+ ret_val = -EINVAL;
+ goto done;
+ }
+ ret_val = put_user(vcc->sk->sndbuf-
atomic_read(&vcc->tx_inuse)-ATM_PDU_OVHD,
(int *) arg) ? -EFAULT : 0;
+ goto done;
case SIOCINQ:
{
struct sk_buff *skb;
- if (sock->state != SS_CONNECTED)
- return -EINVAL;
+ if (sock->state != SS_CONNECTED) {
+ ret_val = -EINVAL;
+ goto done;
+ }
skb = skb_peek(&vcc->recvq);
- return put_user(skb ? skb->len : 0,(int *) arg)
+ ret_val = put_user(skb ? skb->len : 0,(int *) arg)
? -EFAULT : 0;
+ goto done;
}
case ATM_GETNAMES:
if (get_user(buf,
- &((struct atm_iobuf *) arg)->buffer))
- return -EFAULT;
+ &((struct atm_iobuf *) arg)->buffer)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
if (get_user(len,
- &((struct atm_iobuf *) arg)->length))
- return -EFAULT;
+ &((struct atm_iobuf *) arg)->length)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
size = 0;
for (dev = atm_devs; dev; dev = dev->next)
size += sizeof(int);
- if (size > len) return -E2BIG;
+ if (size > len) {
+ ret_val = -E2BIG;
+ goto done;
+ }
tmp_buf = kmalloc(size,GFP_KERNEL);
- if (!tmp_buf) return -ENOMEM;
+ if (!tmp_buf) {
+ ret_val = -ENOMEM;
+ goto done;
+ }
for (dev = atm_devs; dev; dev = dev->next)
*tmp_buf++ = dev->number;
- if (copy_to_user(buf,(char *) tmp_buf-size,size))
- return -EFAULT;
- return put_user(size,
+ if (copy_to_user(buf,(char *) tmp_buf-size,size)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
+ ret_val = put_user(size,
&((struct atm_iobuf *) arg)->length) ? -EFAULT : 0;
+ goto done;
case SIOCGSTAMP: /* borrowed from IP */
- if (!vcc->timestamp.tv_sec) return -ENOENT;
+ if (!vcc->timestamp.tv_sec) {
+ ret_val = -ENOENT;
+ goto done;
+ }
vcc->timestamp.tv_sec += vcc->timestamp.tv_usec/1000000;
vcc->timestamp.tv_usec %= 1000000;
- return copy_to_user((void *) arg,&vcc->timestamp,
+ ret_val = copy_to_user((void *) arg,&vcc->timestamp,
sizeof(struct timeval)) ? -EFAULT : 0;
+ goto done;
case ATM_SETSC:
printk(KERN_WARNING "ATM_SETSC is obsolete\n");
- return 0;
+ ret_val = 0;
+ goto done;
case ATMSIGD_CTRL:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
/*
* The user/kernel protocol for exchanging signalling
* info uses kernel pointers as opaque references,
* on the kernel... so we should make sure that we
* have the same privledges that /proc/kcore needs
*/
- if (!capable(CAP_SYS_RAWIO)) return -EPERM;
+ if (!capable(CAP_SYS_RAWIO)) {
+ ret_val = -EPERM;
+ goto done;
+ }
error = sigd_attach(vcc);
if (!error) sock->state = SS_CONNECTED;
- return error;
+ ret_val = error;
+ goto done;
#ifdef CONFIG_ATM_CLIP
case SIOCMKCLIP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return clip_create(arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = clip_create(arg);
+ goto done;
case ATMARPD_CTRL:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
error = atm_init_atmarp(vcc);
if (!error) sock->state = SS_CONNECTED;
- return error;
+ ret_val = error;
+ goto done;
case ATMARP_MKIP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return clip_mkip(vcc,arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = clip_mkip(vcc,arg);
+ goto done;
case ATMARP_SETENTRY:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return clip_setentry(vcc,arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = clip_setentry(vcc,arg);
+ goto done;
case ATMARP_ENCAP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return clip_encap(vcc,arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = clip_encap(vcc,arg);
+ goto done;
#endif
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
case ATMLEC_CTRL:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
if (atm_lane_ops.lecd_attach == NULL)
atm_lane_init();
- if (atm_lane_ops.lecd_attach == NULL) /* try again */
- return -ENOSYS;
- error = atm_lane_ops.lecd_attach(vcc, (int)arg);
- if (error >= 0) sock->state = SS_CONNECTED;
- return error;
+ if (atm_lane_ops.lecd_attach == NULL) { /* try again */
+ ret_val = -ENOSYS;
+ goto done;
+ }
+ error = atm_lane_ops.lecd_attach(vcc, (int)arg);
+ if (error >= 0) sock->state = SS_CONNECTED;
+ ret_val = error;
+ goto done;
case ATMLEC_MCAST:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return atm_lane_ops.mcast_attach(vcc, (int)arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg);
+ goto done;
case ATMLEC_DATA:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return atm_lane_ops.vcc_attach(vcc, (void*)arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg);
+ goto done;
#endif
#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE)
case ATMMPC_CTRL:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (atm_mpoa_ops.mpoad_attach == NULL)
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
+ if (atm_mpoa_ops.mpoad_attach == NULL)
atm_mpoa_init();
- if (atm_mpoa_ops.mpoad_attach == NULL) /* try again */
- return -ENOSYS;
- error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
- if (error >= 0) sock->state = SS_CONNECTED;
- return error;
+ if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */
+ ret_val = -ENOSYS;
+ goto done;
+ }
+ error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg);
+ if (error >= 0) sock->state = SS_CONNECTED;
+ ret_val = error;
+ goto done;
case ATMMPC_DATA:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- return atm_mpoa_ops.vcc_attach(vcc, arg);
+ if (!capable(CAP_NET_ADMIN))
+ ret_val = -EPERM;
+ else
+ ret_val = atm_mpoa_ops.vcc_attach(vcc, arg);
+ goto done;
#endif
#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE)
case SIOCSIFATMTCP:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (!atm_tcp_ops.attach) return -ENOPKG;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
+ if (!atm_tcp_ops.attach) {
+ ret_val = -ENOPKG;
+ goto done;
+ }
+ fops_get (&atm_tcp_ops);
error = atm_tcp_ops.attach(vcc,(int) arg);
if (error >= 0) sock->state = SS_CONNECTED;
- return error;
+ else fops_put (&atm_tcp_ops);
+ ret_val = error;
+ goto done;
case ATMTCP_CREATE:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (!atm_tcp_ops.create_persistent) return -ENOPKG;
- return atm_tcp_ops.create_persistent((int) arg);
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
+ if (!atm_tcp_ops.create_persistent) {
+ ret_val = -ENOPKG;
+ goto done;
+ }
+ error = atm_tcp_ops.create_persistent((int) arg);
+ if (error < 0) fops_put (&atm_tcp_ops);
+ ret_val = error;
+ goto done;
case ATMTCP_REMOVE:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (!atm_tcp_ops.remove_persistent) return -ENOPKG;
- return atm_tcp_ops.remove_persistent((int) arg);
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
+ if (!atm_tcp_ops.remove_persistent) {
+ ret_val = -ENOPKG;
+ goto done;
+ }
+ error = atm_tcp_ops.remove_persistent((int) arg);
+ fops_put (&atm_tcp_ops);
+ ret_val = error;
+ goto done;
#endif
default:
break;
}
- if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) return -EFAULT;
- if (get_user(len,&((struct atmif_sioc *) arg)->length)) return -EFAULT;
- if (get_user(number,&((struct atmif_sioc *) arg)->number))
- return -EFAULT;
- if (!(dev = atm_find_dev(number))) return -ENODEV;
+ if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
+ if (get_user(len,&((struct atmif_sioc *) arg)->length)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
+ if (get_user(number,&((struct atmif_sioc *) arg)->number)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
+ if (!(dev = atm_find_dev(number))) {
+ ret_val = -ENODEV;
+ goto done;
+ }
+
size = 0;
switch (cmd) {
case ATM_GETTYPE:
size = strlen(dev->type)+1;
- if (copy_to_user(buf,dev->type,size)) return -EFAULT;
+ if (copy_to_user(buf,dev->type,size)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
break;
case ATM_GETESI:
size = ESI_LEN;
- if (copy_to_user(buf,dev->esi,size)) return -EFAULT;
+ if (copy_to_user(buf,dev->esi,size)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
break;
case ATM_SETESI:
{
int i;
for (i = 0; i < ESI_LEN; i++)
- if (dev->esi[i]) return -EEXIST;
+ if (dev->esi[i]) {
+ ret_val = -EEXIST;
+ goto done;
+ }
}
/* fall through */
case ATM_SETESIF:
{
unsigned char esi[ESI_LEN];
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (copy_from_user(esi,buf,ESI_LEN))
- return -EFAULT;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
+ if (copy_from_user(esi,buf,ESI_LEN)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
memcpy(dev->esi,esi,ESI_LEN);
- return ESI_LEN;
+ ret_val = ESI_LEN;
+ goto done;
}
case ATM_GETSTATZ:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
/* fall through */
case ATM_GETSTAT:
size = sizeof(struct atm_dev_stats);
error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
- if (error) return error;
+ if (error) {
+ ret_val = error;
+ goto done;
+ }
break;
case ATM_GETCIRANGE:
size = sizeof(struct atm_cirange);
- if (copy_to_user(buf,&dev->ci_range,size))
- return -EFAULT;
+ if (copy_to_user(buf,&dev->ci_range,size)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
break;
case ATM_GETLINKRATE:
size = sizeof(int);
- if (copy_to_user(buf,&dev->link_rate,size))
- return -EFAULT;
+ if (copy_to_user(buf,&dev->link_rate,size)) {
+ ret_val = -EFAULT;
+ goto done;
+ }
break;
case ATM_RSTADDR:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
reset_addr(dev);
break;
case ATM_ADDADDR:
case ATM_DELADDR:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
{
struct sockaddr_atmsvc addr;
- if (copy_from_user(&addr,buf,sizeof(addr)))
- return -EFAULT;
+ if (copy_from_user(&addr,buf,sizeof(addr))) {
+ ret_val = -EFAULT;
+ goto done;
+ }
if (cmd == ATM_ADDADDR)
- return add_addr(dev,&addr);
- else return del_addr(dev,&addr);
+ ret_val = add_addr(dev,&addr);
+ else
+ ret_val = del_addr(dev,&addr);
+ goto done;
}
case ATM_GETADDR:
size = get_addr(dev,buf,len);
- if (size < 0) return size;
+ if (size < 0)
+ ret_val = size;
+ else
/* may return 0, but later on size == 0 means "don't
write the length" */
- return put_user(size,
- &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+ ret_val = put_user(size,
+ &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
+ goto done;
case ATM_SETLOOP:
if (__ATM_LM_XTRMT((int) (long) buf) &&
__ATM_LM_XTLOC((int) (long) buf) >
- __ATM_LM_XTRMT((int) (long) buf))
- return -EINVAL;
+ __ATM_LM_XTRMT((int) (long) buf)) {
+ ret_val = -EINVAL;
+ goto done;
+ }
/* fall through */
case ATM_SETCIRANGE:
case SONET_GETSTATZ:
case SONET_SETDIAG:
case SONET_CLRDIAG:
case SONET_SETFRAMING:
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ if (!capable(CAP_NET_ADMIN)) {
+ ret_val = -EPERM;
+ goto done;
+ }
/* fall through */
default:
- if (!dev->ops->ioctl) return -EINVAL;
+ if (!dev->ops->ioctl) {
+ ret_val = -EINVAL;
+ goto done;
+ }
size = dev->ops->ioctl(dev,cmd,buf);
- if (size < 0)
- return size == -ENOIOCTLCMD ? -EINVAL : size;
+ if (size < 0) {
+ ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
+ goto done;
+ }
}
- if (!size) return 0;
- return put_user(size,&((struct atmif_sioc *) arg)->length) ?
- -EFAULT : 0;
+
+ if (size)
+ ret_val = put_user(size,&((struct atmif_sioc *) arg)->length) ?
+ -EFAULT : 0;
+
+ done:
+ spin_unlock (&atm_dev_lock);
+ return ret_val;
}
size = sizeof(struct lec_priv);
#ifdef CONFIG_TR
if (is_trdev)
- dev_lec[i] = init_trdev(NULL, size);
+ dev_lec[i] = prepare_trdev(NULL, size);
else
#endif
- dev_lec[i] = init_etherdev(NULL, size);
+ dev_lec[i] = prepare_etherdev(NULL, size);
if (!dev_lec[i])
return -ENOMEM;
priv->is_trdev = is_trdev;
sprintf(dev_lec[i]->name, "lec%d", i);
lec_init(dev_lec[i]);
+ publish_netdev(dev_lec[i]);
} else {
priv = dev_lec[i]->priv;
if (priv->lecd)
for (i = 0; i < MAX_LEC_ITF; i++) {
if (dev_lec[i] != NULL) {
priv = (struct lec_priv *)dev_lec[i]->priv;
- if (priv->is_trdev) {
-#ifdef CONFIG_TR
- unregister_trdev(dev_lec[i]);
-#endif
- } else
- unregister_netdev(dev_lec[i]);
+ unregister_netdev(dev_lec[i]);
kfree(dev_lec[i]);
dev_lec[i] = NULL;
}
default:
here += sprintf(here,"%3d",vcc->family);
}
- here += sprintf(here," %04x %5ld %7d/%7d %7d/%7d\n",vcc->flags.bits,
+ here += sprintf(here," %04lx %5d %7d/%7d %7d/%7d\n",vcc->flags.bits,
vcc->reply,
atomic_read(&vcc->tx_inuse),vcc->sk->sndbuf,
atomic_read(&vcc->rx_inuse),vcc->sk->rcvbuf);
struct atm_dev *atm_devs = NULL;
static struct atm_dev *last_dev = NULL;
struct atm_vcc *nodev_vccs = NULL;
+extern spinlock_t atm_dev_lock;
static struct atm_dev *alloc_atm_dev(const char *type)
static void free_atm_dev(struct atm_dev *dev)
{
+ spin_lock (&atm_dev_lock);
+
if (dev->prev) dev->prev->next = dev->next;
else atm_devs = dev->next;
if (dev->next) dev->next->prev = dev->prev;
else last_dev = dev->prev;
kfree(dev);
+
+ spin_unlock (&atm_dev_lock);
}
if (atm_proc_dev_register(dev) < 0) {
printk(KERN_ERR "atm_dev_register: "
"atm_proc_dev_register failed for dev %s\n",type);
+ spin_unlock (&atm_dev_lock);
free_atm_dev(dev);
return NULL;
}
#endif
+ spin_unlock (&atm_dev_lock);
return dev;
}
struct atm_vcc *sigd = NULL;
static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
+extern spinlock_t atm_dev_lock;
static void sigd_put_skb(struct sk_buff *skb)
{
printk(KERN_ERR "sigd_close: closing with requests pending\n");
while ((skb = skb_dequeue(&vcc->recvq))) kfree_skb(skb);
purge_vccs(nodev_vccs);
+
+ spin_lock (&atm_dev_lock);
for (dev = atm_devs; dev; dev = dev->next) purge_vccs(dev->vccs);
+ spin_unlock (&atm_dev_lock);
}
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
-ax25_cb *volatile ax25_list = NULL;
+ax25_cb *volatile ax25_list;
static struct proto_ops ax25_proto_ops;
ax25_packet_type.type = htons(ETH_P_AX25);
dev_add_pack(&ax25_packet_type);
register_netdevice_notifier(&ax25_dev_notifier);
-#ifdef CONFIG_SYSCTL
ax25_register_sysctl();
-#endif
-#ifdef CONFIG_PROC_FS
proc_net_create("ax25_route", 0, ax25_rt_get_info);
proc_net_create("ax25", 0, ax25_get_info);
proc_net_create("ax25_calls", 0, ax25_uid_get_info);
-#endif
printk(KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n");
return 0;
module_init(ax25_init);
-#ifdef MODULE
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");
static void __exit ax25_exit(void)
{
-#ifdef CONFIG_PROC_FS
proc_net_remove("ax25_route");
proc_net_remove("ax25");
proc_net_remove("ax25_calls");
-#endif
ax25_rt_free();
ax25_uid_free();
ax25_dev_free();
-#ifdef CONFIG_SYSCTL
ax25_unregister_sysctl();
-#endif
unregister_netdevice_notifier(&ax25_dev_notifier);
ax25_packet_type.type = htons(ETH_P_AX25);
sock_unregister(PF_AX25);
}
module_exit(ax25_exit);
-#endif /* MODULE */
-
-#endif
* AX.25 036 Jonathan(G4KLX) Split from ax25_subr.c.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
}
}
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
-ax25_dev *ax25_dev_list = NULL;
+ax25_dev *ax25_dev_list;
ax25_dev *ax25_dev_ax25dev(struct net_device *dev)
{
return;
}
-#ifdef CONFIG_SYSCTL
ax25_unregister_sysctl();
-#endif
memset(ax25_dev, 0x00, sizeof(*ax25_dev));
ax25_dev_list = ax25_dev;
restore_flags(flags);
-#ifdef CONFIG_SYSCTL
ax25_register_sysctl();
-#endif
}
void ax25_dev_device_down(struct net_device *dev)
if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL)
return;
-#ifdef CONFIG_SYSCTL
ax25_unregister_sysctl();
-#endif
save_flags(flags); cli();
ax25_dev_list = s->next;
restore_flags(flags);
kfree(ax25_dev);
-#ifdef CONFIG_SYSCTL
ax25_register_sysctl();
-#endif
return;
}
s->next = ax25_dev->next;
restore_flags(flags);
kfree(ax25_dev);
-#ifdef CONFIG_SYSCTL
ax25_register_sysctl();
-#endif
return;
}
}
restore_flags(flags);
-#ifdef CONFIG_SYSCTL
ax25_register_sysctl();
-#endif
}
int ax25_fwd_ioctl(unsigned int cmd, struct ax25_fwd_struct *fwd)
return ax25_dev->forward;
}
-#ifdef MODULE
-
/*
* Free all memory associated with device structures.
*/
-void ax25_dev_free(void)
+void __exit ax25_dev_free(void)
{
ax25_dev *s, *ax25_dev = ax25_dev_list;
kfree(s);
}
}
-
-#endif
-
-#endif
* Joerg(DL1BKE) ax25->n2count never got reset
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25_DAMA_SLAVE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
return queued;
}
-#endif
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25_DAMA_SLAVE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
ax25_dev_dama_off(ax25->ax25_dev);
}
-#endif
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25_DAMA_SLAVE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
}
-
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
struct protocol_struct *next;
unsigned int pid;
int (*func)(struct sk_buff *, ax25_cb *);
-} *protocol_list = NULL;
+} *protocol_list;
static struct linkfail_struct {
struct linkfail_struct *next;
void (*func)(ax25_cb *, int);
-} *linkfail_list = NULL;
+} *linkfail_list;
static struct listen_struct {
struct listen_struct *next;
ax25_address callsign;
struct net_device *dev;
-} *listen_list = NULL;
+} *listen_list;
int ax25_protocol_register(unsigned int pid, int (*func)(struct sk_buff *, ax25_cb *))
{
return 0;
}
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype);
}
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#endif
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
return 0;
}
-#endif
* Arnaldo C. Melo s/suser/capable/
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
-static ax25_route *ax25_route_list = NULL;
+static ax25_route *ax25_route_list;
static ax25_route *ax25_find_route(ax25_address *, struct net_device *);
return skb;
}
-#ifdef MODULE
-
/*
* Free all memory associated with routing structures.
*/
-void ax25_rt_free(void)
+void __exit ax25_rt_free(void)
{
ax25_route *s, *ax25_rt = ax25_route_list;
kfree(s);
}
}
-
-#endif
-
-#endif
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
return queued;
}
-
-#endif
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
ax25->condition &= ~AX25_COND_ACK_PENDING;
}
-
-#endif
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
ax25_calculate_t1(ax25);
ax25_start_t1timer(ax25);
}
-
-#endif
* AX.25 037 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
ax25->sk->dead = 1;
}
}
-
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#endif
}
}
-
-#endif
* AX.25 036 Jonathan(G4KLX) Split from af_ax25.c.
*/
-#include <linux/config.h>
-#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
* Callsign/UID mapper. This is in kernel space for security on multi-amateur machines.
*/
-static ax25_uid_assoc *ax25_uid_list = NULL;
+static ax25_uid_assoc *ax25_uid_list;
int ax25_uid_policy = 0;
return len;
}
-#ifdef MODULE
-
/*
* Free all memory associated with UID/Callsign structures.
*/
-void ax25_uid_free(void)
+void __exit ax25_uid_free(void)
{
ax25_uid_assoc *s, *ax25_uid = ax25_uid_list;
kfree(s);
}
}
-
-#endif
-
-#endif
printk(".");
jiff = jiffies + timeout;
while (jiffies < jiff && !ic_got_reply)
- ;
+ barrier();
if (ic_got_reply) {
printk(" OK\n");
break;
*/
#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
static unsigned short circuit = 0x101;
-static struct sock *volatile nr_list = NULL;
+static struct sock *volatile nr_list;
static struct proto_ops nr_proto_ops;
sock_register(&nr_family_ops);
register_netdevice_notifier(&nr_dev_notifier);
- printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.1\n");
+ printk(KERN_INFO "G4KLX NET/ROM for Linux. Version 0.7 for AX25.037 Linux 2.4\n");
ax25_protocol_register(AX25_P_NETROM, nr_route_frame);
ax25_linkfail_register(nr_link_failed);
nr_loopback_init();
-#ifdef CONFIG_PROC_FS
proc_net_create("nr", 0, nr_get_info);
proc_net_create("nr_neigh", 0, nr_neigh_get_info);
proc_net_create("nr_nodes", 0, nr_nodes_get_info);
-#endif
return 0;
}
module_init(nr_proto_init);
-#ifdef MODULE
EXPORT_NO_SYMBOLS;
MODULE_PARM(nr_ndevs, "i");
MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");
MODULE_DESCRIPTION("The amateur radio NET/ROM network and transport layer protocol");
-static void nr_exit(void)
+static void __exit nr_exit(void)
{
int i;
-#ifdef CONFIG_PROC_FS
proc_net_remove("nr");
proc_net_remove("nr_neigh");
proc_net_remove("nr_nodes");
-#endif
nr_loopback_clear();
nr_rt_free();
kfree(dev_nr);
}
module_exit(nr_exit);
-#endif /* MODULE */
-
-
-
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/proc_fs.h>
return 0;
};
-
-#endif
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
return queued;
}
-
-#endif
*
*/
-#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <net/ax25.h>
#include <linux/skbuff.h>
#include <net/netrom.h>
+#include <linux/init.h>
static struct sk_buff_head loopback_queue;
static struct timer_list loopback_timer;
}
}
-#ifdef MODULE
-
-void nr_loopback_clear(void)
+void __exit nr_loopback_clear(void)
{
struct sk_buff *skb;
while ((skb = skb_dequeue(&loopback_queue)) != NULL)
kfree_skb(skb);
}
-
-#endif
-
-#endif
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
}
}
}
-
-#endif
* Tomi(OH2BNS) Routing quality and link failure changes.
*/
-#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/netfilter.h>
+#include <linux/init.h>
#include <net/netrom.h>
static unsigned int nr_neigh_no = 1;
-static struct nr_node *nr_node_list = NULL;
-static struct nr_neigh *nr_neigh_list = NULL;
+static struct nr_node *nr_node_list;
+static struct nr_neigh *nr_neigh_list;
static void nr_remove_neigh(struct nr_neigh *);
return len;
}
-#ifdef MODULE
-
/*
* Free all memory associated with the nodes and routes lists.
*/
-void nr_rt_free(void)
+void __exit nr_rt_free(void)
{
struct nr_neigh *s, *nr_neigh = nr_neigh_list;
struct nr_node *t, *nr_node = nr_node_list;
nr_remove_neigh(s);
}
}
-
-#endif
-
-#endif
* NET/ROM 007 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
sk->dead = 1;
}
-
-#endif
* Implemented idle timer.
*/
-#include <linux/config.h>
-#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
nr_start_t1timer(sk);
}
-
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
sock_register(&rose_family_ops);
register_netdevice_notifier(&rose_dev_notifier);
- printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.1\n");
+ printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n");
ax25_protocol_register(AX25_P_ROSE, rose_route_frame);
ax25_linkfail_register(rose_link_failed);
rose_add_loopback_neigh();
-#ifdef CONFIG_PROC_FS
proc_net_create("rose", 0, rose_get_info);
proc_net_create("rose_neigh", 0, rose_neigh_get_info);
proc_net_create("rose_nodes", 0, rose_nodes_get_info);
proc_net_create("rose_routes", 0, rose_routes_get_info);
-#endif
return 0;
}
module_init(rose_proto_init);
-#ifdef MODULE
EXPORT_NO_SYMBOLS;
MODULE_PARM(rose_ndevs, "i");
{
int i;
-#ifdef CONFIG_PROC_FS
proc_net_remove("rose");
proc_net_remove("rose_neigh");
proc_net_remove("rose_nodes");
proc_net_remove("rose_routes");
-#endif
rose_loopback_clear();
rose_rt_free();
kfree(dev_rose);
}
module_exit(rose_exit);
-#endif /* MODULE */
-
-#endif
*/
#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/proc_fs.h>
return 0;
};
-
-#endif
* Removed M bit processing.
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
return queued;
}
-
-#endif
* ROSE 003 Jonathan(G4KLX) New timer architecture.
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
}
}
}
-
-#endif
*
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/timer.h>
#include <net/ax25.h>
#include <linux/skbuff.h>
#include <net/rose.h>
+#include <linux/init.h>
static struct sk_buff_head loopback_queue;
static struct timer_list loopback_timer;
}
}
-#ifdef MODULE
-
-void rose_loopback_clear(void)
+void __exit rose_loopback_clear(void)
{
struct sk_buff *skb;
kfree_skb(skb);
}
}
-
-#endif
-
-#endif
* Removed M bit processing.
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
rose_stop_timer(sk);
}
-
-#endif
* Added use count to neighbours.
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/netfilter.h>
+#include <linux/init.h>
#include <net/rose.h>
static unsigned int rose_neigh_no = 1;
-static struct rose_node *rose_node_list = NULL;
-static struct rose_neigh *rose_neigh_list = NULL;
-static struct rose_route *rose_route_list = NULL;
+static struct rose_node *rose_node_list;
+static struct rose_neigh *rose_neigh_list;
+static struct rose_route *rose_route_list;
-struct rose_neigh *rose_loopback_neigh = NULL;
+struct rose_neigh *rose_loopback_neigh;
static void rose_remove_neigh(struct rose_neigh *);
return len;
}
-#ifdef MODULE
-
/*
* Release all memory associated with ROSE routing structures.
*/
-void rose_rt_free(void)
+void __exit rose_rt_free(void)
{
struct rose_neigh *s, *rose_neigh = rose_neigh_list;
struct rose_node *t, *rose_node = rose_node_list;
rose_remove_route(u);
}
}
-
-#endif
-
-#endif
* ROSE 003 Jonathan(G4KLX) Added use count to neighbours.
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
sk->dead = 1;
}
-
-#endif
* Implemented idle timer.
*/
-#include <linux/config.h>
-#if defined(CONFIG_ROSE) || defined(CONFIG_ROSE_MODULE)
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
sk->dead = 1;
}
-
-#endif
##
# takes a function prototype and spits out all the details
-# stored in the global arrays/hsahes.
+# stored in the global arrays/hashes.
sub dump_function {
my $prototype = shift @_;
- $prototype =~ s/^static+ //;
- $prototype =~ s/^extern+ //;
- $prototype =~ s/^inline+ //;
- $prototype =~ s/^__inline__+ //;
- $prototype =~ s/^#define+ //; #ak added
+ $prototype =~ s/^static +//;
+ $prototype =~ s/^extern +//;
+ $prototype =~ s/^inline +//;
+ $prototype =~ s/^__inline__ +//;
+ $prototype =~ s/^#define +//; #ak added
+
+ # Yes, this truly is vile. We are looking for:
+ # 1. Return type (may be nothing if we're looking at a macro)
+ # 2. Function name
+ # 3. Function parameters.
+ #
+ # All the while we have to watch out for function pointer parameters
+ # (which IIRC is what the two sections are for), C types (these
+ # regexps don't even start to express all the possibilities), and
+ # so on.
+ #
+ # If you mess with these regexps, it's a good idea to check that
+ # the following functions' documentation still comes out right:
+ # - parport_register_device (function pointer parameters)
+ # - atomic_set (macro)
+ # - pci_match_device (long return type)
if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
$prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
$prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
$prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
$prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
$prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
$prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
- $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) {
+ $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) {
$return_type = $1;
$function_name = $2;
$args = $3;
$param="...";
$parameters{"..."} = "variable arguments";
}
- if ($type eq "")
+ elsif ($type eq "" && $param eq "")
{
$type="";
$param="void";
$parameters{void} = "no arguments";
}
- if ($parameters{$param} eq "") {
+ if ($type ne "" && $parameters{$param} eq "") {
$parameters{$param} = "-- undescribed --";
print STDERR "Warning($file:$lineno): Function parameter '$param' not described in '$function_name'\n";
}