Commit bb9c5bf1 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.10

parent c3aa3674
......@@ -172,13 +172,20 @@ S: East Malvern, Victoria, 3145
S: Australia
N: Alan Cox
E: A.Cox@swansea.ac.uk
E: iiitac@pyr.swan.ac.uk
E: iialan@iifeak.swan.ac.uk
E: alan@cymru.net (use for commercial traffic)
E: gw4pts@gw4pts.ampr.org
E: GW4PTS@GB7SWN (packet radio)
D: NET2Debugged author
S: c/o I^2IT Limited
S: The Innovation Centre
S: University Of Wales
S: Swansea, SA2 8PP
S: Wales, UK
D: NET2Debugged/NET3 author
D: Network layer debugging
D: AX.25 & IPX alpha releases
D: Initial AX.25 & IPX releases
D: Original Linux netatalk patches.
D: Current 3c501 hacker. >>More 3c501 info/tricks wanted<<.
N: Laurence Culhane
E: loz@holmes.demon.co.uk
......
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 9
SUBLEVEL = 10
ARCH = i386
......@@ -283,3 +283,5 @@ else
dummy:
endif
include Rules.make
......@@ -6,7 +6,7 @@
# Common rules
#
.c.s:
$(CC) $(CFLAGS) -S $<
$(CC) $(CFLAGS) -S $< -o $@
#
# A rule to do nothing
......
OUTPUT_FORMAT("ecoff-littlealpha")
ENTRY(__start)
SECTIONS
{
.text 0x20000000: {
_ftext = . ;
__istart = . ;
eprol = .;
*(.text)
__fstart = . ;
_etext = .;
}
.rdata : {
*(.rdata)
}
.pdata : {
_fpdata = .;
*(.pdata)
}
.data : {
_fdata = .;
*(.data)
CONSTRUCTORS
}
.xdata : {
*(.xdata)
}
_gp = ALIGN (16) + 0x8000;
.lit8 : {
*(.lit8)
}
.lita : {
*(.lita)
}
.sdata : {
*(.sdata)
}
_EDATA = .;
_FBSS = .;
.sbss : {
*(.sbss)
*(.scommon)
}
.bss : {
*(.bss)
*(COMMON)
}
_end = .;
}
......@@ -17,7 +17,7 @@
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
OBJS = entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
lca.o bios32.o
lca.o bios32.o ptrace.o
all: kernel.o head.o
......
......@@ -105,6 +105,9 @@
.text
.set noat
#ifdef __linux__
.set singlegp
#endif
.align 3
.globl entInt
......@@ -191,9 +194,11 @@ kernel_fork:
stq $16,24($30)
stq $17,32($30)
stq $18,40($30)
bis $31,2,$0 /* Register v0: syscall nr for fork() */
SAVE_ALL
lda $27,sys_fork
jsr $26,($27),sys_fork
stq $0,0($30)
br ret_from_sys_call
.end kernel_fork
......@@ -240,7 +245,7 @@ do_switch_stack:
stt $f28,288($30)
stt $f29,296($30)
stt $f30,304($30)
ret $31,($0),1
ret $31,($1),1
.end do_switch_stack
.align 3
......@@ -286,7 +291,7 @@ undo_switch_stack:
ldt $f29,296($30)
ldt $f30,304($30)
lda $30,SWITCH_STACK_SIZE($30)
ret $31,($0),1
ret $31,($1),1
.end undo_switch_stack
.align 3
......@@ -363,14 +368,11 @@ entUna:
.globl sys_fork
.ent sys_fork
sys_fork:
br $0,do_switch_stack
br $1,do_switch_stack
bis $30,$30,$16
lda $27,alpha_fork
jsr $26,($27),alpha_fork
br $0,undo_switch_stack
ldq $0,0($30)
bis $31,2,$19 /* Make sure that the stored user register v0 has */
stq $19,0($30) /* the syscall # for fork */
br $1,undo_switch_stack
ret $31,($26),1
.end sys_fork
......@@ -378,9 +380,9 @@ sys_fork:
.globl alpha_switch_to
.ent alpha_switch_to
alpha_switch_to:
br $0,do_switch_stack
br $1,do_switch_stack
call_pal PAL_swpctx
br $0,undo_switch_stack
br $1,undo_switch_stack
ret $31,($26),1
.end alpha_switch_to
......@@ -450,7 +452,7 @@ restore_all:
.align 3
signal_return:
bis $30,$30,$17
br $0,do_switch_stack
br $1,do_switch_stack
bis $30,$30,$18
lda $27,do_signal
jsr $26,($27),do_signal
......@@ -480,7 +482,7 @@ sys_sigreturn:
bis $30,$30,$18
lda $27,do_sigreturn
jsr $26,($27),do_sigreturn
br $0,undo_switch_stack
br $1,undo_switch_stack
br $31,ret_from_sys_call
.end sys_sigreturn
......@@ -488,7 +490,7 @@ sys_sigreturn:
.ent sys_sigsuspend
sys_sigsuspend:
bis $30,$30,$17
br $0,do_switch_stack
br $1,do_switch_stack
bis $30,$30,$18
lda $27,do_sigsuspend
jsr $26,($27),do_sigsuspend
......@@ -504,7 +506,7 @@ sys_call_table:
.quad sys_unlink, do_entSys, sys_chdir, sys_fchdir, sys_mknod
.quad sys_chmod, sys_chown, sys_brk, do_entSys, sys_lseek
.quad sys_getxpid, osf_mount, osf_umount, sys_setuid, sys_getxuid
.quad do_entSys, do_entSys, do_entSys, do_entSys, do_entSys
.quad do_entSys, sys_ptrace, do_entSys, do_entSys, do_entSys
.quad do_entSys, do_entSys, do_entSys, sys_access, do_entSys
.quad do_entSys, sys_sync, sys_kill, do_entSys, sys_setpgid
.quad do_entSys, sys_dup, sys_pipe, do_entSys, do_entSys
......
......@@ -123,7 +123,6 @@ void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childregs->r0 = 0;
childregs->r19 = 0;
childregs->r20 = 1; /* OSF/1 has some strange fork() semantics.. */
regs->r0 = p->pid;
regs->r20 = 0;
stack = ((struct switch_stack *) regs) - 1;
childstack = ((struct switch_stack *) childregs) - 1;
......
......@@ -16,6 +16,25 @@
#include <asm/pgtable.h>
#include <asm/system.h>
#undef DEBUG
#ifdef DEBUG
enum {
DBG_MEM = (1<<0),
DBG_BPT = (1<<1)
};
int debug_mask = DBG_BPT;
# define DBG(fac,args) {if ((fac) & debug_mask) printk args;}
#else
# define DBG(fac,args)
#endif
#define BREAKINST 0x00000080 /* call_pal bpt */
/* This was determined via brute force. */
#define MAGICNUM 496
......@@ -24,18 +43,6 @@
* in exit.c or in signal.c.
*/
/* determines which flags the user has access to. */
/* 1 = access 0 = no access */
#define FLAG_MASK 0x00044dd5
/* set's the trap flag. */
#define TRAP_FLAG 0x100
/*
* this is the number to subtract from the top of the stack. To find
* the local frame.
*/
/* A mapping between register number and its offset on the kernel stack.
* You also need to add MAGICNUM to get past the kernel stack frame
* to the actual saved user info.
......@@ -43,6 +50,12 @@
* 320 is the size of the switch_stack area.
*/
enum {
REG_R0 = 0,
REG_F0 = 32,
REG_PC = 64
};
static int map_reg_to_offset[] = {
320+0,320+8,320+16,320+24,320+32,320+40,320+48,320+56,320+64, /* 0-8 */
0,8,16,24,32,40,48, /* 9-15 */
......@@ -58,19 +71,14 @@ static int map_reg_to_offset[] = {
320+168
};
static int offset_of_register(int reg_num) {
if(reg_num<0 || reg_num>64) {
static int offset_of_register(int reg_num)
{
if (reg_num < 0 || reg_num > 64) {
return -1;
}
return map_reg_to_offset[reg_num];
}
static void unset_singlestep(struct task_struct *child) {
}
static void set_singlestep(struct task_struct *child) {
}
/* change a pid into a task struct. */
static inline struct task_struct * get_task(int pid)
{
......@@ -130,9 +138,7 @@ static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
pte_t * pgtable;
unsigned long page;
#ifdef DEBUG
printk("Getting long at 0x%lx\n",addr);
#endif
DBG(DBG_MEM, ("Getting long at 0x%lx\n", addr));
repeat:
pgdir = pgd_offset(vma->vm_task, addr);
if (pgd_none(*pgdir)) {
......@@ -254,9 +260,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
{
struct vm_area_struct * vma = find_extend_vma(tsk, addr);
#ifdef DEBUG
printk("in read_long\n");
#endif
DBG(DBG_MEM, ("in read_long\n"));
if (!vma) {
printk("Unable to find vma for addr 0x%lx\n",addr);
return -EIO;
......@@ -306,9 +310,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
} else {
long l =get_long(vma, addr);
#ifdef DEBUG
printk("value is 0x%lx\n",l);
#endif
DBG(DBG_MEM, ("value is 0x%lx\n",l));
*result = l;
}
return 0;
......@@ -391,33 +393,160 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
return 0;
}
/* Uh, this does ugly stuff. It stores the specified value in the a3
/*
* Read a 32bit int from address space TSK.
*/
static int read_int(struct task_struct * tsk, unsigned long addr, unsigned int *data)
{
unsigned long l, align;
int res;
align = addr & 0x7;
addr &= ~0x7;
res = read_long(tsk, addr, &l);
if (res < 0)
return res;
if (align == 0) {
*data = l;
} else {
*data = l >> 32;
}
return 0;
}
/*
* Write a 32bit word to address space TSK.
*
* For simplicity, do a read-modify-write of the 64bit word that
* contains the 32bit word that we are about to write.
*/
static int write_int(struct task_struct * tsk, unsigned long addr, unsigned int data)
{
unsigned long l, align;
int res;
align = addr & 0x7;
addr &= ~0x7;
res = read_long(tsk, addr, &l);
if (res < 0)
return res;
if (align == 0) {
l = (l & 0xffffffff00000000UL) | ((unsigned long) data << 0);
} else {
l = (l & 0x00000000ffffffffUL) | ((unsigned long) data << 32);
}
return write_long(tsk, addr, l);
}
/*
* Uh, this does ugly stuff. It stores the specified value in the a3
* register. entry.S will swap a3 and the returned value from
* sys_ptrace() before returning to the user.
*/
static inline void set_success(struct pt_regs *regs,long resval) {
regs->r19=resval;
static inline void set_success(struct pt_regs *regs,long resval)
{
regs->r19 = resval;
}
/* This doesn't do diddly, actually--if the value returned from
/*
* This doesn't do diddly, actually--if the value returned from
* sys_ptrace() is != 0, it sets things up properly.
*/
static inline void set_failure(struct pt_regs *regs,long errcode) {
regs->r19=0;
static inline void set_failure(struct pt_regs *regs, long errcode)
{
regs->r19 = 0;
}
asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5, struct pt_regs regs)
/*
* Set breakpoint.
*/
static int set_bpt(struct task_struct *child)
{
int displ, i, res, reg_b, off, nsaved = 0;
u32 insn, op_code;
unsigned long pc;
pc = get_stack_long(child, map_reg_to_offset[REG_PC]);
res = read_int(child, pc, &insn);
if (res < 0)
return res;
op_code = insn >> 26;
if (op_code >= 0x30) {
/*
* It's a branch: instead of trying to figure out
* whether the branch will be taken or not, we'll put
* a breakpoint at either location. This is simpler,
* more reliable, and probably not a whole lot slower
* than the alternative approach of emulating the
* branch (emulation can be tricky for fp branches).
*/
displ = ((s32)(insn << 11)) >> 9;
child->debugreg[nsaved++] = pc + 4;
if (displ) /* guard against unoptimized code */
child->debugreg[nsaved++] = pc + 4 + displ;
DBG(DBG_BPT, ("execing branch\n"));
} else if (op_code == 0x1a) {
reg_b = (insn >> 16) & 0x1f;
off = offset_of_register(reg_b);
if (off >= 0) {
child->debugreg[nsaved++] = get_stack_long(child, off);
} else {
/* $31 (aka zero) doesn't have a stack-slot */
if (reg_b == 31) {
child->debugreg[nsaved++] = 0;
} else {
return -EIO;
}
}
DBG(DBG_BPT, ("execing jump\n"));
} else {
child->debugreg[nsaved++] = pc + 4;
DBG(DBG_BPT, ("execing normal insn\n"));
}
/* install breakpoints: */
for (i = 0; i < nsaved; ++i) {
res = read_int(child, child->debugreg[i], &insn);
if (res < 0)
return res;
child->debugreg[i + 2] = insn;
DBG(DBG_BPT, (" -> next_pc=%lx\n", child->debugreg[i]));
res = write_int(child, child->debugreg[i], BREAKINST);
if (res < 0)
return res;
}
child->debugreg[4] = nsaved;
return 0;
}
int ptrace_cancel_bpt(struct task_struct *child)
{
int i, nsaved = child->debugreg[4];
child->debugreg[4] = 0;
for (i = 0; i < nsaved; ++i) {
write_int(child, child->debugreg[i], child->debugreg[i + 2]);
}
return nsaved;
}
asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4, int a5,
struct pt_regs regs)
{
struct task_struct *child;
struct user * dummy;
int res;
dummy = NULL;
#ifdef DEBUG
printk("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data);
#endif
DBG(DBG_MEM, ("request=%ld pid=%ld addr=0x%lx data=0x%lx\n",request,pid,addr,data));
set_success(&regs,0);
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
......@@ -465,25 +594,19 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
return 0;
}
if (!(child->flags & PF_PTRACED)) {
#ifdef DEBUG
printk("child not traced\n");
#endif
DBG(DBG_MEM, ("child not traced\n"));
set_failure(&regs,-ESRCH);
return -ESRCH;
}
if (child->state != TASK_STOPPED) {
#ifdef DEBUG
printk("child process not stopped\n");
#endif
DBG(DBG_MEM, ("child process not stopped\n"));
if (request != PTRACE_KILL) {
set_failure(&regs,-ESRCH);
return -ESRCH;
}
}
if (child->p_pptr != current) {
#ifdef DEBUG
printk("child not parent of this process\n");
#endif
DBG(DBG_MEM, ("child not parent of this process\n"));
set_failure(&regs,-ESRCH);
return -ESRCH;
}
......@@ -495,9 +618,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
unsigned long tmp;
int res;
#ifdef DEBUG
printk("doing request at addr 0x%lx\n",addr);
#endif
DBG(DBG_MEM, ("doing request at addr 0x%lx\n",addr));
res = read_long(child, addr, &tmp);
if (res < 0) {
set_failure(&regs,res);
......@@ -520,16 +641,16 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
tmp=child->tss.usp;
}
else {
#ifdef DEBUG
int reg=addr;
#endif
addr = offset_of_register(addr);
if(addr < 0) {
set_failure(&regs,-EIO);
if (addr < 0) {
set_failure(&regs, -EIO);
return -EIO;
}
tmp = get_stack_long(child, addr);
#ifdef DEBUG
printk("%d = reg 0x%lx=tmp\n",reg,tmp);
#endif
DBG(DBG_MEM, ("%d = reg 0x%lx=tmp\n",reg,tmp));
}
set_success(&regs,tmp);
return 0;
......@@ -573,12 +694,12 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
child->flags &= ~PF_TRACESYS;
child->exit_code = data;
child->state = TASK_RUNNING;
unset_singlestep(child);
ptrace_cancel_bpt(child);
set_success(&regs,data);
return 0;
}
/*
/*
* make the child exit. Best I can do is send it a sigkill.
* perhaps it should be put in the status that it wants to
* exit.
......@@ -586,7 +707,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
case PTRACE_KILL: {
child->state = TASK_RUNNING;
child->exit_code = SIGKILL;
unset_singlestep(child);
ptrace_cancel_bpt(child);
return 0;
}
......@@ -595,8 +716,11 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
set_failure(&regs,-EIO);
return -EIO;
}
res = set_bpt(child);
if (res < 0) {
return res;
}
child->flags &= ~PF_TRACESYS;
set_singlestep(child);
child->state = TASK_RUNNING;
child->exit_code = data;
/* give it a chance to run. */
......@@ -615,7 +739,7 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data, int a4,
child->p_pptr = child->p_opptr;
SET_LINKS(child);
/* make sure the single step bit is not set. */
unset_singlestep(child);
ptrace_cancel_bpt(child);
return 0;
}
......
......@@ -19,10 +19,10 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err)
unsigned long sp;
unsigned int * pc;
if (regs->ps & 8)
return;
printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
sp = (unsigned long) (regs+1);
if (regs->ps & 8)
sp = rdusp();
printk("pc = %lx ps = %04lx\n", regs->pc, regs->ps);
printk("rp = %lx sp = %lx\n", regs->r26, sp);
printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
......@@ -36,8 +36,6 @@ void die_if_kernel(char * str, struct pt_regs * regs, long err)
regs->r24, regs->r25, regs->r26, regs->r27);
printk("r28=%lx r29=%lx r30=%lx\n",
regs->r28, regs->gp, sp);
if (regs->ps & 8)
return;
printk("Code:");
pc = (unsigned int *) regs->pc;
for (i = -3; i < 6; i++)
......@@ -61,8 +59,29 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
extern int ptrace_cancel_bpt (struct task_struct *who);
die_if_kernel("Instruction fault", &regs, type);
switch (type) {
case 0: /* breakpoint */
if (ptrace_cancel_bpt(current)) {
regs.pc -= 4; /* make pc point to former bpt */
}
if (current->flags & PF_PTRACED)
current->blocked &= ~(1 << (SIGTRAP - 1));
send_sig(SIGTRAP, current, 1);
break;
case 1: /* bugcheck */
case 2: /* gentrap */
case 3: /* FEN fault */
case 4: /* opDEC */
send_sig(SIGILL, current, 1);
break;
default:
panic("do_entIF: unexpected instruction-fault type");
}
}
/*
......@@ -131,6 +150,7 @@ asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
{
if (regs.r0 != 112)
printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
return -1;
}
......
OUTPUT_FORMAT("ecoff-littlealpha")
ENTRY(__start)
SECTIONS
{
.text 0xfffffc0000310000: {
_ftext = . ;
__istart = . ;
eprol = .;
*(.text)
__fstart = . ;
_etext = .;
}
.rdata : {
*(.rdata)
}
.pdata : {
_fpdata = .;
*(.pdata)
}
.data : {
_fdata = .;
*(.data)
CONSTRUCTORS
}
.xdata : {
*(.xdata)
}
_gp = ALIGN (16) + 0x8000;
.lit8 : {
*(.lit8)
}
.lita : {
*(.lita)
}
.sdata : {
*(.sdata)
}
_EDATA = .;
_FBSS = .;
.sbss : {
*(.sbss)
*(.scommon)
}
.bss : {
*(.bss)
*(COMMON)
}
_end = .;
}
......@@ -60,6 +60,7 @@ bool 'IP: Reverse ARP' CONFIG_INET_RARP n
bool 'IP: Assume subnets are local' CONFIG_INET_SNARL y
bool 'IP: Disable NAGLE algorithm (normally enabled)' CONFIG_TCP_NAGLE_OFF n
bool 'IP: Drop source routed frames' CONFIG_IP_NOSR y
bool 'IP: Allow large windows (not recommend if <16Mb of memory)' CONFIG_SKB_LARGE y
fi
bool 'The IPX protocol' CONFIG_IPX n
bool 'Appletalk DDP' CONFIG_ATALK n
......
......@@ -185,7 +185,7 @@
#define DEBUG 0
#define CDU31A_READAHEAD 64 /* 64 sector, 32kB, 16 reads read-ahead */
#define CDU31A_READAHEAD 128 /* 128 sector, 64kB, 32 reads read-ahead */
#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10
/* Define the following if you have data corruption problems. */
......@@ -380,6 +380,8 @@ cdu31a_interrupt(int irq, struct pt_regs *regs)
static inline void
sony_sleep(void)
{
unsigned long flags;
if (irq_used <= 0)
{
current->state = TASK_INTERRUPTIBLE;
......@@ -388,10 +390,11 @@ sony_sleep(void)
}
else /* Interrupt driven */
{
save_flags(flags);
cli();
enable_interrupts();
interruptible_sleep_on(&cdu31a_irq_wait);
sti();
restore_flags(flags);
}
}
......@@ -516,6 +519,18 @@ set_drive_params(void)
unsigned char params[3];
params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME;
params[1] = 0x00; /* Never spin down the drive. */
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD,
params,
2,
res_reg,
&res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk(" Unable to set spin-down time: 0x%2.2x\n", res_reg[1]);
}
params[0] = SONY_SD_MECH_CONTROL;
params[1] = 0x03; /* Set auto spin up and auto eject */
if (is_double_speed)
......@@ -753,8 +768,10 @@ do_sony_cd_cmd(unsigned char cmd,
unsigned int retry_count;
int num_retries;
int recursive_call;
unsigned long flags;
save_flags(flags);
cli();
if (current != has_cd_task) /* Allow recursive calls to this routine */
{
......@@ -777,7 +794,7 @@ do_sony_cd_cmd(unsigned char cmd,
{
recursive_call = 1;
}
sti();
restore_flags(flags);
num_retries = 0;
retry_cd_operation:
......@@ -1356,24 +1373,31 @@ do_cdu31a_request(void)
unsigned char res_reg[12];
unsigned int res_size;
int num_retries;
unsigned long flags;
/*
* Make sure no one else is using the driver; wait for them
* to finish if it is so.
*/
save_flags(flags);
cli();
while (sony_inuse)
{
interruptible_sleep_on(&sony_wait);
if (current->signal & ~current->blocked)
{
restore_flags(flags);
if (CURRENT && (CURRENT->dev > 0))
{
end_request(0);
}
return;
}
}
sony_inuse = 1;
has_cd_task = current;
sti();
restore_flags(flags);
/* Get drive status before doing anything. */
while (handle_sony_cd_attention())
......@@ -1507,6 +1531,7 @@ do_cdu31a_request(void)
}
if (start_request(block / 4, CDU31A_READAHEAD / 4, 0))
{
printk("CDU31a: start request failed\n");
end_request(0);
goto cdu31a_request_startover;
}
......@@ -1991,11 +2016,13 @@ read_audio(struct cdrom_read_audio *ra,
unsigned char res_reg[12];
unsigned int res_size;
unsigned int cframe;
unsigned long flags;
/*
* Make sure no one else is using the driver; wait for them
* to finish if it is so.
*/
save_flags(flags);
cli();
while (sony_inuse)
{
......@@ -2007,7 +2034,7 @@ read_audio(struct cdrom_read_audio *ra,
}
sony_inuse = 1;
has_cd_task = current;
sti();
restore_flags(flags);
if (!sony_spun_up)
{
......@@ -2167,8 +2194,20 @@ read_audio(struct cdrom_read_audio *ra,
/*
* The big ugly ioctl handler.
*/
static int
scd_ioctl(struct inode *inode,
static int do_sony_cd_cmd_chk(char *name, unsigned char cmd, unsigned char *params, unsigned int num_params,
unsigned char *result_buffer, unsigned int *result_size)
{
do_sony_cd_cmd(cmd, params, num_params, result_buffer, result_size);
if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROM%s)\n", result_buffer[1], name);
return -EIO;
}
return 0;
}
static int scd_ioctl(struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
......@@ -2187,12 +2226,7 @@ scd_ioctl(struct inode *inode,
switch (cmd)
{
case CDROMSTART: /* Spin up the drive */
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROMSTART)\n", res_reg[1]);
return -EIO;
}
return do_sony_cd_cmd_chk("START",SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
return 0;
break;
......@@ -2204,25 +2238,11 @@ scd_ioctl(struct inode *inode,
* already not spinning.
*/
sony_audio_status = CDROM_AUDIO_NO_STATUS;
do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
if ( ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
&& (res_reg[1] != SONY_NOT_SPIN_ERR))
{
printk("Sony CDROM error 0x%2.2x (CDROMSTOP)\n", res_reg[1]);
return -EIO;
}
return 0;
break;
return do_sony_cd_cmd_chk("STOP",SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
case CDROMPAUSE: /* Pause the drive */
do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROMPAUSE)\n", res_reg[1]);
if(do_sony_cd_cmd_chk("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size))
return -EIO;
}
/* Get the current position and save it for resuming */
if (read_subcode() < 0)
{
......@@ -2251,18 +2271,15 @@ scd_ioctl(struct inode *inode,
params[5] = final_pos_msf[1];
params[6] = final_pos_msf[2];
params[0] = 0x03;
do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROMRESUME)\n", res_reg[1]);
if(do_sony_cd_cmd_chk("RESUME",SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size)<0)
return -EIO;
}
sony_audio_status = CDROM_AUDIO_PLAY;
return 0;
break;
case CDROMPLAYMSF: /* Play starting at the given MSF address. */
verify_area(VERIFY_READ, (char *) arg, 6);
i=verify_area(VERIFY_READ, (char *) arg, 6);
if(i)
return i;
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
memcpy_fromfs(&(params[1]), (void *) arg, 6);
......@@ -2272,12 +2289,8 @@ scd_ioctl(struct inode *inode,
params[i] = int_to_bcd(params[i]);
}
params[0] = 0x03;
do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROMPLAYMSF)\n", res_reg[1]);
if(do_sony_cd_cmd_chk("PLAYMSF",SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size)<0)
return -EIO;
}
/* Save the final position for pauses and resumes */
final_pos_msf[0] = params[4];
......@@ -2285,7 +2298,6 @@ scd_ioctl(struct inode *inode,
final_pos_msf[2] = params[6];
sony_audio_status = CDROM_AUDIO_PLAY;
return 0;
break;
case CDROMREADTOCHDR: /* Read the table of contents header */
{
......@@ -2299,13 +2311,14 @@ scd_ioctl(struct inode *inode,
}
hdr = (struct cdrom_tochdr *) arg;
verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
i=verify_area(VERIFY_WRITE, hdr, sizeof(*hdr));
if(i<0)
return i;
loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr));
}
return 0;
break;
case CDROMREADTOCENTRY: /* Read a given table of contents entry */
{
......@@ -2321,8 +2334,12 @@ scd_ioctl(struct inode *inode,
}
entry = (struct cdrom_tocentry *) arg;
verify_area(VERIFY_READ, entry, sizeof(*entry));
verify_area(VERIFY_WRITE, entry, sizeof(*entry));
i=verify_area(VERIFY_READ, entry, sizeof(*entry));
if(i<0)
return i;
i=verify_area(VERIFY_WRITE, entry, sizeof(*entry));
if(i<0)
return i;
memcpy_fromfs(&loc_entry, entry, sizeof(loc_entry));
......@@ -2373,7 +2390,9 @@ scd_ioctl(struct inode *inode,
return -EIO;
}
verify_area(VERIFY_READ, (char *) arg, sizeof(ti));
i=verify_area(VERIFY_READ, (char *) arg, sizeof(ti));
if(i<0)
return i;
memcpy_fromfs(&ti, (char *) arg, sizeof(ti));
if ( (ti.cdti_trk0 < sony_toc->first_track_num)
......@@ -2416,6 +2435,7 @@ scd_ioctl(struct inode *inode,
do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size);
do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Params: %x %x %x %x %x %x %x\n", params[0], params[1],
......@@ -2439,34 +2459,22 @@ scd_ioctl(struct inode *inode,
{
struct cdrom_volctrl volctrl;
verify_area(VERIFY_READ, (char *) arg, sizeof(volctrl));
i=verify_area(VERIFY_READ, (char *) arg, sizeof(volctrl));
if(i<0)
return i;
memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
params[0] = SONY_SD_AUDIO_VOLUME;
params[1] = volctrl.channel0;
params[2] = volctrl.channel1;
do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, params, 3, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROMVOLCTRL)\n", res_reg[1]);
return -EIO;
}
return do_sony_cd_cmd_chk("VOLCTRL",SONY_SET_DRIVE_PARAM_CMD, params, 3, res_reg, &res_size);
}
return 0;
case CDROMEJECT: /* Eject the drive */
do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size);
do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size);
sony_audio_status = CDROM_AUDIO_INVALID;
do_sony_cd_cmd(SONY_EJECT_CMD, NULL, 0, res_reg, &res_size);
if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20))
{
printk("Sony CDROM error 0x%2.2x (CDROMEJECT)\n", res_reg[1]);
return -EIO;
}
return 0;
break;
return do_sony_cd_cmd_chk("EJECT",SONY_EJECT_CMD, NULL, 0, res_reg, &res_size);
case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte
raw data tracks. */
......@@ -2480,10 +2488,14 @@ scd_ioctl(struct inode *inode,
return -EIO;
}
verify_area(VERIFY_READ, (char *) arg, sizeof(ra));
i=verify_area(VERIFY_READ, (char *) arg, sizeof(ra));
if(i<0)
return i;
memcpy_fromfs(&ra, (char *) arg, sizeof(ra));
verify_area(VERIFY_WRITE, ra.buf, CD_FRAMESIZE_RAW * ra.nframes);
i=verify_area(VERIFY_WRITE, ra.buf, CD_FRAMESIZE_RAW * ra.nframes);
if(i<0)
return i;
if (ra.addr_format == CDROM_LBA)
{
......
......@@ -114,7 +114,9 @@ static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long f
struct buffer_head *bh;
struct partition *p;
int mask = (1 << hd->minor_shift) - 1;
#ifdef CONFIG_BLK_DEV_IDE
extern void ide_xlate_1024(dev_t);
#endif
read_mbr:
if (!(bh = bread(dev,0,1024))) {
......@@ -149,7 +151,9 @@ static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long f
first_sector += p->end_sector;
hd->part[MINOR(dev)].start_sect += p->end_sector;
hd->part[MINOR(dev)].nr_sects -= p->end_sector;
#ifdef CONFIG_BLK_DEV_IDE
ide_xlate_1024(dev); /* harmless if not an IDE drive */
#endif
bh->b_dirt = 0; /* prevent re-use of this block */
bh->b_uptodate = 0;
bh->b_req = 0;
......@@ -162,7 +166,9 @@ static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long f
*/
if (p->sys_ind == DM6_AUXPARTITION) {
printk(" [DM6]");
#ifdef CONFIG_BLK_DEV_IDE
ide_xlate_1024(dev); /* harmless if not an IDE drive */
#endif
}
current_minor += 4; /* first "extra" minor (for extended partitions) */
......
......@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/types.h>
#include <asm/segment.h>
......@@ -69,7 +70,7 @@ clear_selection(void) {
* User settable table: what characters are to be considered alphabetic?
* 256 bits
*/
static unsigned long inwordLut[8]={
static u32 inwordLut[8]={
0x00000000, /* control chars */
0x03FF0000, /* digits */
0x87FFFFFE, /* uppercase and '_' */
......@@ -90,7 +91,7 @@ int sel_loadlut(const unsigned long arg)
int i = verify_area(VERIFY_READ, (char *) arg, 36);
if (i)
return i;
memcpy_fromfs(inwordLut, (unsigned long *)(arg+4), 32);
memcpy_fromfs(inwordLut, (u32 *)(arg+4), 32);
return 0;
}
......
......@@ -94,48 +94,13 @@ static void unset_locked_termios(struct termios *termios,
old->c_cc[i] : termios->c_cc[i];
}
static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
static void change_termios(struct tty_struct * tty, struct termios * new_termios)
{
struct termio tmp_termio;
struct termios tmp_termios;
int canon_change;
struct termios old_termios = *tty->termios;
int retval, canon_change;
retval = tty_check_change(tty);
if (retval)
return retval;
if (opt & TERMIOS_TERMIO) {
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
if (retval)
return retval;
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, (struct termio *) arg,
sizeof (struct termio));
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
#undef SET_LOW_BITS
} else {
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
if (retval)
return retval;
memcpy_fromfs(&tmp_termios, (struct termios *) arg,
sizeof (struct termios));
}
if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
if (opt & TERMIOS_WAIT)
tty_wait_until_sent(tty, 0);
cli();
*tty->termios = tmp_termios;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
if (canon_change) {
......@@ -173,7 +138,41 @@ static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
if (tty->ldisc.set_termios)
(*tty->ldisc.set_termios)(tty, &old_termios);
}
static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
{
struct termios tmp_termios;
int retval;
retval = tty_check_change(tty);
if (retval)
return retval;
if (opt & TERMIOS_TERMIO) {
struct termio tmp_termio;
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
if (retval)
return retval;
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, (struct termio *) arg,
sizeof (struct termio));
trans_from_termio(&tmp_termio, &tmp_termios);
} else {
retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
if (retval)
return retval;
memcpy_fromfs(&tmp_termios, (struct termios *) arg,
sizeof (struct termios));
}
if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
if (opt & TERMIOS_WAIT)
tty_wait_until_sent(tty, 0);
change_termios(tty, &tmp_termios);
return 0;
}
......@@ -185,13 +184,7 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
if (i)
return i;
tmp_termio.c_iflag = tty->termios->c_iflag;
tmp_termio.c_oflag = tty->termios->c_oflag;
tmp_termio.c_cflag = tty->termios->c_cflag;
tmp_termio.c_lflag = tty->termios->c_lflag;
tmp_termio.c_line = tty->termios->c_line;
for(i=0 ; i < NCC ; i++)
tmp_termio.c_cc[i] = tty->termios->c_cc[i];
trans_to_termio(tty->termios, &tmp_termio);
memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
return 0;
}
......@@ -215,6 +208,169 @@ static unsigned long inq_canon(struct tty_struct * tty)
return nr;
}
#ifdef TIOCGETP
/*
* These are depracated, but there is limited support..
*
* The "sg_flags" translation is a joke..
*/
static int get_sgflags(struct tty_struct * tty)
{
int flags = 0;
if (!(tty->termios->c_lflag & ICANON))
if (tty->termios->c_lflag & ISIG)
flags |= 0x02; /* cbreak */
else
flags |= 0x20; /* raw */
if (tty->termios->c_lflag & ECHO)
flags |= 0x08; /* echo */
if (tty->termios->c_oflag & OPOST)
if (tty->termios->c_oflag & ONLCR)
flags |= 0x10; /* crmod */
return flags;
}
static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
{
int retval;
struct sgttyb tmp;
retval = verify_area(VERIFY_WRITE, sgttyb, sizeof(struct sgttyb));
if (retval)
return retval;
tmp.sg_ispeed = 0;
tmp.sg_ospeed = 0;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
memcpy_tofs(sgttyb, &tmp, sizeof(tmp));
return 0;
}
static void set_sgflags(struct termios * termios, int flags)
{
termios->c_iflag = ICRNL | IXON;
termios->c_oflag = 0;
termios->c_lflag = ISIG | ICANON;
if (flags & 0x02) { /* cbreak */
termios->c_iflag = 0;
termios->c_lflag &= ~ICANON;
}
if (flags & 0x08) { /* echo */
termios->c_lflag |= ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
}
if (flags & 0x10) { /* crmod */
termios->c_oflag |= OPOST | ONLCR;
}
if (flags & 0x20) { /* raw */
termios->c_iflag = 0;
termios->c_lflag &= ~(ISIG | ICANON);
}
if (!(termios->c_lflag & ICANON)) {
termios->c_cc[VMIN] = 1;
termios->c_cc[VTIME] = 0;
}
}
static int set_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
{
int retval;
struct sgttyb tmp;
struct termios termios;
retval = verify_area(VERIFY_READ, sgttyb, sizeof(struct sgttyb));
if (retval)
return retval;
retval = tty_check_change(tty);
if (retval)
return retval;
termios = *tty->termios;
memcpy_fromfs(&tmp, sgttyb, sizeof(tmp));
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
change_termios(tty, &termios);
return 0;
}
#endif
#ifdef TIOCGETC
static int get_tchars(struct tty_struct * tty, struct tchars * tchars)
{
int retval;
struct tchars tmp;
retval = verify_area(VERIFY_WRITE, tchars, sizeof(struct tchars));
if (retval)
return retval;
tmp.t_intrc = tty->termios->c_cc[VINTR];
tmp.t_quitc = tty->termios->c_cc[VQUIT];
tmp.t_startc = tty->termios->c_cc[VSTART];
tmp.t_stopc = tty->termios->c_cc[VSTOP];
tmp.t_eofc = tty->termios->c_cc[VEOF];
tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
memcpy_tofs(tchars, &tmp, sizeof(tmp));
return 0;
}
static int set_tchars(struct tty_struct * tty, struct tchars * tchars)
{
int retval;
struct tchars tmp;
retval = verify_area(VERIFY_READ, tchars, sizeof(struct tchars));
if (retval)
return retval;
memcpy_fromfs(&tmp, tchars, sizeof(tmp));
tty->termios->c_cc[VINTR] = tmp.t_intrc;
tty->termios->c_cc[VQUIT] = tmp.t_quitc;
tty->termios->c_cc[VSTART] = tmp.t_startc;
tty->termios->c_cc[VSTOP] = tmp.t_stopc;
tty->termios->c_cc[VEOF] = tmp.t_eofc;
tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
return 0;
}
#endif
#ifdef TIOCGLTC
static int get_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
{
int retval;
struct ltchars tmp;
retval = verify_area(VERIFY_WRITE, ltchars, sizeof(struct ltchars));
if (retval)
return retval;
tmp.t_suspc = tty->termios->c_cc[VSUSP];
tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */
tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
tmp.t_flushc = tty->termios->c_cc[VEOL2]; /* what is flushc anyway? */
tmp.t_werasc = tty->termios->c_cc[VWERASE];
tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
memcpy_tofs(ltchars, &tmp, sizeof(tmp));
return 0;
}
static int set_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
{
int retval;
struct ltchars tmp;
retval = verify_area(VERIFY_READ, ltchars, sizeof(struct ltchars));
if (retval)
return retval;
memcpy_fromfs(&tmp, ltchars, sizeof(tmp));
tty->termios->c_cc[VSUSP] = tmp.t_suspc;
tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; /* what is dsuspc anyway? */
tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
tty->termios->c_cc[VEOL2] = tmp.t_flushc; /* what is flushc anyway? */
tty->termios->c_cc[VWERASE] = tmp.t_werasc;
tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
return 0;
}
#endif
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
......@@ -229,6 +385,25 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
real_tty = tty;
switch (cmd) {
#ifdef TIOCGETP
case TIOCGETP:
return get_sgttyb(real_tty, (struct sgttyb *) arg);
case TIOCSETP:
case TIOCSETN:
return set_sgttyb(real_tty, (struct sgttyb *) arg);
#endif
#ifdef TIOCGETC
case TIOCGETC:
return get_tchars(real_tty, (struct tchars *) arg);
case TIOCSETC:
return set_tchars(real_tty, (struct tchars *) arg);
#endif
#ifdef TIOCGLTC
case TIOCGLTC:
return get_ltchars(real_tty, (struct ltchars *) arg);
case TIOCSLTC:
return set_ltchars(real_tty, (struct ltchars *) arg);
#endif
case TCGETS:
retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof (struct termios));
......
---------------------------------------------------------------------------
----------------------------------------------------------------------------
NOTE: See also README.arcnet-jumpers in this directory for jumper-setting
information if you're like most of us and didn't happen to get a manual with
information if you're like many of us and didn't happen to get a manual with
your ARCnet card.
---------------------------------------------------------------------------
----------------------------------------------------------------------------
Since no one seems to listen to me otherwise, perhaps a poem will get your
attention:
This is scary software
This is alpha software
If it works I DO CARE.
Hmm, I think I'm allowed to call that a poem, even though it's only two
......@@ -30,63 +30,67 @@ Anyway, enough complaining. Let's get started:
These are the ARCnet drivers for Linux.
This is the first non-ALPHA release, so please be careful, and send all
possible success/failure reports to me. If I don't know when/if/how it
works, I won't be able to answer people's questions. Do we want that? Of
course not.
We're now back to more ALPHA releases after the 1.01 release which made it
into Linux 1.2.2, so please be careful, and send all possible
success/failure reports to me. If I don't know when/if/how it works, I
won't be able to answer people's questions. Do we want that? Of course
not.
Once again: DO send me success reports! I want to know if this is working!
(You know, it might be argued that I'm pushing this point a little too much.
If you think so, why not flame me in a quick little email? Please also
If you think so, why not flame me in a quick little e-mail? Please also
include the type of card(s) you're using, software, size of network, and
whether it's working or not.)
My e-mail address is:
apenwarr@tourism.807-city.on.ca
apenwarr@foxnet.net
Where do I discuss these drivers?
---------------------------------
As of the 0.22 release, we have a mailing list specifically for discussion
of the ARCnet drivers for Linux, and anything you might want to interface
them with (ie. DOS). I'll also post new versions of the Linux-ARCnet
distribution to the list in tar-gzip-uuencode format.
There is a mailing list specifically for discussion of the ARCnet drivers
for Linux, and anything you might want to interface them with (ie. DOS).
I'll also post new versions of the Linux-ARCnet distribution to the list in
tar-gzip-uuencode format.
To subscribe to the list, send a message to listserv@tourism.807-city.on.ca
To subscribe to the list, send a message to listserv@807-city.on.ca
with the following line in the BODY (not the SUBJECT) of your message:
subscribe linux-arcnet YOUR REAL NAME
Remember to remove your signature, or you'll get an error back.
Send all bug (or success) reports to me or to the list.
You're free to use the comp.os.linux.development newsgroup too, but I can't
guarantee I'll see it there. (Hopefully, if my news server stays sane, I
will.)
The people on linux-net@vger.rutgers.edu have also been known to be very
helpful! :)
Other Drivers and Info
----------------------
Also, SMC (one of the companies that makes ARCnet cards) has a WorldWideWeb
site you might be interested in, which includes several drivers for various
cards including ARCnet. Try:
http://www.smc.com/
Performance Technologies makes various network software that supports
ARCnet.
http://www.perftech.com/ or ftp to ftp.perftech.com.
Novell makes a networking stack for DOS which includes ARCnet drivers. Try
ftp'ing to ftp.novell.com.
You can get the Crynwr packet driver collection (including arcether.com, the
one you'll want for arcnet cards) from oak.oakland.edu:/pub/msdos/pktdrvr.
one you'll want for arcnet cards) from oak.oakland.edu:/simtel/msdos/pktdrvr.
It won't work perfectly on a 386+ without patches, though, and also doesn't
like several cards. Mail me if you want a fixed version.
Last warning: This driver may be extremely dangerous, crash your computer,
or kill your dog! (although I'm pretty sure that I've worked that one
out...)
like several cards. Mail me if you want a fixed version. (Ahem: I may or
may not have a 100% fixed version by the time I get your mail!)
Loadable Module Support
-----------------------
This is a new feature as of 0.42 ALPHA.
This is a available starting with 0.42 ALPHA.
Configure and rebuild Linux. When asked, say NO to "arcnet support" if you
want loadable module support.
......@@ -124,28 +128,47 @@ How do I get it to work with...?
--------------------------------
NFS: Should be fine linux->linux, just pretend you're using ethernet cards.
oak.oakland.edu:/pub/msdos/nfs has some nice DOS clients. I can't
get SOSS (dos-based server) to work, although someone has and can't
figure out why it won't work for me.
oak.oakland.edu:/simtel/msdos/nfs has some nice DOS clients. There
is also a DOS-based NFS server called SOSS. It doesn't multitask
quite the way Linux does (actually, it doesn't multitask AT ALL) but
you never know what you might need.
DOS: If you're using the freeware arcether.com, you might want to install
the source code patch. It helps with PC/TCP, and also can get
arcether to load if it timed out too quickly. Mail me if you need a
precompiled version of arcether.com. (ie. you if don't have a DOS
assembler)
Windows: See DOS :)
arcether to load if it timed out too quickly during initialization.
Mail me if you need a precompiled version of arcether.com. (ie. you
if don't have a DOS assembler)
OS2: May work okay. Please e-mail me if you find a freeware TCP/IP stack
for OS/2.
Windows: See DOS :) Trumpet Winsock works fine with either the Novell or
Arcether client, assuming you remember to load winpkt of course.
LAN Manager and Windows for Workgroups: These programs use protocols that
are incompatible with ARCnet for Linux. Rather than using the
internet-standard ARCnet protocol, they try to pretend the cards are
ethernet, and confuse everyone else on the network.
An upcoming release of ARCnet for Linux may have workarounds for
this stupid behaviour.
are incompatible with the internet standard. They try to pretend
the cards are ethernet, and confuse everyone else on the network.
However, v1.90 ALPHA and later of the Linux ARCnet driver support
this protocol via the 'arc0w' device. After setting up arc0 as
usual, ifconfig and set up routes to your WfWg-protocol hosts
through arc0w.
Using the freeware Samba server and clients for Linux, you can now
interface quite nicely with TCP/IP-based WfWg or Lan Manager
networks. In addition, the Linux host can be used as a router
between the standard and WfWg protocols, so hosts that could
previously never talk to each other should now be able to.
This feature is still in early testing, so please e-mail with any
comments/questions you might have.
OS2: Has not been tested. The "correct" solution would be to buy either of
IBM's "TCP/IP for OS/2" or "Warp Connect" packages. However,
ftp.microsoft.com also has a freeware Lan Manager for OS/2 client
which should use the same protocol as WfWg does. This has not been
tested, however. Please mail me with any results.
NetBSD/AmiTCP: These use an old version of the Internet standard ARCnet
protocol which is incompatible with the Linux driver at present.
Work to support these is underway and should be available in a
standard release soon.
It works: what now?
......@@ -154,11 +177,12 @@ It works: what now?
Send mail describing your setup, preferably including driver version, kernel
version, ARCnet card model, CPU type, number of systems on your network, and
list of software in use to me at the following address:
apenwarr@tourism.807-city.on.ca
apenwarr@foxnet.net
I do send (sometimes automated) replies to all messages I receive. My mail
host is quite weird, so if you don't get a reply within a reasonable time,
please resend.
I do send (sometimes automated) replies to all messages I receive. My email
can be weird (and also usually gets forwarded all over the place along the
way to me), so if you don't get a reply within a reasonable time, please
resend.
It doesn't work: what now?
......@@ -171,31 +195,36 @@ with "arcnet:" and has shown up since the last reboot) in your mail.
If you want to try fixing it yourself (I highly recommend that you mail me
about the problem first, since it might already have been solved) you may
want to try some of the debug levels available. For heavy testing on
DEBUG_DURING or more, it would be a REALLY good idea to kill your klogd
daemon first! DEBUG_DURING displays 4-5 lines for each packet sent or
received. DEBUG_TX and RX actually DISPLAY each packet as it is sent or
D_DURING or more, it would be a REALLY good idea to kill your klogd
daemon first! D_DURING displays 4-5 lines for each packet sent or
received. D_TX and RX actually DISPLAY each packet as it is sent or
received, which is obviously quite big.
You can run the arcdump shell script (available from me) as root to list the
contents of the arcnet buffers at any time. To make any sense at all out of
this, you should grab the pertinent RFC's. (some are listed near the top of
arcnet.c). arcdump assumes your card is at 0xD0000. If it isn't, edit the
script.
You can run the arcdump shell script (available from me or in the full
ARCnet package if you got it) as root to list the contents of the arcnet
buffers at any time. To make any sense at all out of this, you should grab
the pertinent RFC's. (some are listed near the top of arcnet.c). arcdump
assumes your card is at 0xD0000. If it isn't, edit the script.
Buffers #0 and 1 are used for receiving, and Buffers #2 and 3 are for
sending. Ping-pong buffers are implemented both ways, just to confuse you.
sending. Ping-pong buffers are implemented both ways.
If your debug level is DEBUG_DURING or more, the buffers are cleared to a
constant value of 0x42 every time the card is reset (which should only
happen when you do an ifconfig up, or when Linux decides that the driver is
broken). This is to make it easier to figure out which bytes are being used
by a packet.
If your debug level includes D_DURING, the buffers are cleared to a constant
value of 0x42 every time the card is reset (which should only happen when
you do an ifconfig up, or when Linux decides that the driver is broken).
This is to make it easier to figure out which bytes are being used by a
packet.
You can change the debug level without recompiling the kernel by typing:
ifconfig arc0 down metric 1x
ifconfig arc0 down metric 1xxx
/etc/rc.d/rc.inet1
where "x" is the debug level you want. For example, "metric 14" would put
you at debug level 4. Debug level 3 is the default (D_EXTRA).
where "xxx" is the debug level you want. For example, "metric 1015" would put
you at debug level 15. Debug level 7 is currently the default.
Note that the debug level is (as of v1.90 ALPHA) a binary combination of
different debug flags; so debug level 7 is really 1+2+4 or
D_NORMAL+D_INIT+D_EXTRA. To reach D_DURING, you would add 8 to this,
resulting in debug level 15.
I want to send money: what now?
......
......@@ -6,7 +6,7 @@ driver configuration help.
Because so many people (myself included) seem to have obtained ARCnet cards
without manuals, this will be a quick listing of all jumper settings I can
find. Please e-mail apenwarr@tourism.807-city.on.ca with any settings for
find. Please e-mail apenwarr@foxnet.net with any settings for
your particular card.
Even if your ARCnet model isn't listed, but has the same jumpers, please
......@@ -15,7 +15,7 @@ e-mail me to say so.
If your model isn't listed, and has different settings, PLEASE PLEASE tell
me. I had to figure mine out without the manual, and it WASN'T FUN!
Cards Listed in this file:
Cards Listed in this file (in this order, mostly):
Manufacturer Model # Bits
------------ ------- ----
......@@ -28,10 +28,14 @@ Cards Listed in this file:
SMC PC500Longboard 16
SMC PC550Longboard 16
SMC PC600 16
SMC? LCS-8830-T 16?
Puredata PDI507 16
CNet Tech CN120-Series 8
CNet Tech CN160-Series 16
No Name -- 8/16
No Name Taiwan R.O.C(?) 8
Tiara Tiara Lancard(?)
** SMC = Standard Microsystems Corp.
** CNet Tech = CNet Technology, Inc.
......@@ -46,7 +50,7 @@ Unclassified Stuff
- And some unknowns (other info is welcome!):
From: root@ultraworld.xs4all.nl (Timo Hilbrink)
To: apenwarr@tourism.807-city.on.ca (Avery Pennarun)
To: apenwarr@foxnet.net (Avery Pennarun)
Date: Wed, 26 Oct 1994 02:10:32 +0000 (GMT)
Reply-To: timoh@xs4all.nl
......@@ -55,7 +59,7 @@ Unclassified Stuff
About the jumpers: On my PC130 there is one more jumper, located near the
cable-connector and it's for changing to star or bus topology;
closed: star - open: bus
On the PC500 are some more jumper-pins, one block labeled with RX,PDN,TXI
On the PC500 are some more jumper-pins, one block labled with RX,PDN,TXI
and another with ALE,LA17,LA18,LA19 these are undocumented..
[...more parts deleted...]
......@@ -67,16 +71,17 @@ Quick Briefing:
---------------
All ARCnet cards should have a total of four different settings:
- the I/O address: this is the "port" your ARCnet card is on. Probed
values, as of v0.14, are only from 0x200 through 0x3F0. (If your card
has additional ones, which is possible, please tell me.) This should not
be the same as any other device on your system. Supposedly MS Windows
prefers values of 0x300 or more, eating net connections on my system
otherwise.
be the same as any other device on your system. According to a doc I
got from Novell, MS Windows prefers values of 0x300 or more, eating
netconnections on my system otherwise.
- Avery's favourite: 0x300.
- the IRQ: on 8-bit cards, it might be 2 (9), 3, 4, 5, or 7.
on 16-bit cards, it might be 2 (9), 3, 4, 5, 7, or 9-15. Make
on 16-bit cards, it might be 2 (9), 3, 4, 5, 7, or 10-15. Make
sure this is different from any other card on your system. Note that
IRQ2 is the same as IRQ9, as far as Linux is concerned.
- Avery's favourite: IRQ2.
......@@ -108,12 +113,18 @@ All ARCnet cards should have a total of four different settings:
PC100, PC110, PC120, PC130 (8-bit cards)
PC500, PC600 (16-bit cards)
---------------------------------
- mainly from Avery Pennarun <apenwarr@tourism.807-city.on.ca>
- values depicted are from Avery's setup.
- mainly from Avery Pennarun <apenwarr@foxnet.net>. Values depicted are
from Avery's setup.
- special thanks to Timo Hilbrink <timoh@xs4all.nl> for noting that PC120,
130, 500, and 600 all have the same switches as Avery's PC100.
PC500/600 have several extra, undocumented pins though. (?)
- PC110 settings were verified by Stephen A. Wood <saw@cebaf.gov>
- On the other hand, John Edward Bauer <jbauer@badlands.NoDak.edu> said
the PC110 settings are all wrong. In his case, you need to switch all
the 1's with 0's. If you're having problems, try that.
- Also, the JP- and S-numbers probably don't match your card exactly. Try
to find jumpers/switches with the same number of settings - it's
probably more reliable.
JP5 [|] : : : :
......@@ -184,6 +195,7 @@ PC500, PC600 (16-bit cards)
DO NOT SET THIS TO 0 OR 255 (0xFF)!
*****************************************************************************
** Standard Microsystems Corp (SMC) **
......@@ -270,7 +282,7 @@ Setting the Node ID
The eight switches in group S2 are used to set the node ID.
Each node attached to the network must have an unique node ID which
must be different from 0.
must be diffrent from 0.
Switch 1 serves as the least significant bit (LSB).
The node ID is the sum of the values of all switches set to "1"
......@@ -309,7 +321,7 @@ Setting the I/O Base Address
----------------------------
The first three switches in switch group S1 are used to select one
of eight possible I/O Base addresses using the following table
of eight possible I/O Base addresses using the followig table
Switch | Hex I/O
......@@ -317,7 +329,7 @@ of eight possible I/O Base addresses using the following table
-------|--------
0 0 0 | 260
0 0 1 | 290
0 1 0 | 2E0 (Manufacturer's default)
0 1 0 | 2E0 (Manufactor's default)
0 1 1 | 2F0
1 0 0 | 300
1 0 1 | 350
......@@ -352,7 +364,7 @@ positions, determined by the offset, switches 7 and 8 of group S1.
0 1 0 1 0 | CD000 | CE000
0 1 0 1 1 | CD800 | CE000
| |
0 1 1 0 0 | D0000 | D2000 (Manufacturer's default)
0 1 1 0 0 | D0000 | D2000 (Manufactor's default)
0 1 1 0 1 | D0800 | D2000
0 1 1 1 0 | D1000 | D2000
0 1 1 1 1 | D1800 | D2000
......@@ -389,7 +401,7 @@ parameters. These two jumpers are normally left open.
Refer to the COM9026 Data Sheet for alternate configurations.
To select a hardware interrupt level set one (only one!) of the jumpers
IRQ2, IRQ3, IRQ4, IRQ5, IRQ7. The manufacturer's default is IRQ2.
IRQ2, IRQ3, IRQ4, IRQ5, IRQ7. The Manufactor's default is IRQ2.
Configuring the PC130E for Star or Bus Topology
......@@ -412,7 +424,7 @@ board activity:
-------|------------------- ---------|-------------------
on | normal activity flash/on | data transfer
blink | reconfiguration off | no data transfer;
off | defective board or | incorrect memory or
off | defectiv board or | incorect memory or
| node ID is zero | I/O address
......@@ -506,7 +518,7 @@ Setting the Node ID
The eight switches in group SW3 are used to set the node ID. Each node
attached to the network must have an unique node ID which must be
different from 0.
diffrent from 0.
Switch 1 serves as the least significant bit (LSB).
The node ID is the sum of the values of all switches set to "1"
......@@ -546,7 +558,7 @@ Setting the I/O Base Address
----------------------------
The first six switches in switch group SW1 are used to select one
of 32 possible I/O Base addresses using the following table
of 32 possible I/O Base addresses using the followig table
Switch | Hex I/O
6 5 4 3 2 1 | Address
......@@ -565,7 +577,7 @@ of 32 possible I/O Base addresses using the following table
0 1 1 0 1 1 | 2B0
0 1 1 1 0 0 | 2C0
0 1 1 1 0 1 | 2D0
0 1 1 1 1 0 | 2E0 (Manufacturer's default)
0 1 1 1 1 0 | 2E0 (Manufactor's default)
0 1 1 1 1 1 | 2F0
1 1 0 0 0 0 | 300
1 1 0 0 0 1 | 310
......@@ -634,10 +646,119 @@ board activity:
-------|------------------- ---------|-------------------
on | normal activity flash/on | data transfer
blink | reconfiguration off | no data transfer;
off | defective board or | incorrect memory or
off | defectiv board or | incorect memory or
| node ID is zero | I/O address
*****************************************************************************
** Possibly SMC **
LCS-8830-T (16-bit card)
------------------------
- from Mathias Katzer <mkatzer@HRZ.Uni-Bielefeld.DE>
This is a LCS-8830-T made by SMC, I think ('SMC' only appears on one PLCC,
nowhere else, not even on the few xeroxed sheets from the manual).
SMC Arcnet Board Type LCS-8830-T
------------------------------------
| |
| JP3 88 8 JP2 |
| ##### | \ |
| ##### ET1 ET2 ###|
| 8 ###|
| U3 SW 1 JP0 ###| Phone Jacks
| -- ###|
| | | |
| | | SW2 |
| | | |
| | | ##### |
| -- ##### #### BNC Connector
| ####
| 888888 JP1 |
| 234567 |
-- -------
|||||||||||||||||||||||||||
--------------------------
SW1: DIP-Switches for Station Address
SW2: DIP-Switches for Memory Base and I/O Base addresses
JP0: If closed, internal termination on (default open)
JP1: IRQ Jumpers
JP2: Boot-ROM enabled if closed
JP3: Jumpers for respsonse timeout
U3: Boot-ROM Socket
ET1 ET2 Response Time Idle Time Reconfiguration Time
78 86 840
X 285 316 1680
X 563 624 1680
X X 1130 1237 1680
(X means closed jumper)
(DIP-Switch downwards means "0")
The station address is binary-coded with SW1.
The I/O base address is coded with DIP-Switches 6,7 and 8 of SW2:
Switches Base
678 Address
000 260-26f
100 290-29f
010 2e0-2ef
110 2f0-2ff
001 300-30f
101 350-35f
011 380-38f
111 3e0-3ef
DIP Switches 1-5 of SW2 encode the RAM and ROM Adress Range:
Switches Ram Rom
12345 Adress Range Address Range
00000 C:0000-C:07ff C:2000-C:3fff
10000 C:0800-C:0fff
01000 C:1000-C:17ff
11000 C:1800-C:1fff
00100 C:4000-C:47ff C:6000-C:7fff
10100 C:4800-C:4fff
01100 C:5000-C:57ff
11100 C:5800-C:5fff
00010 C:C000-C:C7ff C:E000-C:ffff
10010 C:C800-C:Cfff
01010 C:D000-C:D7ff
11010 C:D800-C:Dfff
00110 D:0000-D:07ff D:2000-D:3fff
10110 D:0800-D:0fff
01110 D:1000-D:17ff
11110 D:1800-D:1fff
00001 D:4000-D:47ff D:6000-D:7fff
10001 D:4800-D:4fff
01001 D:5000-D:57ff
11001 D:5800-D:5fff
00101 D:8000-D:87ff D:A000-D:bfff
10101 D:8800-D:8fff
01101 D:9000-D:97ff
11101 D:9800-D:9fff
00011 D:C000-D:c7ff D:E000-D:ffff
10011 D:C800-D:cfff
01011 D:D000-D:d7ff
11011 D:D800-D:dfff
00111 E:0000-E:07ff E:2000-E:3fff
10111 E:0800-E:0fff
01111 E:1000-E:17ff
11111 E:1800-E:1fff
*****************************************************************************
** PureData Corp **
......@@ -690,7 +811,7 @@ further information is welcome.]
DIP Switches:
The dip switches accessible on the accessible end of the card while
The dipswitches accessible on the accessible end of the card while
it is installed, is used to set the arcnet address. There are 8
switches. Use an address from 1 to 254.
......@@ -781,6 +902,7 @@ DIP Switches:
------------------------
- from Juergen Seifert <seifert@htwm.de>
CNET TECHNOLOGY INC. (CNet) ARCNET 120A SERIES
==============================================
......@@ -856,7 +978,7 @@ Setting the Node ID
-------------------
The eight switches in SW2 are used to set the node ID. Each node attached
to the network must have an unique node ID which must be different from 0.
to the network must have an unique node ID which must be diffrent from 0.
Switch 1 (ID0) serves as the least significant bit (LSB).
The node ID is the sum of the values of all switches set to "1"
......@@ -896,7 +1018,7 @@ Setting the I/O Base Address
----------------------------
The last three switches in switch block SW1 are used to select one
of eight possible I/O Base addresses using the following table
of eight possible I/O Base addresses using the followig table
Switch | Hex I/O
......@@ -904,7 +1026,7 @@ of eight possible I/O Base addresses using the following table
------------|--------
ON ON ON | 260
OFF ON ON | 290
ON OFF ON | 2E0 (Manufacturer's default)
ON OFF ON | 2E0 (Manufactor's default)
OFF OFF ON | 2F0
ON ON OFF | 300
OFF ON OFF | 350
......@@ -926,7 +1048,7 @@ Switches 1-5 of switch block SW1 select the Memory Base address.
ON ON ON ON ON | C0000 | C2000
ON ON OFF ON ON | C4000 | C6000
ON ON ON OFF ON | CC000 | CE000
ON ON OFF OFF ON | D0000 | D2000 (Manufacturer's default)
ON ON OFF OFF ON | D0000 | D2000 (Manufactor's default)
ON ON ON ON OFF | D4000 | D6000
ON ON OFF ON OFF | D8000 | DA000
ON ON ON OFF OFF | DC000 | DE000
......@@ -937,7 +1059,7 @@ Switches 1-5 of switch block SW1 select the Memory Base address.
Note: Since the switches 1 and 2 are always set to ON it may be possible
that they can be used to add an offset of 2K, 4K or 6K to the base
address, but this feature is not documented in the manual and I
haven't tested it yet.
haven't testet it yet.
Setting the Interrupt Line
......@@ -1066,7 +1188,7 @@ Setting the Node ID
-------------------
The eight switches in SW2 are used to set the node ID. Each node attached
to the network must have an unique node ID which must be different from 0.
to the network must have an unique node ID which must be diffrent from 0.
Switch 1 (ID0) serves as the least significant bit (LSB).
The node ID is the sum of the values of all switches set to "1"
......@@ -1106,14 +1228,14 @@ Setting the I/O Base Address
----------------------------
The first six switches in switch block SW1 are used to select the I/O Base
address using the following table:
address using the followig table:
Switch | Hex I/O
1 2 3 4 5 6 | Address
------------------------|--------
OFF ON ON OFF OFF ON | 260
OFF ON OFF ON ON OFF | 290
OFF ON OFF OFF OFF ON | 2E0 (Manufacturer's default)
OFF ON OFF OFF OFF ON | 2E0 (Manufactor's default)
OFF ON OFF OFF OFF OFF | 2F0
OFF OFF ON ON ON ON | 300
OFF OFF ON OFF ON OFF | 350
......@@ -1162,9 +1284,9 @@ JP3 through JP13 using the following table:
13 | 2 (=9) Default!
Note: - Do not use JP11=IRQ6, it may conflict with your Floppy Disk
Controller
Controler
- Use JP3=IRQ14 only, if you don't have an IDE-, MFM-, or RLL-
Hard Disk, it may conflict with their controllers
Hard Disk, it may conflict with their controlers
Setting the Timeout Parameters
......@@ -1185,8 +1307,8 @@ NONAME 8-BIT ARCNET
===================
I have named this ARCnet card "NONAME", since there is no name of any
manufacturer on the Installation manual nor on the shipping box. The only
hint to the existence of a manufacturer at all is written into copper,
manufactor on the Installation manual nor on the shipping box. The only
hint to the existence of a manufactor at all is written into cupper,
it is "Made in Taiwan"
This description has been written by Juergen Seifert <seifert@htwm.de>
......@@ -1230,7 +1352,7 @@ ET1, ET2 Extended Timeout Select
ROM ROM Enable Select
CN RG62 Coax Connector
STAR| BUS | T/P Three fields for placing a sign (colored circle)
indicating the topology of the card
indicating the topologie of the card
Setting one of the switches to Off means "1", On means "0".
......@@ -1240,7 +1362,7 @@ Setting the Node ID
The eight switches in group SW1 are used to set the node ID.
Each node attached to the network must have an unique node ID which
must be different from 0.
must be diffrent from 0.
Switch 8 serves as the least significant bit (LSB).
The node ID is the sum of the values of all switches set to "1"
......@@ -1280,14 +1402,14 @@ Setting the I/O Base Address
----------------------------
The first three switches in switch group SW2 are used to select one
of eight possible I/O Base addresses using the following table
of eight possible I/O Base addresses using the followig table
Switch | Hex I/O
1 2 3 | Address
------------|--------
ON ON ON | 260
ON ON OFF | 290
ON OFF ON | 2E0 (Manufacturer's default)
ON OFF ON | 2E0 (Manufactor's default)
ON OFF OFF | 2F0
OFF ON ON | 300
OFF ON OFF | 350
......@@ -1322,7 +1444,7 @@ positions, determined by the offset, switches 7 and 8 of group SW2.
0 1 0 1 0 | CD000 | CE000
0 1 0 1 1 | CD800 | CE000
| |
0 1 1 0 0 | D0000 | D2000 (Manufacturer's default)
0 1 1 0 0 | D0000 | D2000 (Manufactor's default)
0 1 1 0 1 | D0800 | D2000
0 1 1 1 0 | D1000 | D2000
0 1 1 1 1 | D1800 | D2000
......@@ -1355,14 +1477,14 @@ Setting Interrupt Request Lines (IRQ)
-------------------------------------
To select a hardware interrupt level set one (only one!) of the jumpers
IRQ2, IRQ3, IRQ4, IRQ5 or IRQ7. The manufacturer's default is IRQ2.
IRQ2, IRQ3, IRQ4, IRQ5 or IRQ7. The Manufactor's default is IRQ2.
Setting the Timeouts
--------------------
The two jumpers labeled ET1 and ET2 are used to determine the timeout
parameters (response and reconfiguration time). Every node in a network
parameters (respons and reconfiguration time). Every node in a network
must be set to the same timeout values.
ET1 ET2 | Response Time (us) | Reconfiguration Time (ms)
......@@ -1382,7 +1504,7 @@ The manual of my 8-Bit NONAME ARCnet Card contains another description
of a 16-Bit Coax / Twisted Pair Card. This description is incomplete,
because there are missing two pages in the manual booklet. (The table
of contents reports pages ... 2-9, 2-11, 2-12, 3-1, ... but inside
the booklet there is a different way of counting ... 2-9, 2-10, A-1,
the booklet there is a diffrent way of counting ... 2-9, 2-10, A-1,
(empty page), 3-1, ..., 3-18, A-1 (again), A-2)
Also the picture of the board layout is not as good as the picture of
8-Bit card, because there isn't any letter like "SW1" written to the
......@@ -1429,7 +1551,7 @@ Setting the Node ID
The eight switches in group SW2 are used to set the node ID.
Each node attached to the network must have an unique node ID which
must be different from 0.
must be diffrent from 0.
Switch 8 serves as the least significant bit (LSB).
The node ID is the sum of the values of all switches set to "1"
......@@ -1469,14 +1591,14 @@ Setting the I/O Base Address
----------------------------
The first three switches in switch group SW1 are used to select one
of eight possible I/O Base addresses using the following table
of eight possible I/O Base addresses using the followig table
Switch | Hex I/O
3 2 1 | Address
------------|--------
ON ON ON | 260
ON ON OFF | 290
ON OFF ON | 2E0 (Manufacturer's default)
ON OFF ON | 2E0 (Manufactor's default)
ON OFF OFF | 2F0
OFF ON ON | 300
OFF ON OFF | 350
......@@ -1511,7 +1633,7 @@ positions, determined by the offset, switches 4 and 5 of group SW1.
0 1 0 1 0 | CD000 | CE000
0 1 0 1 1 | CD800 | CE000
| |
0 1 1 0 0 | D0000 | D2000 (Manufacturer's default)
0 1 1 0 0 | D0000 | D2000 (Manufactor's default)
0 1 1 0 1 | D0800 | D2000
0 1 1 1 0 | D1000 | D2000
0 1 1 1 1 | D1800 | D2000
......@@ -1551,11 +1673,239 @@ Setting the Timeouts
*****************************************************************************
** No Name **
8-bit cards ("Made in Taiwan R.O.C.")
-----------
- from Vojtech Pavlik <vpav4328@diana.troja.mff.cuni.cz>
I have named this ARCnet card "NONAME", since I got only the card with
no manual at all and the only text identifying the manufacturer is
"MADE IN TAIWAN R.O.C" printed on the card.
This description was written by Vojtech Pavlik
(vpav4328@diana.troja.mff.cuni.cz) using parts of the ARCNET-jumpers
README file from Linux kernel 1.2.2.
____________________________________________________________
| 1 2 3 4 5 6 7 8 |
| |o|o| JP1 o|o|o|o|o|o|o|o| ON |
| + o|o|o|o|o|o|o|o| ___|
| _____________ o|o|o|o|o|o|o|o| OFF _____ | | ID7
| | | SW1 | | | | ID6
| > RAM (2k) | ____________________ | H | | S | ID5
| |_____________| | || y | | W | ID4
| | || b | | 2 | ID3
| | || r | | | ID2
| | || i | | | ID1
| | 90C65 || d | |___| ID0
| SW3 | || | |
| |o|o|o|o|o|o|o|o| ON | || I | |
| |o|o|o|o|o|o|o|o| | || C | |
| |o|o|o|o|o|o|o|o| OFF |____________________|| | _____|
| 1 2 3 4 5 6 7 8 | | | |___
| ______________ | | | BNC |___|
| | | |_____| |_____|
| > EPROM SOCKET | |
| |______________| |
| ______________|
| |
|_____________________________________________|
Legend:
90C65 ARCNET Chip
SW1 1-5: Base Memory Address Select
6-8: Base I/O Address Select
SW2 1-8: Node ID Select (ID0-ID7)
SW3 1-5: IRQ Select
6-7: Extra Timeout
8 : Rom Enable
JP1 Led connector
BNC Coax connector
Although the jumpers SW1 and SW3 are marked SW, not JP, they are jumpers, not
switches.
Setting the jumpers to ON means connecting the upper two pins, off the bottom
two - or - in case of IRQ setting, connecting none of them at all.
Setting the Node ID
-------------------
The eight switches in SW2 are used to set the node ID. Each node attached
to the network must have an unique node ID which must be diffrent from 0.
Switch 1 (ID0) serves as the least significant bit (LSB).
Setting one of the switches to Off means "1", On means "0".
The node ID is the sum of the values of all switches set to "1"
These values are:
Switch | Label | Value
-------|-------|-------
1 | ID0 | 1
2 | ID1 | 2
3 | ID2 | 4
4 | ID3 | 8
5 | ID4 | 16
6 | ID5 | 32
7 | ID6 | 64
8 | ID7 | 128
Some Examples:
Switch | Hex | Decimal
8 7 6 5 4 3 2 1 | Node ID | Node ID
----------------|---------|---------
0 0 0 0 0 0 0 0 | not allowed
0 0 0 0 0 0 0 1 | 1 | 1
0 0 0 0 0 0 1 0 | 2 | 2
0 0 0 0 0 0 1 1 | 3 | 3
. . . | |
0 1 0 1 0 1 0 1 | 55 | 85
. . . | |
1 0 1 0 1 0 1 0 | AA | 170
. . . | |
1 1 1 1 1 1 0 1 | FD | 253
1 1 1 1 1 1 1 0 | FE | 254
1 1 1 1 1 1 1 1 | FF | 255
Setting the I/O Base Address
----------------------------
The last three switches in switch block SW1 are used to select one
of eight possible I/O Base addresses using the followig table
Switch | Hex I/O
6 7 8 | Address
------------|--------
ON ON ON | 260
OFF ON ON | 290
ON OFF ON | 2E0 (Manufactor's default)
OFF OFF ON | 2F0
ON ON OFF | 300
OFF ON OFF | 350
ON OFF OFF | 380
OFF OFF OFF | 3E0
Setting the Base Memory (RAM) buffer Address
--------------------------------------------
The memory buffer (RAM) requires 2K. The base of this buffer can be
located in any of eight positions. The address of the Boot Prom is
memory base + 0x2000.
Jumpers 3-5 of jumper block SW1 select the Memory Base address.
Switch | Hex RAM | Hex ROM
1 2 3 4 5 | Address | Address *)
--------------------|---------|-----------
ON ON ON ON ON | C0000 | C2000
ON ON OFF ON ON | C4000 | C6000
ON ON ON OFF ON | CC000 | CE000
ON ON OFF OFF ON | D0000 | D2000 (Manufactor's default)
ON ON ON ON OFF | D4000 | D6000
ON ON OFF ON OFF | D8000 | DA000
ON ON ON OFF OFF | DC000 | DE000
ON ON OFF OFF OFF | E0000 | E2000
*) To enable the Boot ROM set the jumper 8 of jumper block SW3 to position ON.
The jumpers 1 and 2 probably add 0x0800, 0x1000 and 0x1800 to RAM addres.
Setting the Interrupt Line
--------------------------
Jumpers 1-5 of the jumper block SW3 controll the IRQ level.
Jumper | IRQ
1 2 3 4 5 |
----------------------------
ON OFF OFF OFF OFF | 2
OFF ON OFF OFF OFF | 3
OFF OFF ON OFF OFF | 4
OFF OFF OFF ON OFF | 5
OFF OFF OFF OFF ON | 7
Setting the Timeout Parameters
------------------------------
The jumpers 6-7 of the jumper block SW3 are used to determine the timeout
parameters. These two jumpers are normally left in the OFF position.
*****************************************************************************
** Tiara **
(model unknown)
-------------------------
- from Christoph Lameter <clameter@netcom.com>
Here is information about my card as far as I could figure it out:
----------------------------------------------- tiara
Tiara LanCard of Tiara Computer Systems.
+----------------------------------------------+
! ! Transmitter Unit ! !
! +------------------+ -------
! MEM Coax Connector
! ROM 7654321 <- I/O -------
! : : +--------+ !
! : : ! 90C66LJ! +++
! : : ! ! !D Switch to set
! : : ! ! !I the Nodenumber
! : : +--------+ !P
! !++
! 234567 <- IRQ !
+------------!!!!!!!!!!!!!!!!!!!!!!!!--------+
!!!!!!!!!!!!!!!!!!!!!!!!
0 = Jumper Installed
1 = Open
Top Jumper line Bit 7 = Rom Enable 654=Memory location 321=I/O
Settings for Memory Location (Top Jumper Line)
456 Address selected
000 C0000
001 C4000
010 CC000
011 D0000
100 D4000
101 D8000
110 DC000
111 E0000
Settings for I/O Address (Top Jumper Line)
123 Port
000 260
001 290
010 2E0
011 2F0
100 300
101 350
110 380
111 3E0
Settings for IRQ Selection (Lower Jumper Line)
234567
011111 IRQ 2
101111 IRQ 3
110111 IRQ 4
111011 IRQ 5
111110 IRQ 7
*****************************************************************************
Other Cards
-----------
I have no information on other models of ARCnet cards at the moment. Please
send any and all info to:
apenwarr@tourism.807-city.on.ca
apenwarr@foxnet.net
Thanks.
......@@ -7,6 +7,8 @@
**********************
The original copyright was as follows:
skeleton.c Written 1993 by Donald Becker.
Copyright 1993 United States Government as represented by the
Director, National Security Agency. This software may only be used
......@@ -15,101 +17,143 @@
**********************
v1.02 (95/06/21)
- A fix to make "exception" packets sent from Linux receivable
on other systems. (The protocol_id byte was sometimes being set
incorrectly, and Linux wasn't checking it on receive so it
didn't show up)
- Updated my email address. Please use apenwarr@foxnet.net
from now on.
v1.92 ALPHA (95/07/11)
- Fixes to make things work with kernel 1.3.x. Completely broke
1.2.x support. Oops? 1.2.x users keep using 1.91 ALPHA until I
get out a version that supports both.
v1.91 ALPHA (95/07/02)
- Oops. Exception packets hit us again! I remembered to test
them in Windows-protocol mode, but due to the many various
changes they broke in RFC1201 instead. All fixed.
- A long-standing bug with "exception" packets not setting
protocol_id properly has been corrected. This would have caused
random problems talking to non-Linux servers. I've also sent in
a patch to fix this in the latest stable ARCnet (now 1.02).
- ARC_P_IPX is an RFC1201 protocol too. Thanks, Tomasz.
- We're now "properly" (I think) handling the multiple 'tbusy' and
'start' flags (one for each protocol device) better.
- The driver should now start without a NULL-pointer dereference
if you aren't connected to the network.
v1.90 ALPHA (95/06/18)
- Removal of some outdated and messy config options (no one has
ever complained about the defaults since they were introduced):
DANGER_PROBE, EXTRA_DELAYS, IRQ_XMIT, CAREFUL_XMIT,
STRICT_MEM_DETECT, LIMIT_MTU, USE_TIMER_HANDLER. Also took out
a few "#if 0" sections which are no longer useful.
- Cleaned up debug levels - now instead of levels, there are
individual flags. Watch out when changing with ifconfig.
- More cleanups and beautification. Removed more dead code and
made sure every function was commented.
- Fixed the DETECT_RECONFIGS option so that it actually _won't_
detect reconfigs. Previously, the RECON irq would be disabled
but the recon messages would still be logged on the next normal
IRQ.
- Initial support for "multiprotocol" ARCnet (this involved a LOT
of reorganizing!). Added an arc0w device, which allows us to
talk to "Windows" ARCnet TCP/IP protocol. To use it, ifconfig
arc0 and arc0w (in that order). For now, Windows-protocol
hosts should have routes through arc0w - eventually I hope to
make things more automatic.
v1.11 ALPHA (95/06/07)
- Tomasz saves the day again with patches to fix operation if the
new VERIFY_ACK option is disabled.
- LOTS of little code cleanups/improvements by Tomasz.
- Changed autoprobe, since the "never-changing command port"
probe was causing problems for some people. I also reset the
card fewer times during the probe if DANGER_PROBE is defined,
since DANGER_PROBE seems to be a more reliable method anyway.
- It looks like the null-pointer problem was finally REALLY fixed
by some change from Linux 1.2.8 to 1.2.9. How handy!
v1.10 ALPHA (95/04/15)
- Fixed (?) some null-pointer dereference bugs
- Added better network error detection (from Tomasz) - in
particular, we now notice when our network isn't connected,
also known as a "network reconfiguration."
- We now increment lp->stats.tx_dropped in several more places,
on a suggestion from Tomasz.
- Minor cleanups/spelling fixes.
- We now monitor the TXACK bit in the status register: we don't do
anything with it yet, just notice when a transmitted packet isn't
acknowledged.
- Minor fix with sequence numbers (sometimes they were being sent in
the wrong order due to Linux's packet queuing).
v1.01 (95/03/24)
- Fixed some IPX-related bugs. (Thanks to Tomasz Motylewski
<motyl@tichy.ch.uj.edu.pl> for the patches to make arcnet work
with dosemu!)
v1.0 (95/02/15)
v1.00 (95/02/15)
- Initial non-alpha release.
TO DO:
- Test in systems with NON-ARCnet network cards, just to see if
autoprobe kills anything. With any luck, it won't. (It's pretty
careful.)
- Except some unfriendly NE2000's die. (as of 0.40-ALPHA)
- cards with shared memory that can be "turned off?"
autoprobe kills anything. Currently, we do cause some NE2000's to
die.
- What about cards with shared memory that can be "turned off?"
- NFS mount freezes after several megabytes to SOSS for DOS.
unmount/remount works. Is this arcnet-specific? I don't know.
- Add support for the various stupid bugs ("I didn't read the RFC"
syndrome) in Windows for Workgroups and LanMan.
*/
/**************************************************************************/
unmount/remount fixes it. Is this arcnet-specific? I don't know.
- Add support for "old" (RFC1051) protocol arcnet, such as AmiTCP
and NetBSD. Work in Tomasz' initial support for this.
- How about TCP/IP over netbios?
- Some newer ARCnets support promiscuous mode, supposedly.
If someone sends me information, I'll try to implement it.
- Remove excess lock variables that are probably not necessary
anymore due to the changes in Linux 1.2.9.
/* define this if you want to use the new but possibly dangerous ioprobe
* If you get lockups right after status5, you probably need
* to undefine this. It should make more cards probe correctly,
* I hope.
*/
#define DANGER_PROBE
/* define this if you want to use the "extra delays" which were removed
* in 0.41 since they seemed needless.
*/
#undef EXTRA_DELAYS
Sources:
- Crynwr arcnet.com/arcether.com packet drivers.
- arcnet.c v0.00 dated 1/1/94 and apparently by
Donald Becker - it didn't work :)
- skeleton.c v0.05 dated 11/16/93 by Donald Becker
(from Linux Kernel 1.1.45)
- The official ARCnet data sheets (!) thanks to Ken Cornetet
<kcornete@nyx10.cs.du.edu>
- RFC's 1201 and 1051 (mostly 1201) - re: ARCnet IP packets
- net/inet/eth.c (from kernel 1.1.50) for header-building info...
- Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
- Textual information and more alternate source from Joachim Koenig
<jojo@repas.de>
*/
/* undefine this if you want to use the non-IRQ-driven transmitter. (possibly
* safer, although it takes more CPU time and IRQ_XMIT seems fine right now)
*/
#define IRQ_XMIT
static char *version =
"arcnet.c:v1.92 ALPHA 95/07/11 Avery Pennarun <apenwarr@foxnet.net>\n";
/* define this for "careful" transmitting. Try with and without if you have
* problems. If you use IRQ_XMIT, do NOT define this.
*/
#undef CAREFUL_XMIT
/**************************************************************************/
/* define this for an extra-careful memory detect. This should work all
* the time now, but you never know.
/* Define this if you want to detect network reconfigurations.
* They may be a real nuisance on a larger ARCnet network: but if you are
* a network administrator you probably would like to count them.
* Reconfigurations will be recorded in stats.tx_carrier_errors
* (the last field of the /proc/net/dev file).
*
* The card sends the reconfiguration signal when it loses the connection
* to the rest of its network. It is a 'Hello, is anybody there?' cry. This
* usually happens when a new computer on the network is powered on or when
* the cable is broken.
*/
#define STRICT_MEM_DETECT
#define DETECT_RECONFIGS
/* define this to use the "old-style" limited MTU by default. It basically
* disables packet splitting. ifconfig can still be used to reset the MTU.
/* Define this if you want to make sure transmitted packets are "acknowledged"
* by the destination host, as long as they're not to the broadcast address.
*
* leave this disabled if possible, so it will use ethernet defaults,
* which is our goal.
* That way, if one segment of a split packet doesn't get through, it can
* be resent immediately rather than confusing the other end.
*
* Disable this to return to 1.01-style behaviour, if you have problems.
*/
#undef LIMIT_MTU
#define VERIFY_ACK
/* define this if you have a problem with the card getting "stuck" now and
* then, which can only be fixed by a reboot or resetting the card manually
* via ifconfig up/down. ARCnet will set a timer function which is called
* 8 times every second.
*
* This should no longer be necessary. if you experience "stuck" ARCnet
* drivers, please email apenwarr@foxnet.net or I will remove
* this feature in a future release.
/* Define this if you want to make it easier to use the "call trace" when
* a kernel NULL pointer assignment occurs.
*/
#undef USE_TIMER_HANDLER
#undef static
/**************************************************************************/
static char *version =
"arcnet.c:v1.02 95/06/21 Avery Pennarun <apenwarr@foxnet.net>\n";
/*
Sources:
Crynwr arcnet.com/arcether.com packet drivers.
arcnet.c v0.00 dated 1/1/94 and apparently by
Donald Becker - it didn't work :)
skeleton.c v0.05 dated 11/16/93 by Donald Becker
(from Linux Kernel 1.1.45)
...I sure wish I had the ARCnet data sheets right about now!
RFC's 1201 and 1051 (mostly 1201) - re: ARCnet IP packets
net/inet/eth.c (from kernel 1.1.50) for header-building info...
Alternate Linux ARCnet source by V.Shergin <vsher@sao.stavropol.su>
Textual information and more alternate source from Joachim Koenig
<jojo@repas.de>
*/
#include <linux/config.h>
#ifdef MODULE
......@@ -139,31 +183,31 @@ static char *version =
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <net/arp.h>
/* debug levels:
* D_OFF production
* D_NORMAL verification
* D_INIT show init/detect messages
* D_DURING show messages during normal use (ie interrupts)
* D_DATA show packets data from skb's, not on Arcnet card
* D_TX show tx packets
* D_RX show tx+rx packets
/* new debugging bitflags: each option can be enabled individually.
*
* these can be set while the driver is running by typing:
* ifconfig arc0 down metric 1xxx HOSTNAME
* where 1xx is 1000 + the debug level you want
* and HOSTNAME is your hostname/ip address
* and then resetting your routes.
*/
#define D_OFF 0
#define D_NORMAL 1
#define D_INIT 2
#define D_EXTRA 3
#define D_DURING 4
#define D_DATA 6
#define D_TX 8
#define D_RX 9
#define D_NORMAL 1 /* D_NORMAL startup announcement */
#define D_INIT 2 /* D_INIT show init/probe messages */
#define D_EXTRA 4 /* D_EXTRA extra information */
/* debug levels past this point give LOTS of output! */
#define D_DURING 8 /* D_DURING during normal use (irq's) */
#define D_TX 16 /* D_TX show tx packets */
#define D_RX 32 /* D_RX show rx packets */
#define D_SKB 64 /* D_SKB dump skb's */
#ifndef NET_DEBUG
#define NET_DEBUG D_INIT
#define NET_DEBUG D_NORMAL|D_INIT|D_EXTRA
#endif
static unsigned int net_debug = NET_DEBUG;
int arcnet_debug = NET_DEBUG;
#ifndef HAVE_AUTOIRQ
/* From auto_irq.c, in ioport.h for later versions. */
......@@ -180,10 +224,20 @@ extern struct device *irq2dev_map[16];
#endif
/* macro to simplify debug checking */
#define BUGLVL(x) if (net_debug>=x)
#define BUGLVL(x) if (arcnet_debug&(x))
/* Some useful multiprotocol macros */
#define TBUSY lp->adev->tbusy \
=lp->wdev->tbusy
#define IF_TBUSY (lp->adev->tbusy \
|| lp->wdev->tbusy)
#define START lp->adev->start \
=lp->wdev->start
/* The number of low I/O ports used by the ethercard. */
#define ETHERCARD_TOTAL_SIZE 16
#define ARCNET_TOTAL_SIZE 16
/* Handy defines for ARCnet specific stuff */
......@@ -193,7 +247,8 @@ extern struct device *irq2dev_map[16];
#define COMMAND (ioaddr+1) /* writable, returns random vals on read (?) */
#define RESET (ioaddr+8) /* software reset writable */
/* time needed for various things (in clock ticks, 1/100 sec) */
/* Time needed for various things (in clock ticks, 1/100 sec) */
/* We mostly don't bother with these - watch out. */
#define RESETtime 40 /* reset */
#define XMITtime 10 /* send (?) */
#define ACKtime 10 /* acknowledge (?) */
......@@ -206,66 +261,73 @@ extern struct device *irq2dev_map[16];
* These numbers are compared with the length of the full packet,
* including ClientData header.
*/
#define MTU (253+EXTRA_CLIENTDATA) /* normal packet max size */
#define MinTU (257+EXTRA_CLIENTDATA) /* extended packet min size */
#define XMTU (508+EXTRA_CLIENTDATA) /* extended packet max size */
#define MTU 253 /* normal packet max size */
#define MinTU 257 /* extended packet min size */
#define XMTU 508 /* extended packet max size */
/* status/interrupt mask bit fields */
#define TXFREEflag 0x001 /* transmitter available */
#define TXACKflag 0x002 /* transmitted msg. ackd */
#define RECONflag 0x004 /* system reconfigured */
#define TESTflag 0x008 /* test flag */
#define RESETflag 0x010 /* power-on-reset */
#define RES1flag 0x020 /* unused */
#define RES2flag 0x040 /* unused */
#define NORXflag 0x080 /* receiver inhibited */
#define TXFREEflag 0x01 /* transmitter available */
#define TXACKflag 0x02 /* transmitted msg. ackd */
#define RECONflag 0x04 /* system reconfigured */
#define TESTflag 0x08 /* test flag */
#define RESETflag 0x10 /* power-on-reset */
#define RES1flag 0x20 /* unused */
#define RES2flag 0x40 /* unused */
#define NORXflag 0x80 /* receiver inhibited */
#ifdef DETECT_RECONFIGS
#define RECON_flag RECONflag
#else
#define RECON_flag 0
#endif
/* in the command register, the following bits have these meanings:
* 0-2 command
* 3-4 page number (for enable rcv/xmt command)
* 7 receive broadcasts
*/
#define NOTXcmd 0x001 /* disable transmitter */
#define NORXcmd 0x002 /* disable receiver */
#define TXcmd 0x003 /* enable transmitter */
#define RXcmd 0x004 /* enable receiver */
#define CONFIGcmd 0x005 /* define configuration */
#define CFLAGScmd 0x006 /* clear flags */
#define TESTcmd 0x007 /* load test flags */
#define NOTXcmd 0x01 /* disable transmitter */
#define NORXcmd 0x02 /* disable receiver */
#define TXcmd 0x03 /* enable transmitter */
#define RXcmd 0x04 /* enable receiver */
#define CONFIGcmd 0x05 /* define configuration */
#define CFLAGScmd 0x06 /* clear flags */
#define TESTcmd 0x07 /* load test flags */
/* flags for "clear flags" command */
#define RESETclear 0x008 /* power-on-reset */
#define CONFIGclear 0x010 /* system reconfigured */
#define RESETclear 0x08 /* power-on-reset */
#define CONFIGclear 0x10 /* system reconfigured */
/* flags for "load test flags" command */
#define TESTload 0x008 /* test flag (diagnostic) */
#define TESTload 0x08 /* test flag (diagnostic) */
/* byte deposited into first address of buffers on reset */
#define TESTvalue 0321 /* that's octal for 0xD1 :) */
/* for "enable receiver" command */
#define RXbcasts 0x080 /* receive broadcasts */
#define RXbcasts 0x80 /* receive broadcasts */
/* flags for "define configuration" command */
#define NORMALconf 0x000 /* 1-249 byte packets */
#define EXTconf 0x008 /* 250-504 byte packets */
#define NORMALconf 0x00 /* 1-249 byte packets */
#define EXTconf 0x08 /* 250-504 byte packets */
/* buffers (4 total) used for receive and xmit.
*/
#define EnableReceiver() outb(RXcmd|(recbuf<<3)|RXbcasts,COMMAND)
/*#define TXbuf 2 (Obsoleted by ping-pong xmits) */
/* Protocol ID's */
/* RFC1201 Protocol ID's */
#define ARC_P_IP 212 /* 0xD4 */
#define ARC_P_ARP 213 /* 0xD5 */
#define ARC_P_RARP 214 /* 0xD6 */
#define ARC_P_IPX 250 /* 0xFA */
/* MS LanMan/WfWg protocol */
#define ARC_P_MS_TCPIP 0xE8
/* Unsupported/indirectly supported protocols */
#define ARC_P_LANSOFT 251 /* 0xFB */
#define ARC_P_ATALK 0xDD
/* Length of time between "stuck" checks */
#define TIMERval (HZ/8) /* about 1/8 second */
/* these structures define the format of an arcnet packet. */
#define NORMAL 0
#define EXTENDED 1
......@@ -293,17 +355,16 @@ union ArcPacket
*/
struct ClientData
{
/* data that's NOT part of real packet */
u_char daddr; /* Destination address - stored here,
* but WE MUST GET RID OF IT BEFORE SENDING A
* PACKET!!
/* data that's NOT part of real packet - we MUST get rid of it before
* actually sending!!
*/
u_char saddr; /* Source address - necessary for IPX protocol */
u_char saddr, /* Source address - needed for IPX */
daddr; /* Destination address */
/* data that IS part of real packet */
u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, or ARC_P_RARP */
u_char protocol_id, /* ARC_P_IP, ARC_P_ARP, etc */
split_flag; /* for use with split packets */
u_short sequence; /* sequence number (?) */
u_short sequence; /* sequence number */
};
#define EXTRA_CLIENTDATA (sizeof(struct ClientData)-4)
......@@ -329,6 +390,11 @@ struct Outgoing
segnum, /* segment being sent */
numsegs, /* number of segments */
seglen; /* length of segment */
#ifdef VERIFY_ACK
short lastload_dest, /* can last loaded packet be acked? */
lasttrans_dest; /* can last TX'd packet be acked? */
#endif
};
......@@ -344,9 +410,13 @@ struct arcnet_local {
in_txhandler, /* in TX_IRQ handler? */
sending; /* transmit in progress? */
short tx_left; /* segments of split packet left to TX */
struct timer_list timer; /* the timer interrupt struct */
struct Incoming incoming[256]; /* one from each address */
struct Outgoing outgoing; /* packet currently being sent */
struct device *adev; /* RFC1201 protocol device */
struct device *wdev; /* Windows protocol device */
};
......@@ -356,40 +426,38 @@ extern int arcnet_probe(struct device *dev);
static int arcnet_memprobe(struct device *dev,u_char *addr);
static int arcnet_ioprobe(struct device *dev, short ioaddr);
#endif
static int arcnetW_init(struct device *dev);
static int arcnet_open(struct device *dev);
static int arcnet_close(struct device *dev);
static int arcnet_reset(struct device *dev);
static int arcnet_send_packet(struct sk_buff *skb, struct device *dev);
#ifdef CAREFUL_XMIT
static void careful_xmit_wait(struct device *dev);
#else
#define careful_xmit_wait(dev)
#endif
static void arcnet_continue_tx(struct device *dev);
static void arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,
static int arcnetA_send_packet(struct sk_buff *skb, struct device *dev);
static void arcnetA_continue_tx(struct device *dev);
static void arcnetA_prepare_tx(struct device *dev,struct ClientData *hdr,
short length,char *data);
static void arcnet_go_tx(struct device *dev);
static void arcnetA_go_tx(struct device *dev);
static int arcnetW_send_packet(struct sk_buff *skb, struct device *dev);
static void arcnet_interrupt(int irq,struct pt_regs *regs);
static void arcnet_inthandler(struct device *dev);
static void arcnet_rx(struct device *dev,int recbuf);
#ifdef USE_TIMER_HANDLER
static void arcnet_timer(unsigned long arg);
#endif
static void arcnet_rx(struct device *dev,int recbuf);
static void arcnetA_rx(struct device *dev,struct ClientData *arcsoft,
int length,u_char saddr, u_char daddr);
static void arcnetW_rx(struct device *dev,u_char *arcsoft,
int length,u_char saddr, u_char daddr);
static struct enet_statistics *arcnet_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
/* annoying functions for header/arp/etc building */
int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
int arcnetA_header(struct sk_buff *skb,struct device *dev,unsigned short type,
void *daddr,void *saddr,unsigned len);
int arc_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
int arcnetA_rebuild_header(void *eth,struct device *dev,unsigned long raddr,
struct sk_buff *skb);
unsigned short arc_type_trans(struct sk_buff *skb,struct device *dev);
static int arcnet_reset(struct device *dev);
unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev);
#ifdef MODULE
int init_module(void);
......@@ -398,19 +466,17 @@ void cleanup_module(void);
#define tx_done(dev) 1
/*
#define JIFFER(time) for (delayval=jiffies+(time); delayval>jiffies;);
*/
#define JIFFER(time) for (delayval=0; delayval<(time*10); delayval++) \
udelay(1000);
#ifdef EXTRA_DELAYS
#define XJIFFER(time) JIFFER(time)
#else
#define XJIFFER(time)
#endif
/****************************************************************************
* *
* Probe and initialization *
* *
****************************************************************************/
/* Check for a network adaptor of this type, and return '0' if one exists.
* If dev->base_addr == 0, probe all likely locations.
* If dev->base_addr == 1, always return failure.
......@@ -450,14 +516,14 @@ arcnet_probe(struct device *dev)
int delayval;
struct arcnet_local *lp;
if (net_debug)
BUGLVL(D_NORMAL)
{
printk(version);
printk("arcnet: ***\n");
printk("arcnet: * Read linux/drivers/net/README.arcnet for important release notes!\n");
printk("arcnet: *\n");
printk("arcnet: * This version should be stable, but e-mail me if you have any\n");
printk("arcnet: * questions, comments, or bug reports!\n");
printk("arcnet: * This is an ALPHA version! (Last stable release: v1.02) E-mail me if\n");
printk("arcnet: * you have any questions, comments, or bug reports.\n");
printk("arcnet: ***\n");
}
......@@ -473,7 +539,7 @@ arcnet_probe(struct device *dev)
else for (port = &ports[0]; *port; port++)
{
int ioaddr = *port;
if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE))
if (check_region(ioaddr, ARCNET_TOTAL_SIZE))
{
BUGLVL(D_INIT)
printk("arcnet: Skipping %Xh because of check_region...\n",
......@@ -534,7 +600,7 @@ arcnet_probe(struct device *dev)
}
/* Grab the region so we can find another board if autoIRQ fails. */
request_region(dev->base_addr, ETHERCARD_TOTAL_SIZE,"arcnet");
request_region(dev->base_addr, ARCNET_TOTAL_SIZE,"arcnet");
printk("%s: ARCnet card found at %03lXh, IRQ %d, ShMem at %lXh.\n",
dev->name, dev->base_addr, dev->irq, dev->mem_start);
......@@ -544,27 +610,26 @@ arcnet_probe(struct device *dev)
memset(dev->priv, 0, sizeof(struct arcnet_local));
lp=(struct arcnet_local *)(dev->priv);
dev->open = arcnet_open;
dev->stop = arcnet_close;
dev->hard_start_xmit = arcnet_send_packet;
dev->get_stats = arcnet_get_stats;
dev->open=arcnet_open;
dev->stop=arcnet_close;
dev->hard_start_xmit=arcnetA_send_packet;
dev->get_stats=arcnet_get_stats;
#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
#endif
/* Fill in the fields of the device structure with ethernet-generic values. */
/* Fill in the fields of the device structure with ethernet-generic
* values.
*/
ether_setup(dev);
/* And now fill particular ones with arcnet values :) */
/* And now fill particular fields with arcnet values */
dev->type=ARPHRD_ARCNET;
dev->hard_header_len=sizeof(struct ClientData);
BUGLVL(D_EXTRA)
BUGLVL(D_DURING)
printk("arcnet: ClientData header size is %d.\narcnet: HardHeader size is %d.\n",
sizeof(struct ClientData),sizeof(struct HardHeader));
#if LIMIT_MTU /* the old way - normally, now use ethernet default */
dev->mtu=512-sizeof(struct HardHeader)+EXTRA_CLIENTDATA;
#endif
/* since we strip EXTRA_CLIENTDATA bytes off before sending,
* we let Linux add that many bytes to the packet data...
*/
......@@ -585,8 +650,8 @@ arcnet_probe(struct device *dev)
lp->sequence=1;
lp->recbuf=0;
dev->hard_header = arc_header;
dev->rebuild_header = arc_rebuild_header;
dev->hard_header=arcnetA_header;
dev->rebuild_header=arcnetA_rebuild_header;
return 0;
}
......@@ -598,10 +663,10 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
int delayval,airq;
BUGLVL(D_INIT)
{
printk("arcnet: probing address %Xh\n",ioaddr);
BUGLVL(D_INIT)
printk("arcnet: status1=%Xh\n",inb(STATUS));
}
/* very simple - all we have to do is reset the card, and if there's
......@@ -621,6 +686,7 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
return ENODEV;
}
#if 0
/* we'll try to be reasonably sure it's an arcnet by making sure
* the value of the COMMAND port changes automatically once in a
* while. I have no idea what those values ARE, but at least
......@@ -641,13 +707,13 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
return ENODEV;
}
}
#endif
BUGLVL(D_INIT)
printk("arcnet: status2=%Xh\n",inb(STATUS));
/* now we turn the reset bit off so we can IRQ next reset... */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
XJIFFER(ACKtime);
if (inb(STATUS) & RESETflag) /* reset flag STILL on */
{
BUGLVL(D_INIT)
......@@ -659,32 +725,6 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
/* set up automatic IRQ detection */
autoirq_setup(0);
/* enable reset IRQ's (shouldn't be necessary, but worth a try) */
outb(RESETflag,INTMASK);
/* now reset it again to generate an IRQ */
inb(RESET);
JIFFER(RESETtime);
BUGLVL(D_INIT)
printk("arcnet: status3=%Xh\n",inb(STATUS));
/* and turn the reset flag back off */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
XJIFFER(ACKtime);
BUGLVL(D_INIT)
printk("arcnet: status4=%Xh\n",inb(STATUS));
/* enable reset IRQ's again */
outb(RESETflag,INTMASK);
/* now reset it again to generate an IRQ */
inb(RESET);
JIFFER(RESETtime);
BUGLVL(D_INIT)
printk("arcnet: status5=%Xh\n",inb(STATUS));
/* if we do this, we're sure to get an IRQ since the card has
* just reset and the NORXflag is on until we tell it to start
......@@ -693,18 +733,15 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
* However, this could, theoretically, cause a lockup. Maybe I'm just
* not very good at theory! :)
*/
#ifdef DANGER_PROBE
outb(NORXflag,INTMASK);
JIFFER(RESETtime);
outb(0,INTMASK);
#endif
/* and turn the reset flag back off */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
XJIFFER(ACKtime);
airq = autoirq_report(0);
if (net_debug>=D_INIT && airq)
BUGLVL(D_INIT) if (airq)
printk("arcnet: autoirq is %d\n", airq);
/* if there was no autoirq AND the user hasn't set any defaults,
......@@ -723,7 +760,6 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
{
/* now we turn the reset bit off */
outb(CFLAGScmd|RESETclear|CONFIGclear,COMMAND);
XJIFFER(ACKtime);
}
if (inb(STATUS) & RESETflag) /* reset flag STILL on */
......@@ -744,7 +780,7 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
}
else if (dev->irq == 2)
{
if (net_debug)
BUGLVL(D_NORMAL)
printk("arcnet: IRQ2 == IRQ9, don't worry.\n");
dev->irq = 9;
}
......@@ -758,7 +794,7 @@ int arcnet_ioprobe(struct device *dev, short ioaddr)
/* A memory probe that is called after the card is reset.
* It checks for the official TESTvalue in byte 0 and makes sure the buffer
* has certain characteristics of an ARCnet...
* has certain characteristics of an ARCnet.
*/
int arcnet_memprobe(struct device *dev,u_char *addr)
{
......@@ -767,7 +803,6 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
dev->mem_start=0;
#ifdef STRICT_MEM_DETECT /* probably better. */
/* ARCnet memory byte 0 is TESTvalue */
if (addr[0]!=TESTvalue)
{
......@@ -786,15 +821,6 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
(unsigned long)addr,addr[0]);
return ENODEV;
}
#else
if (addr[0]!=TESTvalue)
{
BUGLVL(D_INIT)
printk("arcnet: probe failed. addr=%lXh, addr[0]=%Xh (not %Xh)\n",
(unsigned long)addr,addr[0],TESTvalue);
return ENODEV;
}
#endif
/* got it! fill in dev */
dev->mem_start=(unsigned long)addr;
......@@ -807,64 +833,136 @@ int arcnet_memprobe(struct device *dev,u_char *addr)
#endif /* MODULE */
/* Open/initialize the board. This is called (in the current kernel)
sometime after booting when the 'ifconfig' program is run.
This routine should set everything up anew at each open, even
registers that "should" only need to be set once at boot, so that
there is non-reboot way to recover if something goes wrong.
int arcnet_reset(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int delayval,recbuf=lp->recbuf;
u_char *cardmem;
outb(0,INTMASK); /* no IRQ's, please! */
BUGLVL(D_INIT)
printk("arcnet: Resetting %s (status=%Xh)\n",
dev->name,inb(STATUS));
inb(RESET); /* Reset by reading this port */
JIFFER(RESETtime);
outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
outb(CFLAGScmd|CONFIGclear,COMMAND);
/* after a reset, the first byte of shared mem is TESTvalue and the
* second byte is our 8-bit ARCnet address.
*/
cardmem = (u_char *) dev->mem_start;
if (cardmem[0] != TESTvalue)
{
BUGLVL(D_INIT)
printk("arcnet: reset failed: TESTvalue not present.\n");
return 1;
}
lp->arcnum=cardmem[1]; /* save address for later use */
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
/* enable extended (512-byte) packets */
outb(CONFIGcmd|EXTconf,COMMAND);
/* clean out all the memory to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)dev->mem_start,0x42,2048);
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
/* re-enable interrupts */
outb(NORXflag|RECON_flag,INTMASK);
/* done! return success. */
return 0;
}
static int arcnetW_init(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
ether_setup(lp->wdev);
dev->dev_addr[0]=0;
dev->dev_addr[5]=lp->arcnum;
dev->mtu=493; /* MTU is small because of missing packet splitting */
lp->wdev->open=NULL;
lp->wdev->stop=NULL;
lp->wdev->hard_start_xmit=arcnetW_send_packet;
BUGLVL(D_EXTRA)
printk("%s: ARCnet \"Windows\" protocol initialized.\n",
lp->wdev->name);
return 0;
}
/****************************************************************************
* *
* Open and close the driver *
* *
****************************************************************************/
/* Open/initialize the board. This is called sometime after booting when
* the 'ifconfig' program is run.
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
* there is non-reboot way to recover if something goes wrong.
*/
static int
arcnet_open(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
/* int ioaddr = dev->base_addr;*/
if (dev->metric>=10)
if (dev->metric>=1000)
{
net_debug=dev->metric-10;
arcnet_debug=dev->metric-1000;
printk("arcnet: debug level set to %d\n",arcnet_debug);
dev->metric=1;
}
if (net_debug) printk(version);
#if 0 /* Yup, they're hardwired in arcnets */
/* This is used if the interrupt line can turned off (shared).
See 3c503.c for an example of selecting the IRQ at config-time. */
if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet")) {
return -EAGAIN;
}
#endif
BUGLVL(D_NORMAL) printk(version);
irq2dev_map[dev->irq] = dev;
/* Reset the hardware here. */
BUGLVL(D_EXTRA) printk("arcnet: arcnet_open: resetting card.\n");
/* try to reset - twice if it fails the first time */
if (arcnet_reset(dev) && arcnet_reset(dev))
return -ENODEV;
/* chipset_init(dev, 1);*/
/* outb(0x00, ioaddr);*/
/* lp->open_time = jiffies;*/
dev->tbusy=0;
dev->interrupt=0;
dev->start=1;
lp->intx=0;
lp->in_txhandler=0;
#ifdef USE_TIMER_HANDLER
/* grab a timer handler to recover from any missed IRQ's */
init_timer(&lp->timer);
lp->timer.expires = TIMERval; /* length of time */
lp->timer.data = (unsigned long)dev; /* pointer to "dev" structure */
lp->timer.function = &arcnet_timer; /* timer handler */
add_timer(&lp->timer);
#endif
/* The RFC1201 driver is the default - just store */
lp->adev=dev;
BUGLVL(D_EXTRA)
printk("%s: ARCnet RFC1201 protocol initialized.\n",
lp->adev->name);
/* Initialize the Windows protocol driver */
lp->wdev=(struct device *)kmalloc(sizeof(struct device),GFP_KERNEL);
memcpy(lp->wdev,dev,sizeof(struct device));
lp->wdev->name=(char *)kmalloc(10,GFP_KERNEL);
sprintf(lp->wdev->name,"%sw",dev->name);
lp->wdev->init=arcnetW_init;
register_netdev(lp->wdev);
/* we're started */
START=1;
#ifdef MODULE
MOD_INC_USE_COUNT;
......@@ -874,33 +972,34 @@ arcnet_open(struct device *dev)
}
/* The inverse routine to arcnet_open(). */
/* The inverse routine to arcnet_open - shuts down the card.
*/
static int
arcnet_close(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr = dev->base_addr;
#ifdef EXTRA_DELAYS
int delayval;
#endif
/* lp->open_time = 0;*/
dev->tbusy = 1;
dev->start = 0;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
/* release the timer */
del_timer(&lp->timer);
TBUSY=1;
START=0;
/* Flush the Tx and disable Rx here. */
/* resetting the card should do the job. */
/*inb(RESET);*/
outb(0,INTMASK); /* no IRQ's */
outb(NOTXcmd,COMMAND); /* disable transmit */
XJIFFER(ACKtime);
outb(NORXcmd,COMMAND); /* disable receive */
/* do NOT free lp->adev!! It's static! */
lp->adev=NULL;
/* free the Windows protocol device */
lp->wdev->start=0;
lp->wdev->priv=NULL;
unregister_netdev(lp->wdev);
kfree(lp->wdev->name);
kfree(lp->wdev);
lp->wdev=NULL;
/* Update the statistics here. */
#ifdef MODULE
......@@ -911,12 +1010,21 @@ arcnet_close(struct device *dev)
}
/****************************************************************************
* *
* Transmitter routines *
* *
****************************************************************************/
/* Called by the kernel in order to transmit a packet.
*/
static int
arcnet_send_packet(struct sk_buff *skb, struct device *dev)
arcnetA_send_packet(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
/* short daddr;*/
lp->intx++;
......@@ -924,7 +1032,14 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
printk("arcnet: transmit requested (status=%Xh, inTX=%d)\n",
inb(STATUS),lp->intx);
if (dev->tbusy || lp->in_txhandler)
if (lp->in_txhandler)
{
printk("arcnet: send_packet called while in txhandler!\n");
lp->intx--;
return 1;
}
if (IF_TBUSY)
{
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
......@@ -932,18 +1047,6 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
int recbuf=lp->recbuf;
int status=inb(STATUS);
/* resume any stopped tx's */
#if 0
if (lp->txready && (inb(STATUS)&TXFREEflag))
{
printk("arcnet: kickme: starting a TX (status=%Xh)\n",
inb(STATUS));
arcnet_go_tx(dev);
lp->intx--;
return 1;
}
#endif
if (tickssofar < 5)
{
BUGLVL(D_DURING)
......@@ -955,27 +1058,36 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
return 1;
}
BUGLVL(D_INIT)
printk("arcnet: transmit timed out (status=%Xh, inTX=%d, tickssofar=%d)\n",
status,lp->intx,tickssofar);
BUGLVL(D_EXTRA)
printk("arcnet: transmit timed out (status=%Xh, inTX=%d, inTXh=%d, tickssofar=%d)\n",
status,lp->intx,lp->in_txhandler,tickssofar);
lp->stats.tx_errors++;
/* Try to restart the adaptor. */
/*arcnet_reset(dev);*/
outb(0,INTMASK);
if (status&NORXflag) EnableReceiver();
if (!(status&TXFREEflag)) outb(NOTXcmd,COMMAND);
dev->trans_start = jiffies;
if (lp->outgoing.skb)
{
dev_kfree_skb(lp->outgoing.skb,FREE_WRITE);
lp->stats.tx_dropped++;
}
lp->outgoing.skb=NULL;
dev->tbusy=0;
mark_bh(NET_BH);
lp->intx=0;
lp->in_txhandler=0;
TBUSY=0;
lp->intx--;
/*lp->intx=0;*/
/*lp->in_txhandler=0;*/
lp->txready=0;
lp->sending=0;
mark_bh(NET_BH);
outb(NORXflag|RECON_flag,INTMASK);
return 1;
}
......@@ -984,7 +1096,7 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL) {
BUGLVL(D_INIT)
BUGLVL(D_NORMAL)
printk("arcnet: tx passed null skb (status=%Xh, inTX=%d, tickssofar=%ld)\n",
inb(STATUS),lp->intx,jiffies-dev->trans_start);
dev_tint(dev);
......@@ -994,9 +1106,16 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
if (lp->txready) /* transmit already in progress! */
{
printk("arcnet: trying to start new packet while busy!\n");
printk("arcnet: marking as not ready.\n");
lp->txready=0;
printk("arcnet: trying to start new packet while busy! (status=%Xh)\n",
inb(STATUS));
/*printk("arcnet: marking as not ready.\n");*/
outb(0,INTMASK);
outb(NOTXcmd,COMMAND); /* abort current send */
arcnet_inthandler(dev); /* fake an interrupt */
lp->stats.tx_errors++;
lp->intx--;
lp->txready=0; /* we definitely need this line! */
return 1;
}
......@@ -1011,10 +1130,15 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
}
else {
struct Outgoing *out=&(lp->outgoing);
out->length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
TBUSY=1;
out->length = 1 < skb->len ? skb->len : 1;
out->hdr=(struct ClientData*)skb->data;
out->skb=skb;
BUGLVL( D_DATA ) {
BUGLVL(D_SKB)
{
short i;
for( i=0; i< skb->len; i++)
{
......@@ -1024,25 +1148,25 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
printk("\n");
}
#ifdef IRQ_XMIT
if (lp->txready && inb(STATUS)&TXFREEflag)
arcnet_go_tx(dev);
#endif
out->hdr->sequence=(lp->sequence++);
if (lp->txready && inb(STATUS)&TXFREEflag)
arcnetA_go_tx(dev);
if (out->length<=XMTU) /* fits in one packet? */
/* fits in one packet? */
if (out->length-EXTRA_CLIENTDATA<=XMTU)
{
BUGLVL(D_TX) printk("arcnet: not splitting %d-byte packet. (split_flag=%d)\n",
BUGLVL(D_DURING)
printk("arcnet: not splitting %d-byte packet. (split_flag=%d)\n",
out->length,out->hdr->split_flag);
BUGLVL(D_INIT) if (out->hdr->split_flag)
BUGLVL(D_EXTRA) if (out->hdr->split_flag)
printk("arcnet: short packet has split_flag set?! (split_flag=%d)\n",
out->hdr->split_flag);
out->numsegs=1;
out->segnum=1;
arcnet_prepare_tx(dev,out->hdr,
arcnetA_prepare_tx(dev,out->hdr,
out->length-sizeof(struct ClientData),
((char *)skb->data)+sizeof(struct ClientData));
careful_xmit_wait(dev);
/* done right away */
dev_kfree_skb(out->skb,FREE_WRITE);
......@@ -1050,16 +1174,16 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
if (!lp->sending)
{
arcnet_go_tx(dev);
arcnetA_go_tx(dev);
/* inform upper layers */
dev->tbusy=0;
TBUSY=0;
mark_bh(NET_BH);
}
}
else /* too big for one - split it */
{
int maxsegsize=XMTU-sizeof(struct ClientData);
int maxsegsize=XMTU-4;
out->data=(u_char *)skb->data
+ sizeof(struct ClientData);
......@@ -1071,23 +1195,22 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
BUGLVL(D_TX) printk("arcnet: packet (%d bytes) split into %d fragments:\n",
out->length,out->numsegs);
#ifdef IRQ_XMIT
/* if a packet waiting, launch it */
if (lp->txready && inb(STATUS)&TXFREEflag)
arcnet_go_tx(dev);
arcnetA_go_tx(dev);
if (!lp->txready)
{
/* prepare a packet, launch it and prepare
* another.
*/
arcnet_continue_tx(dev);
arcnetA_continue_tx(dev);
if (!lp->sending)
{
arcnet_go_tx(dev);
arcnet_continue_tx(dev);
arcnetA_go_tx(dev);
arcnetA_continue_tx(dev);
if (!lp->sending)
arcnet_go_tx(dev);
arcnetA_go_tx(dev);
}
}
......@@ -1101,29 +1224,7 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
if (out->skb)
dev_kfree_skb(out->skb,FREE_WRITE);
out->skb=NULL;
#if 0
/* inform upper layers */
dev->tbusy=0;
mark_bh(NET_BH);
#endif
}
#else /* non-irq xmit */
while (out->segnum<out->numsegs)
{
arcnet_continue_tx(dev);
careful_xmit_wait(dev);
arcnet_go_tx(dev);
dev->trans_start=jiffies;
}
dev_kfree_skb(out->skb,FREE_WRITE);
out->skb=NULL;
/* inform upper layers */
dev->tbusy = 0;
mark_bh(NET_BH);
#endif
}
}
......@@ -1133,10 +1234,15 @@ arcnet_send_packet(struct sk_buff *skb, struct device *dev)
return 0;
}
static void arcnet_continue_tx(struct device *dev)
/* After an RFC1201 split packet has been set up, this function calls
* arcnetA_prepare_tx to load the next segment into the card. This function
* does NOT automatically call arcnetA_go_tx to allow for easier double-
* buffering.
*/
static void arcnetA_continue_tx(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int maxsegsize=XMTU-sizeof(struct ClientData);
int maxsegsize=XMTU-4;
struct Outgoing *out=&(lp->outgoing);
if (lp->txready)
......@@ -1163,57 +1269,35 @@ static void arcnet_continue_tx(struct device *dev)
out->segnum+1,out->seglen,out->numsegs,
out->length,out->hdr->split_flag);
arcnet_prepare_tx(dev,out->hdr,out->seglen,out->data);
arcnetA_prepare_tx(dev,out->hdr,out->seglen,out->data);
out->dataleft-=out->seglen;
out->data+=out->seglen;
out->segnum++;
}
#ifdef CAREFUL_XMIT
static void careful_xmit_wait(struct device *dev)
/* Given an skb, copy a packet into the ARCnet buffers for later transmission
* by arcnetA_go_tx.
*/
static void
arcnetA_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
char *data)
{
int ioaddr=dev->base_addr;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
/* wait patiently for tx to become available again */
while ( !(inb(STATUS)&TXFREEflag) )
{
if (jiffies-dev->trans_start > 20 || !dev->tbusy)
{
BUGLVL(D_INIT)
printk("arcnet: CAREFUL_XMIT timeout. (busy=%d, status=%Xh)\n",
dev->tbusy,inb(STATUS));
lp->stats.tx_errors++;
outb(NOTXcmd,COMMAND);
return;
}
}
BUGLVL(D_TX) printk("arcnet: transmit completed successfully. (status=%Xh)\n",
inb(STATUS));
}
#endif
static void
arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
char *data)
{
/* int ioaddr = dev->base_addr;*/
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct ClientData *arcsoft;
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
u_char pkttype;
int offset;
short daddr;
struct ClientData *arcsoft;
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
u_char pkttype;
int offset;
short daddr;
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate between 2 and 3 */
length+=sizeof(struct ClientData);
length+=4;
BUGLVL(D_TX)
printk("arcnet: arcnet_prep_tx: hdr:%ph, length:%d, data:%ph\n",
printk("arcnet: arcnetA_prep_tx: hdr:%ph, length:%d, data:%ph\n",
hdr,length,data);
/* clean out the page to make debugging make more sense :) */
......@@ -1227,8 +1311,7 @@ arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
{
pkttype=NORMAL;
arcpacket->hardheader.offset1=offset=256-length
+ EXTRA_CLIENTDATA;
arcpacket->hardheader.offset1=offset=256-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
}
......@@ -1237,8 +1320,7 @@ arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
pkttype=EXTENDED;
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length
+ EXTRA_CLIENTDATA;
arcpacket->hardheader.offset2=offset=512-length;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
}
......@@ -1247,8 +1329,7 @@ arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
pkttype=EXCEPTION;
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset=512-length-4
+ EXTRA_CLIENTDATA;
arcpacket->hardheader.offset2=offset=512-length-4;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset+4-EXTRA_CLIENTDATA]);
......@@ -1267,11 +1348,9 @@ arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
* - the first bytes of ClientData header are skipped
*/
memcpy((u_char*)arcsoft+EXTRA_CLIENTDATA,
(u_char*)hdr+EXTRA_CLIENTDATA,
sizeof(struct ClientData)-EXTRA_CLIENTDATA);
(u_char*)hdr+EXTRA_CLIENTDATA,4);
memcpy((u_char*)arcsoft+sizeof(struct ClientData),
data,
length-sizeof(struct ClientData));
data,length-4);
BUGLVL(D_DURING) printk("arcnet: transmitting packet to station %02Xh (%d bytes, type=%d)\n",
daddr,length,pkttype);
......@@ -1292,35 +1371,18 @@ arcnet_prepare_tx(struct device *dev,struct ClientData *hdr,short length,
printk("\n");
}
#ifdef CAREFUL_XMIT
#if 0
careful_xmit_wait(dev);
/* if we're not broadcasting, make sure the xmit was ack'd.
* if it wasn't, there is probably no card with that
* address... or else it missed our tx somehow.
*/
if (daddr && !(inb(STATUS)&TXACKflag))
{
BUGLVL(D_INIT)
printk("arcnet: transmit not acknowledged. (status=%Xh, daddr=%02Xh)\n",
inb(STATUS),daddr);
lp->stats.tx_errors++;
return -ENONET; /* "machine is not on the network" */
}
#endif
#ifdef VERIFY_ACK
lp->outgoing.lastload_dest=hdr->daddr;
#endif
lp->txready=lp->txbuf; /* packet is ready for sending */
#if 0
#ifdef IRQ_XMIT
if (inb(STATUS)&TXFREEflag) arcnet_go_tx(dev);
#endif
#endif
}
/* Actually start transmitting a packet that was placed in the card's
* buffer by arcnetA_prepare_tx.
*/
static void
arcnet_go_tx(struct device *dev)
arcnetA_go_tx(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
int ioaddr=dev->base_addr;
......@@ -1334,25 +1396,176 @@ arcnet_go_tx(struct device *dev)
/* start sending */
outb(TXcmd|(lp->txready<<3),COMMAND);
#ifdef IRQ_XMIT
outb(TXFREEflag|NORXflag,INTMASK);
#endif
outb(TXFREEflag|NORXflag|RECON_flag,INTMASK);
dev->trans_start = jiffies;
lp->txready=0;
lp->sending++;
#ifdef VERIFY_ACK
lp->outgoing.lasttrans_dest=lp->outgoing.lastload_dest;
lp->outgoing.lastload_dest=0;
#endif
}
/* The typical workload of the driver:
Handle the network interface interrupts. */
/* Called by the kernel in order to transmit a "Windows" packet.
*/
static int
arcnetW_send_packet(struct sk_buff *skb, struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
BUGLVL(D_DURING)
printk("%s: in arcnetW_send_packet (skb=%p)\n",dev->name,skb);
if (IF_TBUSY)
{
/* If we get here, some higher level has decided we are broken.
There should really be a "kick me" function call instead. */
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10)
return 1;
printk("%s: transmit timed out\n",dev->name);
/* Try to restart the adaptor. */
TBUSY=0;
dev->trans_start = jiffies;
return 0;
}
/* If some higher layer thinks we've missed an tx-done interrupt
we are passed NULL. Caution: dev_tint() handles the cli()/sti()
itself. */
if (skb == NULL)
{
dev_tint(dev);
return 0;
}
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
{
union ArcPacket *arcpacket =
(union ArcPacket *)(dev->mem_start+512*(lp->txbuf^1));
u_char *arcsoft,daddr;
short offset,length=skb->len+1;
TBUSY=1;
if (length>XMTU)
{
printk("arcnet: MTU for %s and %s must be <= 493 for Windows protocol.\n",
lp->adev->name,lp->wdev->name);
printk("arcnet: transmit aborted.\n");
dev_kfree_skb(skb,FREE_WRITE);
return 0;
}
BUGLVL(D_DURING)
printk("arcnet: starting tx sequence...\n");
lp->txbuf=lp->txbuf^1; /* XOR with 1 to alternate btw 2 & 3 */
/* clean out the page to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)dev->mem_start+lp->txbuf*512,0x42,512);
/* broadcasts have address FF:FF:FF:FF:FF:FF in etherspeak */
if (((struct ethhdr*)(skb->data))->h_dest[0] == 0xFF)
daddr=arcpacket->hardheader.destination=0;
else
daddr=arcpacket->hardheader.destination=
((struct ethhdr*)(skb->data))->h_dest[5];
/* load packet into shared memory */
offset=512-length;
if (length>MTU) /* long/exception packet */
{
if (length<MinTU) offset-=3;
arcpacket->hardheader.offset1=0;
arcpacket->hardheader.offset2=offset;
}
else /* short packet */
{
arcpacket->hardheader.offset1=(offset-=256);
}
BUGLVL(D_DURING)
printk("arcnet: length=%Xh, offset=%Xh, offset1=%Xh, offset2=%Xh\n",
length,offset,arcpacket->hardheader.offset1,
arcpacket->hardheader.offset2);
arcsoft=&arcpacket->raw[offset];
arcsoft[0]=ARC_P_MS_TCPIP;
arcsoft++;
/* copy the packet into ARCnet shmem
* - the first bytes of ClientData header are skipped
*/
BUGLVL(D_DURING) printk("arcnet: ready to memcpy\n");
memcpy(arcsoft,skb->data,skb->len);
BUGLVL(D_DURING)
printk("arcnet: transmitting packet to station %02Xh (%d bytes)\n",
daddr,length);
BUGLVL(D_TX)
{
int countx,county;
printk("arcnet: packet dump [tx] follows:");
for (county=0; county<16+(length>=240)*16; county++)
{
printk("\n[%04X] ",county*16);
for (countx=0; countx<16; countx++)
printk("%02X ",
arcpacket->raw[county*16+countx]);
}
printk("\n");
}
#ifdef VERIFY_ACK
lp->outgoing.lastload_dest=daddr;
#endif
lp->txready=lp->txbuf; /* packet is ready for sending */
arcnetA_go_tx(dev);
dev->trans_start = jiffies;
}
dev_kfree_skb(skb,FREE_WRITE);
return 0;
}
/****************************************************************************
* *
* Interrupt handler *
* *
****************************************************************************/
/* The typical workload of the driver: Handle the network interface
* interrupts. This doesn't do much right now except call arcnet_inthandler,
* which takes different parameters but is sometimes called from other places
* as well.
*/
static void
arcnet_interrupt(int irq,struct pt_regs *regs)
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
if (dev == NULL) {
if (net_debug >= D_DURING)
if (dev==NULL || !dev->start)
{
BUGLVL(D_EXTRA)
printk("arcnet: irq %d for unknown device.\n", irq);
return;
}
......@@ -1360,21 +1573,26 @@ arcnet_interrupt(int irq,struct pt_regs *regs)
arcnet_inthandler(dev);
}
/* The actual interrupt handler routine - handle various IRQ's generated
* by the card.
*/
static void
arcnet_inthandler(struct device *dev)
{
struct arcnet_local *lp;
int ioaddr, status, boguscount = 3, didsomething;
if (dev->interrupt)
printk("arcnet: DRIVER PROBLEM! Nested arcnet interrupts!\n");
dev->interrupt = 1;
sti();
ioaddr = dev->base_addr;
lp = (struct arcnet_local *)dev->priv;
#ifdef IRQ_XMIT
outb(0,INTMASK);
#endif
sti();
BUGLVL(D_DURING)
printk("arcnet: in net_interrupt (status=%Xh)\n",inb(STATUS));
......@@ -1386,13 +1604,12 @@ arcnet_inthandler(struct device *dev)
if (!dev->start)
{
BUGLVL(D_EXTRA)
BUGLVL(D_DURING)
printk("arcnet: ARCnet not yet initialized. irq ignored. (status=%Xh)\n",
status);
#ifdef IRQ_XMIT
if (!(status&NORXflag))
outb(NORXflag,INTMASK);
#endif
outb(NORXflag|RECON_flag,INTMASK);
dev->interrupt=0;
return;
}
......@@ -1402,14 +1619,22 @@ arcnet_inthandler(struct device *dev)
*/
if (status & RESETflag)
{
outb(CFLAGScmd|RESETclear,COMMAND);
BUGLVL(D_INIT)
printk("arcnet: reset irq (status=%Xh)\n",
status);
dev->interrupt=0;
return;
}
#ifdef DETECT_RECONFIGS
if (status & RECONflag)
{
outb(CFLAGScmd|CONFIGclear,COMMAND);
BUGLVL(D_EXTRA)
printk("arcnet: Network reconfiguration detected (status=%Xh)\n",
status);
lp->stats.tx_carrier_errors++;
}
#endif
#if 1 /* yes, it's silly to disable this part but it makes good testing */
/* RX is inhibited - we must have received something. */
if (status & NORXflag)
{
......@@ -1427,8 +1652,7 @@ arcnet_inthandler(struct device *dev)
didsomething++;
}
#endif
#ifdef IRQ_XMIT
/* it can only be an xmit-done irq if we're xmitting :) */
if (status&TXFREEflag && !lp->in_txhandler && lp->sending)
{
......@@ -1441,10 +1665,31 @@ arcnet_inthandler(struct device *dev)
printk("arcnet: TX IRQ (stat=%Xh, numsegs=%d, segnum=%d, skb=%ph)\n",
status,out->numsegs,out->segnum,out->skb);
#ifdef VERIFY_ACK
if (!(status&TXACKflag))
{
if (lp->outgoing.lasttrans_dest != 0)
{
BUGLVL(D_NORMAL)
printk("arcnet: transmit was not acknowledged! (status=%Xh, dest=%d)\n",
status,
lp->outgoing.lasttrans_dest);
lp->stats.tx_errors++;
}
else
{
BUGLVL(D_DURING)
printk("arcnet: broadcast was not acknowledged; that's normal (status=%Xh, dest=%d)\n",
status,
lp->outgoing.lasttrans_dest);
}
}
#endif
/* send packet if there is one */
if (lp->txready)
{
arcnet_go_tx(dev);
arcnetA_go_tx(dev);
didsomething++;
}
......@@ -1460,9 +1705,9 @@ arcnet_inthandler(struct device *dev)
printk("arcnet: TX IRQ done: no split to continue.\n");
/* inform upper layers */
if (!lp->txready && dev->tbusy)
if (!lp->txready && IF_TBUSY)
{
dev->tbusy=0;
TBUSY=0;
mark_bh(NET_BH);
}
......@@ -1476,9 +1721,9 @@ arcnet_inthandler(struct device *dev)
* are done, then continue xmit.
*/
if (out->segnum<out->numsegs)
arcnet_continue_tx(dev);
arcnetA_continue_tx(dev);
if (lp->txready && !lp->sending)
arcnet_go_tx(dev);
arcnetA_go_tx(dev);
/* if segnum==numsegs, the transmission is finished;
* free the skb.
......@@ -1492,9 +1737,9 @@ arcnet_inthandler(struct device *dev)
out->skb=NULL;
/* inform upper layers */
if (!lp->txready && dev->tbusy)
if (!lp->txready && IF_TBUSY)
{
dev->tbusy=0;
TBUSY=0;
mark_bh(NET_BH);
}
}
......@@ -1502,47 +1747,50 @@ arcnet_inthandler(struct device *dev)
lp->in_txhandler--;
}
#endif /* IRQ_XMIT */
} while (--boguscount && didsomething);
BUGLVL(D_DURING)
printk("arcnet: net_interrupt complete (status=%Xh)\n",
printk("arcnet: net_interrupt complete (status=%Xh)\n\n",
inb(STATUS));
#ifdef IRQ_XMIT
if (dev->start && lp->sending )
outb(NORXflag|TXFREEflag,INTMASK);
outb(NORXflag|TXFREEflag|RECON_flag,INTMASK);
else
outb(NORXflag,INTMASK);
#endif
outb(NORXflag|RECON_flag,INTMASK);
dev->interrupt=0;
}
/****************************************************************************
* *
* Receiver routines *
* *
****************************************************************************/
/* A packet has arrived; grab it from the buffers and possibly unsplit it.
* This is a generic packet receiver that calls arcnet??_rx depending on the
* protocol ID found.
*/
static void
arcnet_rx(struct device *dev,int recbuf)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
int ioaddr = dev->base_addr;
/* int status = inb(STATUS);*/
struct sk_buff *skb;
union ArcPacket *arcpacket=
(union ArcPacket *)(dev->mem_start+recbuf*512);
struct ClientData *soft,*arcsoft;
u_char *arcsoft;
short length,offset;
u_char pkttype,daddr,saddr;
u_char daddr,saddr;
daddr=arcpacket->hardheader.destination;
saddr=arcpacket->hardheader.source;
daddr=arcpacket->hardheader.destination;
/* if source is 0, it's not a "used" packet! */
/* if source is 0, it's a "used" packet! */
if (saddr==0)
{
/*BUGLVL(D_DURING)*/
printk("arcnet: discarding old packet. (status=%Xh)\n",
inb(STATUS));
lp->stats.rx_errors++;
......@@ -1553,30 +1801,91 @@ arcnet_rx(struct device *dev,int recbuf)
if (arcpacket->hardheader.offset1) /* Normal Packet */
{
offset=arcpacket->hardheader.offset1;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
length=256-offset+EXTRA_CLIENTDATA;
pkttype=NORMAL;
arcsoft=&arcpacket->raw[offset];
length=256-offset;
}
else /* ExtendedPacket or ExceptionPacket */
{
offset=arcpacket->hardheader.offset2;
arcsoft=(struct ClientData *)
(&arcpacket->raw[offset-EXTRA_CLIENTDATA]);
arcsoft=&arcpacket->raw[offset];
length=512-offset;
}
BUGLVL(D_DURING)
printk("arcnet: received packet from %02Xh to %02Xh (%d bytes)\n",
saddr,daddr,length);
/* call the right receiver for the protocol */
switch (arcsoft[0])
{
case ARC_P_IP:
case ARC_P_ARP:
case ARC_P_RARP:
case ARC_P_IPX:
arcnetA_rx(dev,(struct ClientData*)arcsoft,
length,saddr,daddr);
break;
case ARC_P_MS_TCPIP:
arcnetW_rx(dev,arcsoft,length,saddr,daddr);
break;
default:
printk("arcnet: received unknown protocol %d (%Xh)\n",
arcsoft[0],arcsoft[0]);
break;
}
if (arcsoft->split_flag!=0xFF) /* Extended Packet */
BUGLVL(D_RX)
{
length=512-offset+EXTRA_CLIENTDATA;
pkttype=EXTENDED;
int countx,county;
printk("arcnet: rx packet dump follows:");
for (county=0; county<16+(length>240)*16; county++)
{
printk("\n[%04X] ",county*16);
for (countx=0; countx<16; countx++)
printk("%02X ",
arcpacket->raw[county*16+countx]);
}
else /* Exception Packet */
printk("\n");
}
/* If any worth-while packets have been received, a mark_bh(NET_BH)
* has been done by netif_rx and Linux will handle them after we
* return.
*/
}
/* Packet receiver for "standard" RFC1201-style packets
*/
static void
arcnetA_rx(struct device *dev,struct ClientData *arcsoft,
int length,u_char saddr, u_char daddr)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
struct sk_buff *skb;
struct ClientData *soft;
BUGLVL(D_DURING)
printk("arcnet: it's an RFC1201 packet (length=%d)\n",
length);
arcsoft=(struct ClientData *)((u_char *)arcsoft-EXTRA_CLIENTDATA);
length+=EXTRA_CLIENTDATA;
if (arcsoft->split_flag==0xFF) /* Exception Packet */
{
BUGLVL(D_DURING)
printk("arcnet: compensating for exception packet\n");
/* skip over 4-byte junkola */
arcsoft=(struct ClientData *)
((u_char *)arcsoft + 4);
length=512-offset+EXTRA_CLIENTDATA-4;
pkttype=EXCEPTION;
}
length-=4;
}
if (!arcsoft->split_flag) /* not split */
......@@ -1588,24 +1897,26 @@ arcnet_rx(struct device *dev,int recbuf)
if (in->skb) /* already assembling one! */
{
BUGLVL(D_INIT) printk("arcnet: aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE);
lp->stats.tx_dropped++;
lp->stats.rx_errors++;
in->skb=NULL;
}
in->sequence=arcsoft->sequence;
skb = dev_alloc_skb(length);
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
printk("%s: Memory squeeze, dropping packet.\n",
dev->name);
printk("arcnet: Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
soft=(struct ClientData *)skb_put(skb,length);
soft=(struct ClientData *)skb->data;
skb->len = length;
skb->dev = dev;
memcpy((u_char *)soft+EXTRA_CLIENTDATA,
......@@ -1614,30 +1925,10 @@ arcnet_rx(struct device *dev,int recbuf)
soft->daddr=daddr;
soft->saddr=saddr;
BUGLVL(D_DURING)
printk("arcnet: received packet from %02Xh to %02Xh (%d bytes, type=%d)\n",
saddr,daddr,length,pkttype);
BUGLVL(D_RX)
{
int countx,county;
printk("arcnet: packet dump [rx-unsplit] follows:");
for (county=0; county<16+(pkttype!=NORMAL)*16; county++)
{
printk("\n[%04X] ",county*16);
for (countx=0; countx<16; countx++)
printk("%02X ",
arcpacket->raw[county*16+countx]);
}
printk("\n");
}
/* ARP packets have problems when sent from DOS.
* source address is always 0! So we take the hardware
* source addr (which is impossible to fumble) and insert
* it ourselves.
* source address is always 0 on some systems! So we take
* the hardware source addr (which is impossible to fumble)
* and insert it ourselves.
*/
if (soft->protocol_id == ARC_P_ARP)
{
......@@ -1651,7 +1942,7 @@ arcnet_rx(struct device *dev,int recbuf)
if (!*cptr) /* is saddr = 00? */
{
BUGLVL(D_DURING)
BUGLVL(D_EXTRA)
printk("arcnet: ARP source address was 00h, set to %02Xh.\n",
saddr);
*cptr=saddr;
......@@ -1666,9 +1957,23 @@ arcnet_rx(struct device *dev,int recbuf)
{
printk("arcnet: funny-shaped ARP packet. (%Xh, %Xh)\n",
arp->ar_hln,arp->ar_pln);
lp->stats.rx_frame_errors++;
}
}
BUGLVL(D_SKB)
{
short i;
for( i=0; i< skb->len; i++)
{
if( i%16 == 0 ) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]);
}
skb->protocol=arc_type_trans(skb,dev);
printk("\n");
}
skb->protocol=arcnetA_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
}
......@@ -1698,11 +2003,13 @@ arcnet_rx(struct device *dev,int recbuf)
if (in->skb && in->sequence!=arcsoft->sequence)
{
BUGLVL(D_INIT) printk("arcnet: wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: wrong seq number, aborting assembly (expected=%d, seq=%d, splitflag=%d)\n",
in->sequence,arcsoft->sequence,
arcsoft->split_flag);
kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL;
lp->stats.tx_dropped++;
lp->stats.rx_fifo_errors++;
in->lastpacket=in->numpackets=0;
}
......@@ -1712,9 +2019,11 @@ arcnet_rx(struct device *dev,int recbuf)
arcsoft->split_flag);
if (in->skb) /* already assembling one! */
{
BUGLVL(D_INIT) printk("arcnet: aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
lp->stats.tx_dropped++;
lp->stats.rx_over_errors++;
kfree_skb(in->skb,FREE_WRITE);
}
......@@ -1724,14 +2033,15 @@ arcnet_rx(struct device *dev,int recbuf)
if (in->numpackets>16)
{
printk("arcnet: incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: incoming packet more than 16 segments; dropping. (splitflag=%d)\n",
arcsoft->split_flag);
lp->stats.rx_dropped++;
return;
}
in->skb=skb=dev_alloc_skb(508*in->numpackets
+ sizeof(struct ClientData));
in->skb=skb=alloc_skb(508*in->numpackets
+ sizeof(struct ClientData),
GFP_ATOMIC);
if (skb == NULL) {
printk("%s: (split) memory squeeze, dropping packet.\n",
dev->name);
......@@ -1744,8 +2054,9 @@ arcnet_rx(struct device *dev,int recbuf)
*/
skb->free=1;
soft=(struct ClientData *)skb_put(skb,sizeof(struct ClientData));
soft=(struct ClientData *)skb->data;
skb->len=sizeof(struct ClientData);
skb->dev=dev;
memcpy((u_char *)soft+EXTRA_CLIENTDATA,
......@@ -1762,8 +2073,9 @@ arcnet_rx(struct device *dev,int recbuf)
*/
if (!in->skb)
{
BUGLVL(D_INIT) printk("arcnet: can't continue split without starting first! (splitflag=%d, seq=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: can't continue split without starting first! (splitflag=%d, seq=%d)\n",
arcsoft->split_flag,arcsoft->sequence);
lp->stats.rx_errors++;
return;
}
......@@ -1773,53 +2085,37 @@ arcnet_rx(struct device *dev,int recbuf)
/* harmless duplicate? ignore. */
if (packetnum<=in->lastpacket-1)
{
BUGLVL(D_INIT) printk("arcnet: duplicate splitpacket ignored! (splitflag=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: duplicate splitpacket ignored! (splitflag=%d)\n",
arcsoft->split_flag);
return;
}
/* "bad" duplicate, kill reassembly */
BUGLVL(D_INIT) printk("arcnet: out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
BUGLVL(D_EXTRA) printk("arcnet: out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n",
in->sequence,arcsoft->split_flag,
arcsoft->sequence);
kfree_skb(in->skb,FREE_WRITE);
in->skb=NULL;
lp->stats.tx_dropped++;
lp->stats.rx_fifo_errors++;
in->lastpacket=in->numpackets=0;
return;
}
soft=(struct ClientData *)skb->data;
soft=(struct ClientData *)in->skb->data;
}
skb=in->skb;
memcpy(skb_put(skb,length-sizeof(struct ClientData)),
memcpy(skb->data+skb->len,
(u_char *)arcsoft+sizeof(struct ClientData),
length-sizeof(struct ClientData));
skb->len+=length-sizeof(struct ClientData);
soft->daddr=daddr;
soft->saddr=saddr;
BUGLVL(D_DURING)
printk("arcnet: received packet from %02Xh to %02Xh (%d bytes, type=%d)\n",
saddr,daddr,length,pkttype);
BUGLVL(D_RX)
{
int countx,county;
printk("arcnet: packet dump [rx-split] follows:");
for (county=0; county<16+(pkttype!=NORMAL)*16; county++)
{
printk("\n[%04X] ",county*16);
for (countx=0; countx<16; countx++)
printk("%02X ",
arcpacket->raw[county*16+countx]);
}
printk("\n");
}
/* are we done? */
if (in->lastpacket == in->numpackets)
{
......@@ -1828,75 +2124,102 @@ arcnet_rx(struct device *dev,int recbuf)
skb,in->skb);
in->skb=NULL;
in->lastpacket=in->numpackets=0;
skb->protocol=arc_type_trans(skb,dev);
BUGLVL(D_SKB)
{
short i;
for( i=0; i< skb->len; i++)
{
if( i%16 == 0 ) printk("\n[%04hX] ",i);
printk("%02hX ",((unsigned char*)skb->data)[i]);
}
printk("\n");
}
skb->protocol=arcnetA_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
}
}
/* If any worth-while packets have been received, netif_rx()
has done a mark_bh(NET_BH) for us and will work on them
when we get to the bottom-half routine. */
}
#ifdef USE_TIMER_HANDLER
/* this function is called every once in a while to make sure the ARCnet
* isn't stuck.
*
* If we miss a receive IRQ, the receiver (and IRQ) is permanently disabled
* and we might never receive a packet again! This will check if this
* is the case, and if so, re-enable the receiver.
/* Packet receiver for non-standard Windows-style packets
*/
static void
arcnet_timer(unsigned long arg)
arcnetW_rx(struct device *dev,u_char *arcsoft,
int length,u_char saddr, u_char daddr)
{
struct device *dev=(struct device *)arg;
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int status=inb(STATUS);
struct sk_buff *skb;
/* if we didn't interrupt the IRQ handler, and RX's are still
* disabled, and we're not resetting the card... then we're stuck!
*/
if (!dev->interrupt && dev->start
&& status&NORXflag && !status&RESETflag)
{
BUGLVL(D_INIT)
printk("arcnet: timer: ARCnet was stuck! (status=%Xh)\n",
status);
BUGLVL(D_DURING)
printk("arcnet: it's a Windows packet (length=%d)\n",
length);
arcnet_inthandler(dev);
skb = alloc_skb(length, GFP_ATOMIC);
if (skb == NULL) {
printk("arcnet: Memory squeeze, dropping packet.\n");
lp->stats.rx_dropped++;
return;
}
/* requeue ourselves */
init_timer(&lp->timer);
lp->timer.expires=TIMERval;
add_timer(&lp->timer);
skb->len = length;
skb->dev = lp->wdev;
memcpy(skb->data,(u_char *)arcsoft+1,length-1);
BUGLVL(D_SKB)
{
short i;
printk("arcnet: rx skb dump follows:\n");
for(i=0; i<skb->len; i++)
{
if (i%16==0)
printk("\n[%04hX] ",i);
else
printk("%02hX ",((u_char *)skb->data)[i]);
}
printk("\n");
}
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
lp->stats.rx_packets++;
}
#endif
/****************************************************************************
* *
* Miscellaneous routines *
* *
****************************************************************************/
/* Get the current statistics. This may be called with the card open or
closed. */
* closed.
*/
static struct enet_statistics *
arcnet_get_stats(struct device *dev)
{
struct arcnet_local *lp = (struct arcnet_local *)dev->priv;
/* short ioaddr = dev->base_addr;*/
return &lp->stats;
}
/* Set or clear the multicast filter for this adaptor.
num_addrs == -1 Promiscuous mode, receive all packets
num_addrs == 0 Normal mode, clear multicast list
num_addrs > 0 Multicast mode, receive normal and MC packets, and do
best-effort filtering.
* num_addrs == -1 Promiscuous mode, receive all packets
* num_addrs == 0 Normal mode, clear multicast list
* num_addrs > 0 Multicast mode, receive normal and MC packets, and do
* best-effort filtering.
*/
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
#if 0 /* no promiscuous mode at all */
#if 0 /* no promiscuous mode at all on most ARCnet models */
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
short ioaddr = dev->base_addr;
......@@ -1907,74 +2230,17 @@ set_multicast_list(struct device *dev, int num_addrs, void *addrs)
#endif
}
int arcnet_reset(struct device *dev)
{
struct arcnet_local *lp=(struct arcnet_local *)dev->priv;
short ioaddr=dev->base_addr;
int delayval,recbuf=lp->recbuf;
outb(0,INTMASK); /* no IRQ's, please! */
BUGLVL(D_INIT)
printk("arcnet: Resetting %s (status=%Xh)\n",
dev->name,inb(STATUS));
inb(RESET); /* Reset by reading this port */
JIFFER(RESETtime);
outb(CFLAGScmd|RESETclear, COMMAND); /* clear flags & end reset */
outb(CFLAGScmd|CONFIGclear,COMMAND);
/* after a reset, the first byte of shared mem is TESTvalue and the
* second byte is our 8-bit ARCnet address
*/
{
u_char *cardmem = (u_char *) dev->mem_start;
if (cardmem[0] != TESTvalue)
{
BUGLVL(D_INIT)
printk("arcnet: reset failed: TESTvalue not present.\n");
return 1;
}
lp->arcnum=cardmem[1]; /* save address for later use */
}
/* clear out status variables */
recbuf=lp->recbuf=0;
lp->txbuf=2;
/*dev->tbusy=0;*/
/* enable extended (512-byte) packets */
outb(CONFIGcmd|EXTconf,COMMAND);
XJIFFER(ACKtime);
/* clean out all the memory to make debugging make more sense :) */
BUGLVL(D_DURING)
memset((void *)dev->mem_start,0x42,2048);
/* and enable receive of our first packet to the first buffer */
EnableReceiver();
/* re-enable interrupts */
outb(NORXflag,INTMASK);
/* done! return success. */
return 0;
}
/*
* Create the ARCnet ClientData header for an arbitrary protocol layer
/* Create the ARCnet ClientData header for an arbitrary protocol layer
*
* saddr=NULL means use device source address (always will anyway)
* daddr=NULL means leave destination address (eg unresolved arp)
*/
int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
int arcnetA_header(struct sk_buff *skb,struct device *dev,unsigned short type,
void *daddr,void *saddr,unsigned len)
{
struct ClientData *head = (struct ClientData *)
skb_push(skb,dev->hard_header_len);
struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);
/* struct arcnet_local *lp=(struct arcnet_local *)(dev->priv);*/
/* set the protocol ID according to RFC-1201 */
switch(type)
......@@ -2000,18 +2266,18 @@ int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
return 0;
}
#if 1
/*
* Set the source hardware address.
* AVE: we can't do this, so we don't. Code below is directly
* stolen from eth.c driver and won't work.
** TM: but for debugging I would like to have saddr in the header
*
* This is pretty pointless for most purposes, but it can help
* in debugging. saddr is stored in the ClientData header and
* removed before sending the packet (since ARCnet does not allow
* us to change the source address in the actual packet sent)
*/
if(saddr)
head->saddr=((u_char*)saddr)[0];
else
head->saddr=((u_char*)(dev->dev_addr))[0];
#endif
#if 0
/*
......@@ -2028,7 +2294,7 @@ int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
#endif
head->split_flag=0; /* split packets are done elsewhere */
head->sequence=(lp->sequence++);
head->sequence=0; /* so are sequence numbers */
/* supposedly if daddr is NULL, we should ignore it... */
if(daddr)
......@@ -2043,18 +2309,17 @@ int arc_header(struct sk_buff *skb,struct device *dev,unsigned short type,
}
/*
* Rebuild the ARCnet ClientData header. This is called after an ARP
/* Rebuild the ARCnet ClientData header. This is called after an ARP
* (or in future other address resolution) has completed on this
* sk_buff. We now let ARP fill in the other fields.
*/
int arc_rebuild_header(void *buff,struct device *dev,unsigned long dst,
int arcnetA_rebuild_header(void *buff,struct device *dev,unsigned long dst,
struct sk_buff *skb)
{
struct ClientData *head = (struct ClientData *)buff;
/*
* Only ARP/IP is currently supported
* Only ARP and IP are currently supported
*/
if(head->protocol_id != ARC_P_IP)
......@@ -2076,25 +2341,22 @@ int arc_rebuild_header(void *buff,struct device *dev,unsigned long dst,
#endif
}
/*
* Determine the packet's protocol ID.
/* Determine a packet's protocol ID.
*
* With ARCnet we have to convert everything to Ethernet-style stuff.
*/
unsigned short arc_type_trans(struct sk_buff *skb,struct device *dev)
unsigned short arcnetA_type_trans(struct sk_buff *skb,struct device *dev)
{
struct ClientData *head = (struct ClientData *) skb->data;
struct arcnet_local *lp=(struct arcnet_local *) (dev->priv);
/*
* Pull off the arcnet header.
*/
/* Pull off the arcnet header. */
skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len);
if (head->daddr==0)
skb->pkt_type=PACKET_BROADCAST;
else if(dev->flags&IFF_PROMISC)
else if (dev->flags&IFF_PROMISC)
{
/* if we're not sending to ourselves :) */
if (head->daddr != dev->dev_addr[0])
......@@ -2108,20 +2370,31 @@ unsigned short arc_type_trans(struct sk_buff *skb,struct device *dev)
case ARC_P_ARP: return htons(ETH_P_ARP);
case ARC_P_RARP: return htons(ETH_P_RARP);
case ARC_P_IPX: return htons(ETH_P_IPX);
case ARC_P_ATALK: return htons(ETH_P_ATALK); /* Doesn't work yet */
case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */
case ARC_P_LANSOFT: /* don't understand. fall through. */
default:
BUGLVL(D_DURING)
BUGLVL(D_EXTRA)
printk("arcnet: received packet of unknown protocol id %d (%Xh)\n",
head->protocol_id,head->protocol_id);
lp->stats.rx_frame_errors++;
return 0;
}
return htons(ETH_P_IP);
}
/****************************************************************************
* *
* Kernel Loadable Module Support *
* *
****************************************************************************/
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
static struct device thisARCnet = {
static struct device thiscard = {
" ",/* if blank, device name inserted by /linux/drivers/net/net_init.c */
0, 0, 0, 0,
0, 0, /* I/O address, IRQ */
......@@ -2129,29 +2402,29 @@ static struct device thisARCnet = {
int io=0x0; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
int irqnum=0; /* or use the insmod io= irq= shmem= options */
int irqnum=0; /* or use the insmod io= irqnum= shmem= options */
int shmem=0;
int num=0; /* number of device (ie for arc0, arc1, arc2...) */
int num=0; /* number of device (ie for 0 for arc0, 1 for arc1...) */
int
init_module(void)
{
sprintf(thisARCnet.name,"arc%d",num);
sprintf(thiscard.name,"arc%d",num);
thisARCnet.base_addr=io;
thiscard.base_addr=io;
thisARCnet.irq=irqnum;
if (thisARCnet.irq==2) thisARCnet.irq=9;
thiscard.irq=irqnum;
if (thiscard.irq==2) thiscard.irq=9;
if (shmem)
{
thisARCnet.mem_start=shmem;
thisARCnet.mem_end=thisARCnet.mem_start+512*4-1;
thisARCnet.rmem_start=thisARCnet.mem_start+512*0;
thisARCnet.rmem_end=thisARCnet.mem_start+512*2-1;
thiscard.mem_start=shmem;
thiscard.mem_end=thiscard.mem_start+512*4-1;
thiscard.rmem_start=thiscard.mem_start+512*0;
thiscard.rmem_end=thiscard.mem_start+512*2-1;
}
if (register_netdev(&thisARCnet) != 0)
if (register_netdev(&thiscard) != 0)
return -EIO;
return 0;
}
......@@ -2159,14 +2432,17 @@ init_module(void)
void
cleanup_module(void)
{
if (MOD_IN_USE) {
printk("%s: device busy, remove delayed\n",thisARCnet.name);
} else {
if (thisARCnet.start) arcnet_close(&thisARCnet);
if (thisARCnet.irq) free_irq(thisARCnet.irq);
if (thisARCnet.base_addr) release_region(thisARCnet.base_addr,
ETHERCARD_TOTAL_SIZE);
unregister_netdev(&thisARCnet);
if (MOD_IN_USE)
{
printk("%s: device busy, remove delayed\n",thiscard.name);
}
else
{
if (thiscard.start) arcnet_close(&thiscard);
if (thiscard.irq) free_irq(thiscard.irq);
if (thiscard.base_addr) release_region(thiscard.base_addr,
ARCNET_TOTAL_SIZE);
unregister_netdev(&thiscard);
}
}
......@@ -2176,10 +2452,10 @@ cleanup_module(void)
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c arcnet.c"
* version-control: t
* kept-new-versions: 5
* tab-width: 4
* tab-width: 8
* End:
*/
......@@ -249,7 +249,7 @@ eql_init(struct device *dev)
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof (unsigned long);
dev->pa_alen = 4;
dev->type = ARPHRD_SLIP;
......
......@@ -139,7 +139,7 @@ int loopback_init(struct device *dev)
dev->pa_addr = in_aton("127.0.0.1");
dev->pa_brdaddr = in_aton("127.255.255.255");
dev->pa_mask = in_aton("255.0.0.0");
dev->pa_alen = sizeof(unsigned long);
dev->pa_alen = 4;
#endif
dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL);
memset(dev->priv, 0, sizeof(struct enet_statistics));
......
......@@ -194,6 +194,7 @@ void ether_setup(struct device *dev)
dev->hard_header = eth_header;
dev->rebuild_header = eth_rebuild_header;
dev->set_mac_address = eth_mac_addr;
dev->header_cache = eth_header_cache;
dev->type = ARPHRD_ETHER;
dev->hard_header_len = ETH_HLEN;
......@@ -209,7 +210,7 @@ void ether_setup(struct device *dev)
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
dev->pa_alen = 4;
}
#ifdef CONFIG_TR
......@@ -239,7 +240,7 @@ void tr_setup(struct device *dev)
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
dev->pa_alen = 4;
}
#endif
......
......@@ -1442,7 +1442,7 @@ static int pi_probe(struct device *dev, int card_type)
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
dev->pa_alen = 4;
return 0;
}
......
......@@ -295,7 +295,7 @@ ppp_init(struct device *dev)
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
dev->pa_alen = 4;
return 0;
}
......@@ -1144,7 +1144,7 @@ ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
sendit:
if (ppp_debug_netpackets) {
struct iphdr *iph = (struct iphdr *) c;
PRINTK ((KERN_INFO "%s <-- src %lx dst %lx len %d\n", ppp->dev->name,
PRINTK ((KERN_INFO "%s <-- src %x dst %x len %d\n", ppp->dev->name,
iph->saddr, iph->daddr, count))
}
......@@ -1251,9 +1251,8 @@ ppp_read(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned
CHECK_PPP(-ENXIO);
PRINTKN (4,(KERN_DEBUG "ppp_read: called %x num %u\n",
(unsigned int) buf,
nr));
PRINTKN (4,(KERN_DEBUG "ppp_read: called %p num %u\n",
buf, nr));
do {
/* try to acquire read lock */
......@@ -1323,8 +1322,8 @@ ppp_stuff_char(struct ppp *ppp, unsigned char c)
{
int curpt = ppp->xhead - ppp->xbuff;
if ((curpt < 0) || (curpt > 3000)) {
PRINTK ((KERN_DEBUG "ppp_stuff_char: %x %x %d\n",
(unsigned int) ppp->xbuff, (unsigned int) ppp->xhead, curpt))
PRINTK ((KERN_DEBUG "ppp_stuff_char: %p %p %d\n",
ppp->xbuff, ppp->xhead, curpt))
}
if (in_xmap (ppp, c)) {
*ppp->xhead++ = PPP_ESC;
......@@ -1402,8 +1401,8 @@ ppp_write(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigne
if (ppp_debug >= 6)
ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
else {
PRINTKN (4,(KERN_DEBUG
"ppp_write: writing %d chars\n", ppp->xhead - ppp->xbuff));
PRINTKN (4,(KERN_DEBUG "ppp_write: writing %d chars\n",
(int) (ppp->xhead - ppp->xbuff)));
}
/* packet is ready-to-go */
......@@ -1471,7 +1470,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
if (error == 0) {
put_user (ppp->xmit_async_map[0], (int *) l);
PRINTKN (3,(KERN_INFO "ppp_ioctl: get asyncmap: addr %lx asyncmap %lx\n",
l, ppp->xmit_async_map[0]));
l, (unsigned long) ppp->xmit_async_map[0]));
}
break;
......@@ -1482,7 +1481,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
bset (ppp->xmit_async_map, PPP_FLAG);
bset (ppp->xmit_async_map, PPP_ESC);
PRINTKN (3,(KERN_INFO "ppp_ioctl: set xmit asyncmap %lx\n",
ppp->xmit_async_map[0]));
(unsigned long) ppp->xmit_async_map[0]));
}
break;
......@@ -1491,7 +1490,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
if (error == 0) {
ppp->recv_async_map = get_user ((int *) l);
PRINTKN (3,(KERN_INFO "ppp_ioctl: set recv asyncmap %lx\n",
ppp->recv_async_map));
(unsigned long) ppp->recv_async_map));
}
break;
......@@ -1573,7 +1572,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
error = verify_area (VERIFY_READ, (void *) l,
sizeof (ppp->xmit_async_map));
if (error == 0) {
unsigned long temp_tbl [8];
__u32 temp_tbl [8];
memcpy_fromfs (temp_tbl, (void *) l, sizeof (ppp->xmit_async_map));
temp_tbl[1] = 0x00000000; /* must not escape 0x20 - 0x3f */
......@@ -1831,8 +1830,8 @@ ppp_xmit(struct sk_buff *skb, struct device *dev)
if (ppp_debug >= 6)
ppp_print_buffer ("xmit buffer", ppp->xbuff, ppp->xhead - ppp->xbuff, KERNEL_DS);
else {
PRINTKN (4,(KERN_DEBUG
"ppp_write: writing %d chars\n", ppp->xhead - ppp->xbuff));
PRINTKN (4,(KERN_DEBUG "ppp_write: writing %d chars\n",
(int) (ppp->xhead - ppp->xbuff)));
}
ppp_kick_tty(ppp);
......
......@@ -1141,7 +1141,7 @@ slip_init(struct device *dev)
dev->pa_addr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
dev->pa_alen = 4;
return 0;
}
......
......@@ -244,7 +244,9 @@ print_ip(iph);
#ifdef TUNNEL_DEBUG
printk("tunnel: calling ip_forward()\n");
#endif
ip_forward(skb2, dev, 0, iph->daddr, 0);
if(ip_forward(skb2, dev, 0, iph->daddr, 0))
kfree_skb(skb2, FREE_WRITE);
#ifdef TUNNEL_DEBUG
printk("Packet sent through tunnel interface!\n");
......@@ -255,8 +257,6 @@ print_ip(iph);
#ifdef TUNNEL_DEBUG
printk("tunnel: Updated usage statistics.\n");
#endif
/* Clean up and return okay. */
kfree_skb(skb2, FREE_WRITE);
dev->tbusy=0;
return 0;
}
......
......@@ -105,7 +105,6 @@ int generic_proc_info(char *buffer, char **start, off_t offset,
extern int dispatch_scsi_info(int ino, char *buffer, char **start,
off_t offset, int length, int func)
{
int retval;
struct Scsi_Host *hpnt = scsi_hostlist;
if(func != 2) {
......
......@@ -57,6 +57,7 @@ static char *pas_model_names[] =
/*
* to support other than the default base address
*/
extern void mix_write (unsigned char data, int ioaddr);
unsigned char
pas_read (int ioaddr)
......@@ -367,7 +368,7 @@ attach_pas_card (long mem_start, struct address_info *hw_config)
if (detect_pas_hw (hw_config))
{
if (pas_model = pas_read (CHIP_REV))
if ((pas_model = pas_read (CHIP_REV)))
{
printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID));
}
......
......@@ -103,6 +103,10 @@
#define FM_MONO 0x388 /* This is the I/O address used by AdLib */
#ifndef PAS_BASE
#define PAS_BASE 0x388
#endif
/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the
driver. (There is no need to alter this) */
#define SEQ_MAX_QUEUE 1024
......
......@@ -766,7 +766,7 @@ int ext2_symlink (struct inode * dir, const char * name, int len,
for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
symname [l]; l++)
;
if (l >= EXT2_N_BLOCKS * sizeof (__u32)) {
if (l >= sizeof (inode->u.ext2_i.i_data)) {
ext2_debug ("l=%d, normal symlink\n", l);
......
#ifndef __ALPHA_A_OUT_H__
#define __ALPHA_A_OUT_H__
/* OSF/1 pseudo-a.out header */
/*
* OSF/1 ECOFF header structs. ECOFF files consist of:
* - a file header (struct filehdr),
* - an a.out header (struct aouthdr),
* - one or more section headers (struct scnhdr).
* The filhdr's "f_nscns" field contains the
* number of section headers.
*/
struct filehdr
{
/* OSF/1 "file" header */
__u16 f_magic, f_nscns;
__u32 f_timdat;
__u64 f_symptr;
__u32 f_nsyms;
__u16 f_opthdr, f_flags;
};
struct aouthdr
{
__u64 info; /* after that it looks quite normal.. */
__u64 tsize;
__u64 dsize;
__u64 bsize;
__u64 entry;
__u64 text_start; /* with a few additions that actually make sense */
__u64 data_start;
__u64 bss_start;
__u32 gprmask, fprmask; /* but what are these? */
__u64 gpvalue;
};
struct scnhdr
{
char s_name[8];
__u64 s_paddr;
__u64 s_vaddr;
__u64 s_size;
__u64 s_scnptr;
__u64 s_relptr;
__u64 s_lnnoptr;
__u16 s_nreloc;
__u16 s_nlnno;
__u32 s_flags;
};
struct exec
{
/* OSF/1 "file" header */
unsigned short f_magic, f_nscns;
unsigned int f_timdat;
unsigned long f_symptr;
unsigned int f_nsyms;
unsigned short f_opthdr, f_flags;
/* followed by a more normal "a.out" header */
unsigned long a_info; /* after that it looks quite normal.. */
unsigned long a_text;
unsigned long a_data;
unsigned long a_bss;
unsigned long a_entry;
unsigned long a_textstart; /* with a few additions that actually make sense */
unsigned long a_datastart;
unsigned long a_bssstart;
unsigned int a_gprmask, a_fprmask; /* but what are these? */
unsigned long a_gpvalue;
struct filehdr fh;
struct aouthdr ah;
};
/*
* Define's so that the kernel exec code can access the a.out header
* fields...
*/
#define a_info ah.info
#define a_text ah.tsize
#define a_data ah.dsize
#define a_bss ah.bsize
#define a_entry ah.entry
#define a_textstart ah.text_start
#define a_datastart ah.data_start
#define a_bssstart ah.bss_start
#define a_gprmask ah.gprmask
#define a_fprmask ah.fprmask
#define a_gpvalue ah.gpvalue
#define N_TXTADDR(x) ((x).a_textstart)
#define N_DATADDR(x) ((x).a_datastart)
#define N_BSSADDR(x) ((x).a_bssstart)
......@@ -29,12 +78,13 @@ struct exec
#define N_TRSIZE(x) 0
#define N_SYMSIZE(x) 0
#define SCNHSZ 64 /* XXX should be sizeof(scnhdr) */
#define AOUTHSZ sizeof(struct aouthdr)
#define SCNHSZ sizeof(struct scnhdr)
#define SCNROUND 16
#define N_TXTOFF(x) \
((long) N_MAGIC(x) == ZMAGIC ? 0 : \
(sizeof(struct exec) + (x).f_nscns*SCNHSZ + SCNROUND - 1) & ~(SCNROUND - 1))
(sizeof(struct exec) + (x).fh.f_nscns*SCNHSZ + SCNROUND - 1) & ~(SCNROUND - 1))
#ifdef __KERNEL__
......
......@@ -304,8 +304,15 @@ extern void writew(unsigned short b, unsigned long addr);
#define inb_p inb
#define outb_p outb
#define readl(addr) __readl(addr)
#define writel(b,addr) __writel(b,addr)
extern inline unsigned long readl(unsigned long addr)
{
return __readl(addr);
}
extern inline void writel(unsigned int b, unsigned long addr)
{
__writel(b, addr);
}
#undef vuip
......
......@@ -333,4 +333,59 @@ struct termios {
#define N_MOUSE 2
#define N_PPP 3
#endif
#ifdef __KERNEL__
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
extern inline void trans_from_termio(struct termio * termio,
struct termios * termios)
{
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
SET_LOW_BITS(termios->c_iflag, termio->c_iflag);
SET_LOW_BITS(termios->c_oflag, termio->c_oflag);
SET_LOW_BITS(termios->c_cflag, termio->c_cflag);
SET_LOW_BITS(termios->c_lflag, termio->c_lflag);
#undef SET_LOW_BITS
termios->c_cc[VINTR] = termio->c_cc[_VINTR];
termios->c_cc[VQUIT] = termio->c_cc[_VQUIT];
termios->c_cc[VERASE]= termio->c_cc[_VERASE];
termios->c_cc[VKILL] = termio->c_cc[_VKILL];
termios->c_cc[VEOF] = termio->c_cc[_VEOF];
termios->c_cc[VMIN] = termio->c_cc[_VMIN];
termios->c_cc[VEOL] = termio->c_cc[_VEOL];
termios->c_cc[VTIME] = termio->c_cc[_VTIME];
termios->c_cc[VEOL2] = termio->c_cc[_VEOL2];
termios->c_cc[VSWTC] = termio->c_cc[_VSWTC];
}
/*
* Translate a "termios" structure into a "termio". Ugh.
*
* Note the "fun" _VMIN overloading.
*/
extern inline void trans_to_termio(struct termios * termios,
struct termio * termio)
{
termio->c_iflag = termios->c_iflag;
termio->c_oflag = termios->c_oflag;
termio->c_cflag = termios->c_cflag;
termio->c_lflag = termios->c_lflag;
termio->c_line = termios->c_line;
termio->c_cc[_VINTR] = termios->c_cc[VINTR];
termio->c_cc[_VQUIT] = termios->c_cc[VQUIT];
termio->c_cc[_VERASE]= termios->c_cc[VERASE];
termio->c_cc[_VKILL] = termios->c_cc[VKILL];
termio->c_cc[_VEOF] = termios->c_cc[VEOF];
termio->c_cc[_VEOL] = termios->c_cc[VEOL];
termio->c_cc[_VEOL2] = termios->c_cc[VEOL2];
termio->c_cc[_VSWTC] = termios->c_cc[VSWTC];
if (!(termios->c_lflag & ICANON)) {
termio->c_cc[_VMIN] = termios->c_cc[VMIN];
termio->c_cc[_VTIME] = termios->c_cc[VTIME];
}
}
#endif /* __KERNEL__ */
#endif /* _ALPHA_TERMIOS_H */
......@@ -263,4 +263,37 @@ struct termios {
#define N_MOUSE 2
#define N_PPP 3
#endif
#ifdef __KERNEL__
/*
* Translate a "termio" structure into a "termios". Ugh.
*/
extern inline void trans_from_termio(struct termio * termio,
struct termios * termios)
{
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
SET_LOW_BITS(termios->c_iflag, termio->c_iflag);
SET_LOW_BITS(termios->c_oflag, termio->c_oflag);
SET_LOW_BITS(termios->c_cflag, termio->c_cflag);
SET_LOW_BITS(termios->c_lflag, termio->c_lflag);
#undef SET_LOW_BITS
memcpy(termios->c_cc, termio->c_cc, NCC);
}
/*
* Translate a "termios" structure into a "termio". Ugh.
*/
extern inline void trans_to_termio(struct termios * termios,
struct termio * termio)
{
termio->c_iflag = termios->c_iflag;
termio->c_oflag = termios->c_oflag;
termio->c_cflag = termios->c_cflag;
termio->c_lflag = termios->c_lflag;
termio->c_line = termios->c_line;
memcpy(termio->c_cc, termios->c_cc, NCC);
}
#endif /* __KERNEL__ */
#endif /* _I386_TERMIOS_H */
......@@ -34,8 +34,10 @@ extern int eth_header(struct sk_buff *skb, struct device *dev,
extern int eth_rebuild_header(void *buff, struct device *dev,
unsigned long dst, struct sk_buff *skb);
extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev);
extern void eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
extern void eth_copy_and_sum(struct sk_buff *dest,
unsigned char *src, int length, int base);
extern void eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
#endif
......
......@@ -44,7 +44,7 @@
#define ST0_DS 0x03 /* drive select mask */
#define ST0_HA 0x04 /* Head (Address) */
#define ST0_NR 0x08 /* Not Ready */
#define ST0_ECE 0x10 /* Equipment chech error */
#define ST0_ECE 0x10 /* Equipment check error */
#define ST0_SE 0x20 /* Seek end */
#define ST0_INTR 0xC0 /* Interrupt code mask */
......
......@@ -59,15 +59,15 @@
struct icmphdr {
unsigned char type;
unsigned char code;
unsigned short checksum;
__u8 type;
__u8 code;
__u16 checksum;
union {
struct {
unsigned short id;
unsigned short sequence;
__u16 id;
__u16 sequence;
} echo;
unsigned long gateway;
__u32 gateway;
} un;
};
......
......@@ -95,17 +95,17 @@
*/
struct ppp_lqp_packet_hdr {
unsigned long LastOutLQRs; /* Copied from PeerOutLQRs */
unsigned long LastOutPackets; /* Copied from PeerOutPackets */
unsigned long LastOutOctets; /* Copied from PeerOutOctets */
unsigned long PeerInLQRs; /* Copied from SavedInLQRs */
unsigned long PeerInPackets; /* Copied from SavedInPackets */
unsigned long PeerInDiscards; /* Copied from SavedInDiscards */
unsigned long PeerInErrors; /* Copied from SavedInErrors */
unsigned long PeerInOctets; /* Copied from SavedInOctets */
unsigned long PeerOutLQRs; /* Copied from OutLQRs, plus 1 */
unsigned long PeerOutPackets; /* Current ifOutUniPackets, + 1 */
unsigned long PeerOutOctets; /* Current ifOutOctets + LQR */
__u32 LastOutLQRs; /* Copied from PeerOutLQRs */
__u32 LastOutPackets; /* Copied from PeerOutPackets */
__u32 LastOutOctets; /* Copied from PeerOutOctets */
__u32 PeerInLQRs; /* Copied from SavedInLQRs */
__u32 PeerInPackets; /* Copied from SavedInPackets */
__u32 PeerInDiscards; /* Copied from SavedInDiscards */
__u32 PeerInErrors; /* Copied from SavedInErrors */
__u32 PeerInOctets; /* Copied from SavedInOctets */
__u32 PeerOutLQRs; /* Copied from OutLQRs, plus 1 */
__u32 PeerOutPackets; /* Current ifOutUniPackets, + 1 */
__u32 PeerOutOctets; /* Current ifOutOctets + LQR */
};
/*
......@@ -114,11 +114,11 @@ struct ppp_lqp_packet_hdr {
*/
struct ppp_lqp_packet_trailer {
unsigned long SaveInLQRs; /* Current InLQRs on reception */
unsigned long SaveInPackets; /* Current ifInUniPackets */
unsigned long SaveInDiscards; /* Current ifInDiscards */
unsigned long SaveInErrors; /* Current ifInErrors */
unsigned long SaveInOctets; /* Current ifInOctects */
__u32 SaveInLQRs; /* Current InLQRs on reception */
__u32 SaveInPackets; /* Current ifInUniPackets */
__u32 SaveInDiscards; /* Current ifInDiscards */
__u32 SaveInErrors; /* Current ifInErrors */
__u32 SaveInOctets; /* Current ifInOctects */
};
/*
......@@ -128,7 +128,7 @@ struct ppp_lqp_packet_trailer {
*/
struct ppp_lpq_packet {
unsigned long magic; /* current magic value */
__u32 magic; /* current magic value */
struct ppp_lqp_packet_hdr hdr; /* Header fields for structure */
struct ppp_lqp_packet_trailer tail; /* Trailer fields (not sent) */
};
......@@ -138,21 +138,21 @@ struct ppp_lpq_packet {
*/
struct ppp_stats {
unsigned long rbytes; /* bytes received */
unsigned long rcomp; /* compressed packets received */
unsigned long runcomp; /* uncompressed packets received */
unsigned long rothers; /* non-ip frames received */
unsigned long rerrors; /* received errors */
unsigned long roverrun; /* "buffer overrun" counter */
unsigned long tossed; /* packets discarded */
unsigned long runts; /* frames too short to process */
unsigned long rgiants; /* frames too large to process */
unsigned long sbytes; /* bytes sent */
unsigned long scomp; /* compressed packets sent */
unsigned long suncomp; /* uncompressed packets sent */
unsigned long sothers; /* non-ip frames sent */
unsigned long serrors; /* transmitter errors */
unsigned long sbusy; /* "transmitter busy" counter */
__u32 rbytes; /* bytes received */
__u32 rcomp; /* compressed packets received */
__u32 runcomp; /* uncompressed packets received */
__u32 rothers; /* non-ip frames received */
__u32 rerrors; /* received errors */
__u32 roverrun; /* "buffer overrun" counter */
__u32 tossed; /* packets discarded */
__u32 runts; /* frames too short to process */
__u32 rgiants; /* frames too large to process */
__u32 sbytes; /* bytes sent */
__u32 scomp; /* compressed packets sent */
__u32 suncomp; /* uncompressed packets sent */
__u32 sothers; /* non-ip frames sent */
__u32 serrors; /* transmitter errors */
__u32 sbusy; /* "transmitter busy" counter */
};
/*
......@@ -172,17 +172,17 @@ struct ppp {
int magic; /* magic value for structure */
/* Bitmapped flag fields. */
char inuse; /* are we allocated? */
char sending; /* "channel busy" indicator */
char escape; /* 0x20 if prev char was PPP_ESC*/
char toss; /* toss this frame */
unsigned long inuse; /* are we allocated? */
unsigned int flags; /* miscellany */
unsigned long xmit_async_map[8]; /* 1 bit means that given control
__u32 xmit_async_map[8]; /* 1 bit means that given control
character is quoted on output*/
unsigned long recv_async_map; /* 1 bit means that given control
__u32 recv_async_map; /* 1 bit means that given control
character is ignored on input*/
int mtu; /* maximum xmit frame size */
int mru; /* maximum receive frame size */
......@@ -193,7 +193,7 @@ struct ppp {
struct tty_struct *tty; /* ptr to TTY structure */
struct device *dev; /* easy for intr handling */
struct slcompress *slcomp; /* for header compression */
unsigned long last_xmit; /* time of last transmission */
__u32 last_xmit; /* time of last transmission */
/* These are pointers to the malloc()ed frame buffers.
These buffers are used while processing a packet. If a packet
......@@ -216,7 +216,7 @@ struct ppp {
unsigned char *us_rbuff_end; /* end of allocated space */
unsigned char *us_rbuff_head; /* head of waiting packets */
unsigned char *us_rbuff_tail; /* tail of waiting packets */
unsigned char us_rbuff_lock; /* lock: bit 0 head bit 1 tail */
unsigned long us_rbuff_lock; /* lock: bit 0 head bit 1 tail */
int inp_sig; /* input ready signal for pgrp */
int inp_sig_pid; /* process to get notified */
......
......@@ -118,4 +118,12 @@ struct sockaddr_in {
#include <asm/byteorder.h>
/* Some random defines to make it easier in the kernel.. */
#ifdef __KERNEL__
#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000))
#define MULTICAST(x) (((x) & htonl(0xf0000000)) == htonl(0xe0000000))
#endif
#endif /* _LINUX_IN_H */
......@@ -156,7 +156,7 @@ struct device
int (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);
#define HAVE_SET_CONFIG
int (*set_config)(struct device *dev, struct ifmap *map);
int (*header_cache)(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
void (*header_cache)(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
};
......
......@@ -147,7 +147,7 @@ struct task_struct {
unsigned long blocked; /* bitmap of masked signals */
unsigned long flags; /* per process flags, defined below */
int errno;
int debugreg[8]; /* Hardware debugging registers */
long debugreg[8]; /* Hardware debugging registers */
struct exec_domain *exec_domain;
/* various fields */
struct linux_binfmt *binfmt;
......
......@@ -90,8 +90,13 @@ struct sk_buff {
unsigned char *end; /* End pointer */
};
#ifdef CONFIG_SKB_LARGE
#define SK_WMEM_MAX 65535
#define SK_RMEM_MAX 65535
#else
#define SK_WMEM_MAX 32767
#define SK_RMEM_MAX 32767
#endif
#if CONFIG_SKB_CHECK
#define SK_FREED_SKB 0x0DE2C0DE
......
#include <linux/config.h>
#include <linux/linkage.h>
#ifdef CONFIG_MODVERSIONS /* CONFIG_MODVERSIONS */
#undef _set_ver
#undef X
#ifndef __GENKSYMS__
#ifdef MODULE
#define _set_ver(sym,ver) \
#ifdef CONFIG_MODVERSIONS
# undef _set_ver
# undef X
# ifndef __GENKSYMS__
# ifdef MODULE
# define _set_ver(sym,ver) \
{ (void *) & sym ## _R ## ver, SYMBOL_NAME_STR(sym) "_R" #ver }
#else /* MODULE */
#define _set_ver(sym,ver) \
# else /* MODULE */
# define _set_ver(sym,ver) \
{ (void *) & sym, SYMBOL_NAME_STR(sym) "_R" #ver }
#endif /* MODULE */
#define X(a) a
#endif /* __GENKSYMS__ */
# endif /* MODULE */
# define X(a) a
# endif /* !__GENKSYMS__ */
#else /* CONFIG_MODVERSIONS */
#define X(sym) { (void *) & sym, SYMBOL_NAME_STR(sym)}
# define X(sym) { (void *) & sym, SYMBOL_NAME_STR(sym)}
#endif /* CONFIG_MODVERSIONS */
#define EMPTY {0,0}
0, 0, 0, {
......@@ -32,6 +32,6 @@ extern int eth_rebuild_header(void *buff, struct device *dev,
extern void eth_add_arp(unsigned long addr, struct sk_buff *skb,
struct device *dev);
extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev);
extern int eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
extern void eth_header_cache(struct device *dev, struct sock *sk, unsigned long saddr, unsigned long daddr);
#endif /* _ETH_H */
/*
* Header exploders. We inline those only appearing once.
*
* We assume 8 bit bytes.
*
* This is oriented to getting good code out of GCC. It may need
* tuning for other processors.
*
* Note only IGMP uses this so far. Just as an experiment.
*/
extern __inline__ unsigned char *exp_getu16(unsigned char *bp, unsigned short *u)
{
*u=(*bp<<8)|bp[1];
return bp+2;
}
extern __inline__ unsigned char *exp_getn16(unsigned char *bp, unsigned short *u)
{
unsigned char *tp=(unsigned char *)u;
*tp++=*bp++;
*tp++=*bp++;
return bp;
}
extern __inline__ unsigned char *imp_putu16(unsigned char *bp, unsigned short n)
{
*bp=(n>>8);
bp[1]=n&0xFF;
return bp+2;
}
extern __inline__ unsigned char *imp_putn16(unsigned char *bp, unsigned short n)
{
unsigned char *sp=(unsigned char *)&n;
*bp++=*sp++;
*bp++=*sp++;
return bp;
}
extern __inline__ unsigned char *exp_getu32(unsigned char *bp, unsigned long *u)
{
*u=(bp[0]<<24)|(bp[1]<<16)|(bp[2]<<8)|bp[3];
return bp+4;
}
extern __inline__ unsigned char *exp_getn32(unsigned char *bp, unsigned long *u)
{
unsigned char *tp=(unsigned char *)u;
*tp++=*bp++;
*tp++=*bp++;
*tp++=*bp++;
*tp++=*bp++;
return bp;
}
extern __inline__ unsigned char *imp_putu32(unsigned char *bp, unsigned long n)
{
bp[0]=n>>24;
bp[1]=(n>>16)&0xFF;
bp[2]=(n>>8)&0xFF;
bp[3]=n&0xFF;
return bp+4;
}
extern __inline__ unsigned char *imp_putn32(unsigned char *bp, unsigned long n)
{
unsigned char *sp=(unsigned char *)&n;
*bp++=*sp++;
*bp++=*sp++;
*bp++=*sp++;
*bp++=*sp++;
return bp;
}
#if 0
extern __inline__ unsigned char *ip_explode(unsigned char *iph, struct ip_header *ip)
{
ip->version=*iph>>4; /* Avoid the shift. We do our equality checks shifted too */
ip->ihl=(*iph++)&0xF; /* Length in long words */
ip->tos=*iph++; /* Service type */
iph=exp_getu16(iph,&ip->tot_len); /* Length of packet */
iph=exp_getu16(iph,&ip->id); /* Packet identity */
iph=exp_getu16(iph,&ip->frag_off); /* Fragment offset */
ip->ttl=*iph++;
ip->protocol=*iph++;
iph=exp_getn16(iph,&ip->check);
iph=exp_getn32(iph,&ip->saddr);
iph=exp_getn32(iph,&ip->daddr);
return iph;
}
extern __inline__ unsigned char *icmp_explode(unsigned char *icmph, struct icmp_header *icmp)
{
icmp->type=*icmp++;
icmp->code=*icmp++;
icmph=exp_getn16(icmph,&icmp->checksum);
/* These two pairs are a union... expand both */
exp_getu32(icmph,&icmp->gateway);
icmph=exp_getu16(icmph,&icmp->id);
icmph=exp_getu16(icmph,&icmp->sequence);
return icmph;
}
#endif
extern __inline__ unsigned char *igmp_explode(unsigned char *igmph, struct igmp_header *igmp)
{
igmp->type=*igmph++;
igmph++; /* unused */
igmph=exp_getn16(igmph,&igmp->csum);
igmph=exp_getn32(igmph,&igmp->group);
return igmph;
}
#if 0
extern __inline__ unsigned char *tcp_explode(unsigned char *tcph, struct tcp_header *tcp)
{
tcph=exp_getu16(tcph,&tcp->source);
tcph=exp_getu16(tcph,&tcp->dest);
tcph=exp_getu32(tcph,&tcp->seq);
tcph=exp_getu32(tcph,&tcp->ack_seq);
tcph=exp_getu16(tcph,&tcp->u.bitmask);
tcph=exp_getu16(tcph,&tcp->window);
tcph=exp_getn16(tcph,&tcp->check);
tcph=exp_getu16(tcph,&tcp->urg_ptr);
return tcph;
}
extern __inline__ unsigned char *udp_explode(unsigned char *udph, struct udp_header *udp)
{
udph=exp_getu16(tcph,&udp->source);
udph=exp_getu16(udph,&udp->dest);
udph=exp_getu16(udph,&udp->len);
udph=exp_getn16(udph,&udp->check);
return udph;
}
#endif
......@@ -44,7 +44,6 @@
extern void ip_mc_dropsocket(struct sock *);
extern void ip_mc_dropdevice(struct device *dev);
extern int ip_mc_procinfo(char *, char **, off_t, int);
#define MULTICAST(x) (IN_MULTICAST(htonl(x)))
#endif
......@@ -89,7 +88,7 @@ extern int ip_build_header(struct sk_buff *skb,
/*extern unsigned short ip_compute_csum(unsigned char * buff, int len);*/
extern int ip_rcv(struct sk_buff *skb, struct device *dev,
struct packet_type *pt);
extern void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned long target_addr, int target_strict);
extern int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned long target_addr, int target_strict);
extern void ip_send_check(struct iphdr *ip);
extern int ip_id_count;
extern void ip_queue_xmit(struct sock *sk,
......
......@@ -24,7 +24,9 @@
#define MAX_FIN_SIZE 40 + MAX_HEADER + 15
#define MAX_ACK_SIZE 40 + MAX_HEADER + 15
#define MAX_RESET_SIZE 40 + MAX_HEADER + 15
#define MAX_WINDOW 16384
#define MAX_WINDOW 32767 /* Never offer a window over 32767 without using
window scaling (not yet supported). Some poor
stacks do signed 16bit maths! */
#define MIN_WINDOW 2048
#define MAX_ACK_BACKLOG 2
#define MIN_WRITE_SPACE 2048
......
......@@ -167,6 +167,89 @@ static int alloc_area_pages(unsigned long address, unsigned long size)
return 0;
}
static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
unsigned long offset)
{
unsigned long end;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
if (!pte_none(*pte))
printk("remap_area_pte: page already exists\n");
*pte = mk_pte(offset, PAGE_KERNEL);
address += PAGE_SIZE;
offset += PAGE_SIZE;
pte++;
} while (address < end);
}
static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
unsigned long offset)
{
unsigned long end;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
offset -= address;
do {
pte_t * pte = pte_alloc_kernel(pmd, address);
if (!pte)
return -ENOMEM;
remap_area_pte(pte, address, end - address, address + offset);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
return 0;
}
static int remap_area_pages(unsigned long address, unsigned long offset, unsigned long size)
{
pgd_t * dir;
unsigned long end = address + size;
offset -= address;
dir = pgd_offset(&init_task, address);
while (address < end) {
pmd_t *pmd = pmd_alloc_kernel(dir, address);
if (!pmd)
return -ENOMEM;
if (remap_area_pmd(pmd, address, end - address, offset + address))
return -ENOMEM;
set_pgdir(address, *dir);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
}
invalidate();
return 0;
}
static struct vm_struct * get_vm_area(unsigned long size)
{
void *addr;
struct vm_struct **p, *tmp, *area;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
addr = (void *) VMALLOC_START;
area->size = size + PAGE_SIZE;
area->next = NULL;
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
area->addr = addr;
area->next = *p;
*p = area;
return area;
}
void vfree(void * addr)
{
struct vm_struct **p, *tmp;
......@@ -191,25 +274,15 @@ void vfree(void * addr)
void * vmalloc(unsigned long size)
{
void * addr;
struct vm_struct **p, *tmp, *area;
struct vm_struct *area;
size = PAGE_ALIGN(size);
if (!size || size > high_memory)
return NULL;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
area = get_vm_area(size);
if (!area)
return NULL;
addr = (void *) VMALLOC_START;
area->size = size + PAGE_SIZE;
area->next = NULL;
for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
area->addr = addr;
area->next = *p;
*p = area;
addr = area->addr;
if (alloc_area_pages(VMALLOC_VMADDR(addr), size)) {
vfree(addr);
return NULL;
......@@ -217,6 +290,34 @@ void * vmalloc(unsigned long size)
return addr;
}
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access high addresses
* directly.
*/
void * vremap(unsigned long offset, unsigned long size)
{
void * addr;
struct vm_struct * area;
if (offset < high_memory)
return NULL;
if (offset & ~PAGE_MASK)
return NULL;
size = PAGE_ALIGN(size);
if (!size || size > offset + size)
return NULL;
area = get_vm_area(size);
if (!area)
return NULL;
addr = area->addr;
if (remap_area_pages(VMALLOC_VMADDR(addr), offset, size)) {
vfree(addr);
return NULL;
}
return addr;
}
int vread(char *buf, char *addr, int count)
{
struct vm_struct **p, *tmp;
......
......@@ -53,39 +53,39 @@ o TCP irtt support [TESTED]
o RTF_REJECT routing support [TESTED]
o Fixed 0 length fragment bug [TESTED]
o Fixed overlapping reasm bug [TESTED]
o Newest AX.25 code from John Naylor [IN]
o NetROM from John Naylor [IN]
o Newest AX.25 code from John Naylor [TESTED]
o NetROM from John Naylor [TESTED]
o Routerless DDP fixes from Wesley [TESTED]
------->>>>> ALPHA 005 <<<<<----------
o Several compile and bugfixes from Jakko [IN]
o Several compile and bugfixes from Jakko [TESTED]
o Connect fix from Matt Day (+ fix to fix) [TESTED]
o RTT, memory leak and other netrom/ax.25 cures
-- John Naylor [IN]
o IP source route via broadcast now illegal [IN]
-- John Naylor [TESTED]
o IP source route via broadcast now illegal [TESTED]
------->>>>> ALPHA 006 <<<<<----------
o Yet more NetROM/AX.25 improvements [IN]
o Yet more NetROM/AX.25 improvements [TESTED]
-- John Naylor
o Fixed a _stupid_ appletalk bug [TESTED]
o Missing include [IN]
o Missing include [TESTED]
-- Lots of people
o Can drop all source routes [IN]
o Can drop all source routes [TESTED]
o Printing fixes for ip_fw [IN]
o UDP checksum fix (Gerhard) [IN]
o UDP checksum fix (Gerhard) [TESTED]
o Newer 3c505 driver from Juha Laiho [IN]
o Security fix to axassociate [IN]
o Security fix to axassociate [TESTED]
o Loopback driver debugged (fixes named) [TESTED]
o SCC driver from Joerg Reuter [IN]
o IP Firewall accounting zero bug [IN]
o SCC driver from Joerg Reuter [TESTED]
o IP Firewall accounting zero bug [TESTED]
////////////////////////////1.3.0///////////////////////////
o Merged loadable firewall code [NOT INCLUDED YET]
o New buffers used totally non optimally [SEEMS OK]
o New buffers used totally non optimally [TESTED]
o Fast ip_forwarding (needs changing) [NOT INCLUDED YET]
o Fixed connection hang bug in new SWS code [TESTED]
o Buffer management hack putting skbuff control
......@@ -93,10 +93,10 @@ o Buffer management hack putting skbuff control
totally cache non-optimal [TESTED]
o Faster checksum [Tom May] [IN]
o Appletalk router fixes [Michael Callahan] [IN]
o TCP state error fixes [Mark Tamsky] [IN]
o Verify area fixes [Heiko Eissfeldt] [IN]
o TCP state error fixes [Mark Tamsky] [TESTED]
o Verify area fixes [Heiko Eissfeldt] [TESTED]
o Routes use metric field [John Naylor] [IN]
o Major AX.25/NetROM fixes [John Nalor] [IN]
o Major AX.25/NetROM fixes [John Nalor] [TESTED]
------->>>>> NET3 030 <<<<<----------
......@@ -104,18 +104,47 @@ o Long word align ethernet IP headers (64byte align for pentium) [TESTED]
(less helpful than I'd have liked)
o Fixed variable length header support to really work [TESTED]
o Mend appletalk/ipx partially [IN]
o Start playing with input checksum & copy [IN]
o Start playing with input checksum & copy [TESTED]
o Fixed PPP and other oddments [IN]
o Mended IPIP [Might work ;)]
------->>>>> 1.3.7 <<<<<----------
o Checksum bug fixed [TESTED]
o Lance driver panic cured [BROKEN]
o DEC ALPHA stuff (Linus) [ASK HIM NOT ME]
o Always try to keep output packet order
(eg for vat and BSD fast path tcp) [TESTED]
o Copy the mac pointer in skb_clone [TESTED]
o Fix tcpdump panic [IN]
o Fix dev_alloc_skb NULL deref bug [TESTED]
o Fix Security error in SIGURG stuff [TESTED]
o Missing 15 byte slack on ip_loopback [IN, still has mcast bugs left!]
------->>>>> 1.3.8 <<<<<----------
o UDP snmp count fixed [IN]
o IP snmp out count fixed [IN] (fragment still wrong)
o First bit of Dave Bonn's fast forwarding [IN]
o Fix leaks and double free in firewalling [IN]
o Fix memory scribble in ip_build_xmit [TESTED]
o Do fast cases of ip_build_xmit first
slows fragmented I/O down, speeds up smaller
packets. UDP send ttcp can now touch 7.5Mbyte/sec
with nothing else going on. UDP recv is slower 8( [TESTED]
o Fixed and enabled ethernet header caches [IN]
o Removed junk from igmp [IN]
o Obscure UDP/copy&sum bug fix [IN]
o Fixed multicast [IN]
o TCP does rerouting for most cases [NOT WORKING YET]
------->>>>> 1.3.? <<<<<----------
o Finish merging the bridge code
o Device locking
o SIOCSLEEPRT patch
o Options support in ip_build_xmit [PENDING]
o Fast checksum/copy on outgoing TCP
o Explode/implode headers for alpha,mips etc.
o Fast dev_grab_next() transmit reload function
and dev_push_failed() ??
o Faster ip_forward [PENDING]
......@@ -127,6 +156,7 @@ o AX.25 set protocol type
o Clean up RAW AX.25 sockets.
o Finish 802.2 Class I code to be compliant to the oddities of 802.2
o Full variable length AX.25 support [JSN doing]
o Tidy BPQ support
0.2
---
......@@ -139,6 +169,7 @@ o PPP for Sonix ISDN.
o Loadable firewall extensions.
o Screend loadable firewall module
o LZ SLIP [Done, resolving patent issues]
o AXIP
0.3
---
......@@ -198,7 +229,7 @@ problem.
10. Frame Relay/WAN/ISDN drivers [I'm working on the sonix EuroISDN board
driver but thats for an internal project and its general release is still
a maybe (so is finishing it ;))].
a maybe (so is finishing it ;))][Someone is working on Frame Relay].
11. IP over SCSI.
......
......@@ -72,8 +72,10 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock,
if(sk->err)
{
release_sock(sk);
cli();
*err=-sk->err;
sk->err=0;
restore_flags(intflags);
return NULL;
}
......@@ -163,8 +165,6 @@ void skb_free_datagram(struct sk_buff *skb)
void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
{
/* We will know all about the fraglist options to allow >4K receives
but not this release */
memcpy_tofs(to,skb->h.raw+offset,size);
}
......
......@@ -312,7 +312,6 @@ int unregister_netdevice_notifier(struct notifier_block *nb)
void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
{
unsigned long flags;
int nitcount;
struct packet_type *ptype;
int where = 0; /* used to say if the packet should go */
/* at the front or the back of the */
......@@ -367,7 +366,7 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
restore_flags(flags);
/* copy outgoing packets to any sniffer packet handlers */
if(!where)
if(!where && dev_nit)
{
skb->stamp=xtime;
for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next)
......@@ -384,7 +383,6 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
skb2->h.raw = skb2->data + dev->hard_header_len;
skb2->mac.raw = skb2->data;
ptype->func(skb2, skb->dev, ptype);
nitcount--;
}
}
}
......@@ -458,7 +456,7 @@ void netif_rx(struct sk_buff *skb)
*/
#ifdef CONFIG_NET_RUNONIRQ /* Dont enable yet, needs some driver mods */
inet_bh();
net_bh();
#else
mark_bh(NET_BH);
#endif
......@@ -616,7 +614,8 @@ void net_bh(void *tmp)
/*
* Can we send anything now? We want to clear the
* decks for any more sends that get done as we
* process the input.
* process the input. This also minimises the
* latency on a transmit interrupt bh.
*/
dev_transmit();
......@@ -676,7 +675,7 @@ void net_bh(void *tmp)
for (ptype = ptype_base[ntohs(type)&15]; ptype != NULL; ptype = ptype->next)
{
if ((ptype->type == type || ptype->type == htons(ETH_P_ALL)) && (!ptype->dev || ptype->dev==skb->dev))
if (ptype->type == type && (!ptype->dev || ptype->dev==skb->dev))
{
/*
* We already have a match queued. Deliver
......
......@@ -40,6 +40,9 @@
* (eg for big web sites), but only if
* specifically application requested.
* Alan Cox : New buffering throughout IP. Used dumbly.
* Alan Cox : New buffering now used smartly.
* Alan Cox : BSD rather than common sense interpretation of
* listen.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -491,6 +494,8 @@ static int inet_listen(struct socket *sock, int backlog)
* else does..
* Now truncate to 128 not 5.
*/
if ((unsigned) backlog == 0) /* BSDism */
backlog = 1;
if ((unsigned) backlog > 128)
backlog = 128;
sk->max_ack_backlog = backlog;
......
......@@ -33,7 +33,7 @@
* Peter Belding : Tightened up ICMP redirect handling
* Alan Cox : Tightened even more.
* Arnt Gulbrandsen: Misplaced #endif with net redirect and break
*
* A.N.Kuznetsov : ICMP timestamp still used skb+1
*
*
* This program is free software; you can redistribute it and/or
......@@ -544,7 +544,7 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct de
* Build ICMP_TIMESTAMP Response message.
*/
icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
icmphr = (struct icmphdr *) (skb2->data + offset);
memcpy((char *) icmphr, (char *) icmph, 12);
icmphr->type = ICMP_TIMESTAMPREPLY;
icmphr->code = icmphr->checksum = 0;
......
......@@ -14,6 +14,7 @@
* Alan Cox : Added lots of __inline__ to optimise
* the memory usage of all the tiny little
* functions.
* Alan Cox : Dumped the header building experiment.
*/
......@@ -36,7 +37,6 @@
#include <net/sock.h>
#include <linux/igmp.h>
#include <net/checksum.h>
#include <net/head_explode.h>
#ifdef CONFIG_IP_MULTICAST
......@@ -84,7 +84,7 @@ static void igmp_send_report(struct device *dev, unsigned long address, int type
{
struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC);
int tmp;
unsigned char *dp;
struct igmphdr *ih;
if(skb==NULL)
return;
......@@ -95,15 +95,12 @@ static void igmp_send_report(struct device *dev, unsigned long address, int type
kfree_skb(skb, FREE_WRITE);
return;
}
dp=skb->data+tmp;
skb_put(skb,sizeof(struct igmphdr));
*dp++=type;
*dp++=0;
skb->h.raw=dp;
dp=imp_putu16(dp,0); /* checksum */
dp=imp_putn32(dp,address); /* Address (already in net order) */
imp_putn16(skb->h.raw,ip_compute_csum(skb->data+tmp,sizeof(struct igmphdr))); /* Checksum fill */
ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
ih->type=IGMP_HOST_MEMBERSHIP_REPORT;
ih->unused=0;
ih->csum=0;
ih->group=address;
ih->csum=ip_compute_csum((void *)ih,sizeof(struct igmphdr)); /* Checksum fill */
ip_queue_xmit(NULL,dev,skb,1);
}
......@@ -204,10 +201,9 @@ int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
struct inet_protocol *protocol)
{
/* This basically follows the spec line by line -- see RFC1112 */
struct igmp_header igh;
struct igmphdr *ih;
/* Pull the IGMP header */
igmp_explode(skb->h.raw,&igh);
ih=(struct igmphdr *)skb->data;
if(skb->len <sizeof(struct igmphdr) || skb->ip_hdr->ttl!=1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr)))
{
......@@ -215,10 +211,10 @@ int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
return 0;
}
if(igh.type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
igmp_heard_query(dev);
if(igh.type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==igh.group)
igmp_heard_report(dev,igh.group);
if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group)
igmp_heard_report(dev,ih->group);
kfree_skb(skb, FREE_READ);
return 0;
}
......
......@@ -82,6 +82,9 @@
* Alan Cox : Stopped broadcast source route explosions.
* Alan Cox : Can disable source routing
* Takeshi Sone : Masquerading didn't work.
* Dave Bonn,Alan Cox : Faster IP forwarding whenever possible.
* Alan Cox : Memory leaks, tramples, misc debugging.
* Alan Cox : Fixed multicast (by popular demand 8))
*
*
*
......@@ -142,7 +145,6 @@ extern int last_retran;
extern void sort_send(struct sock *sk);
#define min(a,b) ((a)<(b)?(a):(b))
#define LOOPBACK(x) (((x) & htonl(0xff000000)) == htonl(0x7f000000))
/*
* SNMP management statistics
......@@ -1007,7 +1009,7 @@ void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int i
* Forward an IP datagram to its next destination.
*/
void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned long target_addr, int target_strict)
int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned long target_addr, int target_strict)
{
struct device *dev2; /* Output device */
struct iphdr *iph; /* Our header */
......@@ -1037,7 +1039,7 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
/* fall thru */
default:
return;
return -1;
}
}
#endif
......@@ -1070,7 +1072,7 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
{
/* Tell the sender its packet died... */
icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0, dev);
return;
return -1;
}
/*
......@@ -1086,7 +1088,7 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
* ICMP is screened later.
*/
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, 0, dev);
return;
return -1;
}
......@@ -1109,8 +1111,7 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
if(target_strict)
{
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0, dev);
kfree_skb(skb, FREE_READ);
return;
return -1;
}
/*
......@@ -1125,7 +1126,7 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
* Tell the sender its packet cannot be delivered...
*/
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0, dev);
return;
return -1;
}
if (rt->rt_gateway != 0)
raddr = rt->rt_gateway;
......@@ -1145,12 +1146,12 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
* we calculated.
*/
#ifndef CONFIG_IP_NO_ICMP_REDIRECT
if (dev == dev2 && !((iph->saddr^iph->daddr)&dev->pa_mask) && rt->rt_flags&RTF_MODIFIED)
if (dev == dev2 && !((iph->saddr^iph->daddr)&dev->pa_mask) && (rt->rt_flags&RTF_MODIFIED))
icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev);
#endif
/*
* We now allocate a new buffer, and copy the datagram into it.
* We now may allocate a new buffer, and copy the datagram into it.
* If the indicated interface is up and running, kick it.
*/
......@@ -1165,13 +1166,9 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
ip_fw_masquerade(&skb, dev2);
#endif
/*
* Current design decrees we copy the packet. For identical header
* lengths we could avoid it. The new skb code will let us push
* data so the problem goes away then.
*/
if(skb_headroom(skb)<dev2->hard_header_len)
skb2 = alloc_skb(dev2->hard_header_len + skb->len + 15, GFP_ATOMIC);
else skb2=skb;
/*
* This is rare and since IP is tolerant of network failures
......@@ -1181,13 +1178,20 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
if (skb2 == NULL)
{
NETDEBUG(printk("\nIP: No memory available for IP forward\n"));
return;
return -1;
}
/* Now build the MAC header. */
(void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr);
/*
* We have to copy the bytes over as the new header wouldn't fit
* the old buffer. This should be very rare.
*/
if(skb2!=skb)
{
ptr = skb_put(skb2,skb->len);
skb2->free = 1;
skb2->h.raw = ptr;
......@@ -1196,7 +1200,7 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
* Copy the packet data into the new buffer.
*/
memcpy(ptr, skb->h.raw, skb->len);
}
ip_statistics.IpForwDatagrams++;
......@@ -1234,6 +1238,16 @@ void ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, unsigned l
dev_queue_xmit(skb2, dev2, SOPRI_NORMAL);
}
}
else
return -1;
/*
* Tell the caller if their buffer is free.
*/
if(skb==skb2)
return 0;
return 1;
}
......@@ -1293,6 +1307,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/*
* Our transport medium may have padded the buffer out. Now we know it
* is IP we can trim to the true length of the frame.
* Note this now means skb->len holds ntohs(iph->tot_len).
*/
skb_trim(skb,ntohs(iph->tot_len));
......@@ -1480,7 +1495,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
if (ip_fw_demasquerade(skb))
{
struct iphdr *iph=skb->h.iph;
ip_forward(skb, dev, is_frag|4, iph->daddr, 0);
if(ip_forward(skb, dev, is_frag|4, iph->daddr, 0))
kfree_skb(skb, FREE_WRITE);
return(0);
}
......@@ -1620,15 +1635,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
}
/*
* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday.
*
* This is inefficient. While finding out if it is for us we could also compute
* the routing table entry. This is where the great unified cache theory comes
* in as and when someone implements it
*
* For most hosts over 99% of packets match the first conditional
* and don't go via ip_chk_addr. Note: brd is set to IS_MYADDR at
* function entry.
* Do any IP forwarding required.
*/
/*
......@@ -1646,18 +1653,14 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
*/
#ifdef CONFIG_IP_FORWARD
ip_forward(skb, dev, is_frag, target_addr, target_strict);
if(ip_forward(skb, dev, is_frag, target_addr, target_strict))
kfree_skb(skb, FREE_WRITE);
#else
/* printk("Machine %lx tried to use us as a forwarder to %lx but we have forwarding disabled!\n",
iph->saddr,iph->daddr);*/
ip_statistics.IpInAddrErrors++;
#endif
/*
* The forwarder is inefficient and copies the packet. We
* free the original now.
*/
kfree_skb(skb, FREE_WRITE);
#endif
return(0);
}
......@@ -1694,7 +1697,7 @@ static void ip_loopback(struct device *old_dev, struct sk_buff *skb)
/*
* Add the rest of the data space.
*/
newskb->ip_hdr=(struct iphdr *)skb_put(skb, len);
newskb->ip_hdr=(struct iphdr *)skb_put(newskb, len);
/*
* Copy the data
*/
......@@ -1894,7 +1897,7 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
}
}
#endif
if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))
if((dev->flags&IFF_BROADCAST) && (iph->daddr==dev->pa_brdaddr||iph->daddr==0xFFFFFFFF) && !(dev->flags&IFF_LOOPBACK))
ip_loopback(dev,skb);
if (dev->flags & IFF_UP)
......@@ -1974,7 +1977,6 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
}
#endif
/*
* Socket option code for IP. This is the end of the line after any TCP,UDP etc options on
* an IP socket.
......@@ -1997,6 +1999,8 @@ static struct device *ip_mc_find_devfor(unsigned long addr)
return NULL;
}
#endif
int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen)
{
int val,err;
......@@ -2344,6 +2348,8 @@ int ip_build_xmit(struct sock *sk,
int local=0;
struct device *dev;
ip_statistics.IpOutRequests++;
#ifdef CONFIG_INET_MULTICAST
if(sk && MULTICAST(daddr) && *sk->ip_mc_name)
......@@ -2421,6 +2427,69 @@ int ip_build_xmit(struct sock *sk,
* Now compute the buffer space we require
*/
/*
* Try the simple case first. This leaves broadcast, multicast, fragmented frames, and by
* choice RAW frames within 20 bytes of maximum size(rare) to the long path
*/
if(length+20 <= dev->mtu && !MULTICAST(daddr) && daddr!=0xFFFFFFFF && daddr!=dev->pa_brdaddr)
{
int error;
struct sk_buff *skb=sock_alloc_send_skb(sk, length+20+15+dev->hard_header_len,0,&error);
if(skb==NULL)
return error;
skb->dev=dev;
skb->free=1;
skb->when=jiffies;
skb->sk=sk;
skb->arp=0;
skb->saddr=saddr;
length+=20; /* We do this twice so the subtract once is quicker */
skb->raddr=(rt&&rt->rt_gateway)?rt->rt_gateway:daddr;
skb_reserve(skb,(dev->hard_header_len+15)&~15);
if(sk->ip_hcache_state>0)
{
memcpy(skb_push(skb,dev->hard_header_len),sk->ip_hcache_data,dev->hard_header_len);
skb->arp=1;
}
else if(dev->hard_header)
{
if(dev->hard_header(skb,dev,ETH_P_IP,NULL,NULL,0)>0)
skb->arp=1;
}
skb->ip_hdr=iph=(struct iphdr *)skb_put(skb,length);
if(type!=IPPROTO_RAW)
{
iph->version=4;
iph->ihl=5;
iph->tos=sk->ip_tos;
iph->tot_len = htons(length);
iph->id=htons(ip_id_count++);
iph->frag_off = 0;
iph->ttl=sk->ip_ttl;
iph->protocol=type;
iph->saddr=saddr;
iph->daddr=daddr;
iph->check=0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
getfrag(frag,saddr,(void *)(iph+1),0, length-20);
}
else
getfrag(frag,saddr,(void *)iph,0,length);
#ifdef CONFIG_IP_ACCT
ip_fw_chk((void *)skb->data,dev,ip_acct_chain, IP_FW_F_ACCEPT,1);
#endif
if(dev->flags&IFF_UP)
dev_queue_xmit(skb,dev,sk->priority);
else
{
ip_statistics.IpOutDiscards++;
kfree_skb(skb, FREE_WRITE);
}
return 0;
}
fragheaderlen = dev->hard_header_len;
if(type != IPPROTO_RAW)
fragheaderlen += 20;
......@@ -2512,7 +2581,7 @@ int ip_build_xmit(struct sock *sk,
if(sk->ip_hcache_state>0)
{
memcpy(skb->data,sk->ip_hcache_data, dev->hard_header_len);
memcpy(skb_push(skb,dev->hard_header_len),sk->ip_hcache_data, dev->hard_header_len);
skb->arp=1;
}
else if (dev->hard_header)
......@@ -2526,7 +2595,7 @@ int ip_build_xmit(struct sock *sk,
* Find where to start putting bytes.
*/
iph = (struct iphdr *)data;
skb->ip_hdr = iph = (struct iphdr *)data;
/*
* Only write IP header onto non-raw packets
......@@ -2620,6 +2689,13 @@ int ip_build_xmit(struct sock *sk,
kfree_skb(skb, FREE_READ);
}
#endif
/*
* BSD loops broadcasts
*/
if((dev->flags&IFF_BROADCAST) && (daddr==0xFFFFFFFF || daddr==dev->pa_brdaddr) && !(dev->flags&IFF_LOOPBACK))
ip_loopback(dev,skb);
/*
* Now queue the bytes into the device.
*/
......
......@@ -56,7 +56,7 @@ int ipip_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
#ifdef TUNNEL_DEBUG
printk("ipip_rcv: got a packet!\n");
#endif
ip_forward(skb, dev, 0, daddr, 0);
if(ip_forward(skb, dev, 0, daddr, 0))
kfree_skb(skb, FREE_READ);
MOD_DEC_USE_COUNT;
return(0);
......
......@@ -29,6 +29,7 @@
* Alan Cox : RTF_REJECT support.
* Alan Cox : TCP irtt support.
* Jonathan Naylor : Added Metric support.
* Miquel van Smoorenburg : BSD API fixes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -314,8 +315,7 @@ void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
while ((r = *rp) != NULL)
{
if (r->rt_dst != dst ||
r->rt_mask != mask ||
r->rt_metric < metric)
r->rt_mask != mask)
{
rp = &r->rt_next;
continue;
......@@ -381,6 +381,7 @@ static int rt_new(struct rtentry *r)
char * devname;
struct device * dev = NULL;
unsigned long flags, daddr, mask, gw;
unsigned char metric;
/*
* If a device is specified find it.
......@@ -406,13 +407,14 @@ static int rt_new(struct rtentry *r)
/*
* Make local copies of the important bits
* We decrement the metric by one for BSD compatibility.
*/
flags = r->rt_flags;
daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr;
mask = ((struct sockaddr_in *) &r->rt_genmask)->sin_addr.s_addr;
gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr;
metric = r->rt_metric > 0 ? r->rt_metric - 1 : 0;
/*
* BSD emulation: Permits route add someroute gw one-of-my-addresses
......@@ -475,7 +477,7 @@ static int rt_new(struct rtentry *r)
* Add the route
*/
ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mss, r->rt_window, r->rt_irtt, r->rt_metric);
ip_rt_add(flags, daddr, mask, gw, dev, r->rt_mss, r->rt_window, r->rt_irtt, metric);
return 0;
}
......
......@@ -45,6 +45,8 @@
* Arnt Gulbrandsen : New udp_send and stuff
* Alan Cox : Cache last socket
* Alan Cox : Route cache
* Alan Cox : Checksum precompute is bogus is some lame
* software is padding its udp frames in IP!
*
*
* This program is free software; you can redistribute it and/or
......@@ -273,7 +275,10 @@ static int udp_send(struct sock *sk, struct sockaddr_in *sin,
else
a = ip_build_xmit(sk, udp_getfrag, &ufh, ulen,
sin->sin_addr.s_addr, rt, IPPROTO_UDP);
return(a<0 ? a : len);
if(a<0)
return a;
udp_statistics.UdpOutDatagrams++;
return len;
}
......@@ -533,6 +538,9 @@ int udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
ulen = ntohs(uh->len);
if(ulen!=len)
skb->ip_summed=0; /* Bogoid padded frame */
if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh))
{
NETDEBUG(printk("UDP: short packet: %d/%d\n", ulen, len));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment