Commit 69651a92 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.48

parent 74beaae0
......@@ -228,6 +228,13 @@ S: West Hanningfield Road
S: Great Baddow, Essex CM2 8HN
S: UK
N: Michael Hipp
E: mhipp@student.uni-tuebingen.de
D: drivers for the racal ni5210 & ni6510 ethernet-boards
S: Talstr. 1
S: D - 72072 Tuebingen
S: Germany
N: Dirk Hohndel
E: hohndel@informatik.uni-wuerzburg.de
D: XFree86
......
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 47
SUBLEVEL = 48
ARCH = i386
......@@ -110,7 +110,10 @@ boot:
include/asm:
( cd include ; ln -sf asm-$(ARCH) asm)
symlinks: boot include/asm
kernel/entry.S:
ln -sf ../arch/$(ARCH)/entry.S kernel/entry.S
symlinks: boot include/asm kernel/entry.S
config.in: arch/$(ARCH)/config.in
cp $< $@
......@@ -183,7 +186,7 @@ mrproper: clean
rm -f include/linux/autoconf.h tools/version.h
rm -f drivers/sound/local.h
rm -f .version .config* config.in config.old
rm -f boot include/asm
rm -f boot include/asm kernel/entry.S
rm -f .depend `find . -name .depend -print`
distclean: mrproper
......
......@@ -108,6 +108,8 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool 'EtherExpress support' CONFIG_EEXPRESS n
bool 'AT1700 support' CONFIG_AT1700 n
bool 'NI5210 support' CONFIG_NI52 n
bool 'NI6510 support' CONFIG_NI65 n
fi
bool 'HP PCLAN support' CONFIG_HPLAN n
bool 'NE2000/NE1000 support' CONFIG_NE2000 y
......@@ -118,8 +120,6 @@ bool 'EISA and on board controllers' CONFIG_NET_EISA n
bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
fi
bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
#bool 'NI52EE support' CONFIG_NI52 n
#bool 'NI65EE support' CONFIG_NI65 n
bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
if [ "$CONFIG_NET_POCKET" = "y" ]; then
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
......
/*
* linux/arch/i386/entry.S
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* entry.S contains the system-call and fault low-level handling routines.
* This also contains the timer-interrupt handler, as well as all interrupts
* and faults that can result in a task-switch.
*
* NOTE: This code handles signal-recognition, which happens every time
* after a timer-interrupt and after each system call.
*
* I changed all the .align's to 4 (16 byte alignment), as that's faster
* on a 486.
*
* Stack layout in 'ret_from_system_call':
* ptrace needs to have all regs on the stack.
* if the order here is changed, it needs to be
* updated in fork.c:copy_process, signal.c:do_signal,
* ptrace.c and ptrace.h
*
* 0(%esp) - %ebx
* 4(%esp) - %ecx
* 8(%esp) - %edx
* C(%esp) - %esi
* 10(%esp) - %edi
* 14(%esp) - %ebp
* 18(%esp) - %eax
* 1C(%esp) - %ds
* 20(%esp) - %es
* 24(%esp) - %fs
* 28(%esp) - %gs
* 2C(%esp) - orig_eax
* 30(%esp) - %eip
* 34(%esp) - %cs
* 38(%esp) - %eflags
* 3C(%esp) - %oldesp
* 40(%esp) - %oldss
*/
#include <linux/segment.h>
#include <linux/sys.h>
EBX = 0x00
ECX = 0x04
EDX = 0x08
ESI = 0x0C
EDI = 0x10
EBP = 0x14
EAX = 0x18
DS = 0x1C
ES = 0x20
FS = 0x24
GS = 0x28
ORIG_EAX = 0x2C
EIP = 0x30
CS = 0x34
EFLAGS = 0x38
OLDESP = 0x3C
OLDSS = 0x40
CF_MASK = 0x00000001
IF_MASK = 0x00000200
NT_MASK = 0x00004000
VM_MASK = 0x00020000
/*
* these are offsets into the task-struct.
*/
state = 0
counter = 4
priority = 8
signal = 12
blocked = 16
flags = 20
errno = 24
dbgreg6 = 52
dbgreg7 = 56
exec_domain = 60
ENOSYS = 38
.globl _system_call,_lcall7
.globl _device_not_available, _coprocessor_error
.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_reserved
.globl _alignment_check,_page_fault
.globl ret_from_sys_call, _sys_call_table
#define SAVE_ALL \
cld; \
push %gs; \
push %fs; \
push %es; \
push %ds; \
pushl %eax; \
pushl %ebp; \
pushl %edi; \
pushl %esi; \
pushl %edx; \
pushl %ecx; \
pushl %ebx; \
movl $(KERNEL_DS),%edx; \
mov %dx,%ds; \
mov %dx,%es; \
movl $(USER_DS),%edx; \
mov %dx,%fs;
#define RESTORE_ALL \
cmpw $(KERNEL_CS),CS(%esp); \
je 1f; \
movl _current,%eax; \
movl dbgreg7(%eax),%ebx; \
movl %ebx,%db7; \
1: popl %ebx; \
popl %ecx; \
popl %edx; \
popl %esi; \
popl %edi; \
popl %ebp; \
popl %eax; \
pop %ds; \
pop %es; \
pop %fs; \
pop %gs; \
addl $4,%esp; \
iret
.align 4
_lcall7:
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
SAVE_ALL
movl EIP(%esp),%eax # due to call gates, this is eflags, not eip..
movl CS(%esp),%edx # this is eip..
movl EFLAGS(%esp),%ecx # and this is cs..
movl %eax,EFLAGS(%esp) #
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
movl %esp,%eax
movl _current,%edx
pushl %eax
movl exec_domain(%edx),%edx # Get the execution domain
movl 4(%edx),%edx # Get the lcall7 handler for the domain
call *%edx
popl %eax
jmp ret_from_sys_call
.align 4
handle_bottom_half:
pushfl
incl _intr_count
sti
call _do_bottom_half
popfl
decl _intr_count
jmp 9f
.align 4
reschedule:
pushl $ret_from_sys_call
jmp _schedule
.align 4
_system_call:
pushl %eax # save orig_eax
SAVE_ALL
movl $-ENOSYS,EAX(%esp)
cmpl $(NR_syscalls),%eax
jae ret_from_sys_call
movl _sys_call_table(,%eax,4),%eax
testl %eax,%eax
je ret_from_sys_call
movl _current,%ebx
andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
movl $0,errno(%ebx)
movl %db6,%edx
movl %edx,dbgreg6(%ebx) # save current hardware debugging status
testb $0x20,flags(%ebx) # PF_TRACESYS
jne 1f
call *%eax
movl %eax,EAX(%esp) # save the return value
movl errno(%ebx),%edx
negl %edx
je ret_from_sys_call
movl %edx,EAX(%esp)
orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
jmp ret_from_sys_call
.align 4
1: call _syscall_trace
movl ORIG_EAX(%esp),%eax
call _sys_call_table(,%eax,4)
movl %eax,EAX(%esp) # save the return value
movl _current,%eax
movl errno(%eax),%edx
negl %edx
je 1f
movl %edx,EAX(%esp)
orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
1: call _syscall_trace
.align 4,0x90
ret_from_sys_call:
cmpl $0,_intr_count
jne 2f
9: movl _bh_mask,%eax
andl _bh_active,%eax
jne handle_bottom_half
movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
testl $(VM_MASK),%eax # different then
jne 1f
cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ?
je 2f
1: sti
orl $(IF_MASK),%eax # these just try to make sure
andl $~NT_MASK,%eax # the program doesn't do anything
movl %eax,EFLAGS(%esp) # stupid
cmpl $0,_need_resched
jne reschedule
movl _current,%eax
cmpl _task,%eax # task[0] cannot have signals
je 2f
cmpl $0,state(%eax) # state
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
movl blocked(%eax),%ecx
movl %ecx,%ebx # save blocked in %ebx for signal handling
notl %ecx
andl signal(%eax),%ecx
jne signal_return
2: RESTORE_ALL
.align 4
signal_return:
movl %esp,%ecx
pushl %ecx
testl $(VM_MASK),EFLAGS(%ecx)
jne v86_signal_return
pushl %ebx
call _do_signal
popl %ebx
popl %ebx
RESTORE_ALL
.align 4
v86_signal_return:
call _save_v86_state
movl %eax,%esp
pushl %eax
pushl %ebx
call _do_signal
popl %ebx
popl %ebx
RESTORE_ALL
.align 4
_divide_error:
pushl $0 # no error code
pushl $_do_divide_error
.align 4,0x90
error_code:
push %fs
push %es
push %ds
pushl %eax
pushl %ebp
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
movl $0,%eax
movl %eax,%db7 # disable hardware debugging...
cld
movl $-1, %eax
xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
xorl %ebx,%ebx # zero ebx
mov %gs,%bx # get the lower order bits of gs
xchgl %ebx, GS(%esp) # get the address and save gs.
pushl %eax # push the error code
lea 4(%esp),%edx
pushl %edx
movl $(KERNEL_DS),%edx
mov %dx,%ds
mov %dx,%es
movl $(USER_DS),%edx
mov %dx,%fs
pushl %eax
movl _current,%eax
movl %db6,%edx
movl %edx,dbgreg6(%eax) # save current hardware debugging status
popl %eax
call *%ebx
addl $8,%esp
jmp ret_from_sys_call
.align 4
_coprocessor_error:
pushl $0
pushl $_do_coprocessor_error
jmp error_code
.align 4
_device_not_available:
pushl $-1 # mark this as an int
SAVE_ALL
pushl $ret_from_sys_call
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
je _math_state_restore
pushl $0 # temporary storage for ORIG_EIP
call _math_emulate
addl $4,%esp
ret
.align 4
_debug:
pushl $0
pushl $_do_debug
jmp error_code
.align 4
_nmi:
pushl $0
pushl $_do_nmi
jmp error_code
.align 4
_int3:
pushl $0
pushl $_do_int3
jmp error_code
.align 4
_overflow:
pushl $0
pushl $_do_overflow
jmp error_code
.align 4
_bounds:
pushl $0
pushl $_do_bounds
jmp error_code
.align 4
_invalid_op:
pushl $0
pushl $_do_invalid_op
jmp error_code
.align 4
_coprocessor_segment_overrun:
pushl $0
pushl $_do_coprocessor_segment_overrun
jmp error_code
.align 4
_reserved:
pushl $0
pushl $_do_reserved
jmp error_code
.align 4
_double_fault:
pushl $_do_double_fault
jmp error_code
.align 4
_invalid_TSS:
pushl $_do_invalid_TSS
jmp error_code
.align 4
_segment_not_present:
pushl $_do_segment_not_present
jmp error_code
.align 4
_stack_segment:
pushl $_do_stack_segment
jmp error_code
.align 4
_general_protection:
pushl $_do_general_protection
jmp error_code
.align 4
_alignment_check:
pushl $_do_alignment_check
jmp error_code
.align 4
_page_fault:
pushl $_do_page_fault
jmp error_code
.data
.align 4
_sys_call_table:
.long _sys_setup /* 0 */
.long _sys_exit
.long _sys_fork
.long _sys_read
.long _sys_write
.long _sys_open /* 5 */
.long _sys_close
.long _sys_waitpid
.long _sys_creat
.long _sys_link
.long _sys_unlink /* 10 */
.long _sys_execve
.long _sys_chdir
.long _sys_time
.long _sys_mknod
.long _sys_chmod /* 15 */
.long _sys_chown
.long _sys_break
.long _sys_stat
.long _sys_lseek
.long _sys_getpid /* 20 */
.long _sys_mount
.long _sys_umount
.long _sys_setuid
.long _sys_getuid
.long _sys_stime /* 25 */
.long _sys_ptrace
.long _sys_alarm
.long _sys_fstat
.long _sys_pause
.long _sys_utime /* 30 */
.long _sys_stty
.long _sys_gtty
.long _sys_access
.long _sys_nice
.long _sys_ftime /* 35 */
.long _sys_sync
.long _sys_kill
.long _sys_rename
.long _sys_mkdir
.long _sys_rmdir /* 40 */
.long _sys_dup
.long _sys_pipe
.long _sys_times
.long _sys_prof
.long _sys_brk /* 45 */
.long _sys_setgid
.long _sys_getgid
.long _sys_signal
.long _sys_geteuid
.long _sys_getegid /* 50 */
.long _sys_acct
.long _sys_phys
.long _sys_lock
.long _sys_ioctl
.long _sys_fcntl /* 55 */
.long _sys_mpx
.long _sys_setpgid
.long _sys_ulimit
.long _sys_olduname
.long _sys_umask /* 60 */
.long _sys_chroot
.long _sys_ustat
.long _sys_dup2
.long _sys_getppid
.long _sys_getpgrp /* 65 */
.long _sys_setsid
.long _sys_sigaction
.long _sys_sgetmask
.long _sys_ssetmask
.long _sys_setreuid /* 70 */
.long _sys_setregid
.long _sys_sigsuspend
.long _sys_sigpending
.long _sys_sethostname
.long _sys_setrlimit /* 75 */
.long _sys_getrlimit
.long _sys_getrusage
.long _sys_gettimeofday
.long _sys_settimeofday
.long _sys_getgroups /* 80 */
.long _sys_setgroups
.long _sys_select
.long _sys_symlink
.long _sys_lstat
.long _sys_readlink /* 85 */
.long _sys_uselib
.long _sys_swapon
.long _sys_reboot
.long _sys_readdir
.long _sys_mmap /* 90 */
.long _sys_munmap
.long _sys_truncate
.long _sys_ftruncate
.long _sys_fchmod
.long _sys_fchown /* 95 */
.long _sys_getpriority
.long _sys_setpriority
.long _sys_profil
.long _sys_statfs
.long _sys_fstatfs /* 100 */
.long _sys_ioperm
.long _sys_socketcall
.long _sys_syslog
.long _sys_setitimer
.long _sys_getitimer /* 105 */
.long _sys_newstat
.long _sys_newlstat
.long _sys_newfstat
.long _sys_uname
.long _sys_iopl /* 110 */
.long _sys_vhangup
.long _sys_idle
.long _sys_vm86
.long _sys_wait4
.long _sys_swapoff /* 115 */
.long _sys_sysinfo
.long _sys_ipc
.long _sys_fsync
.long _sys_sigreturn
.long _sys_clone /* 120 */
.long _sys_setdomainname
.long _sys_newuname
.long _sys_modify_ldt
.long _sys_adjtimex
.long _sys_mprotect /* 125 */
.long _sys_sigprocmask
.long _sys_create_module
.long _sys_init_module
.long _sys_delete_module
.long _sys_get_kernel_syms /* 130 */
.long _sys_quotactl
.long _sys_getpgid
.long _sys_fchdir
.long _sys_bdflush
.long _sys_sysfs /* 135 */
.long _sys_personality
.long 0 /* for afs_syscall */
.long _sys_setfsuid
.long _sys_setfsgid
.long _sys_llseek /* 140 */
.space (NR_syscalls-139)*4
.space (NR_syscalls-140)*4
......@@ -2035,7 +2035,7 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
dma_channel = cdu31a_addresses[i].dma_num;
if (dma_channel > 0)
{
if (request_dma(dma_channel))
if (request_dma(dma_channel,"cdu31a"))
{
dma_channel = -1;
printk("Unable to grab DMA%d for the CDU31A driver\n",
......
......@@ -280,8 +280,8 @@ static struct floppy_struct floppy_type[32] = {
{ 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */
{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x6C,"d880" }, /* 20 880KB 5.25" */
{ 2080,13,2,80,0,0x1C,0x0A,0xCF,0x6C,"D1040" }, /* 21 1.04MB 3.5" */
{ 2240,14,2,80,0,0x1C,0x1A,0xCF,0x6C,"D1120" }, /* 22 1.12MB 3.5" */
{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x6C,"D1040" }, /* 21 1.04MB 3.5" */
{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x6C,"D1120" }, /* 22 1.12MB 3.5" */
{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x6C,"h1600" }, /* 23 1.6MB 5.25" */
{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x6C,"H1760" }, /* 24 1.76MB 3.5" */
{ 3840,24,2,80,0,0x1C,0x18,0xCF,0x6C,"H1920" }, /* 25 1.92MB 3.5" */
......@@ -290,7 +290,7 @@ static struct floppy_struct floppy_type[32] = {
{ 7680,48,2,80,0,0x25,0x63,0xCF,0x6C,"E3840" }, /* 28 3.84MB 3.5" */
{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x6C,"H1840" }, /* 29 1.84MB 3.5" */
{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"H800" }, /* 30 800KB 3.5" */
{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */
{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x6C,"H1600" }, /* 31 1.6MB 3.5" */
};
......@@ -2923,7 +2923,8 @@ void floppy_init(void)
#if N_FDC > 1
fdc_state[1].address = 0x370;
#endif
for(fdc = 0 ; fdc < N_FDC; fdc++){
for (i = 0 ; i < N_FDC ; i++) {
fdc = i;
FDCS->dtr = -1;
FDCS->dor = 0;
FDCS->reset = 0;
......@@ -2932,8 +2933,9 @@ void floppy_init(void)
}
/* initialise drive state */
for ( current_drive=0; current_drive < N_DRIVE ; current_drive++){
DRS->flags = 0;
for (i = 0; i < N_DRIVE ; i++) {
current_drive = i;
DRS->flags = FD_VERIFY;
DRS->generation = 0;
DRS->keep_data = 0;
DRS->fd_ref = 0;
......@@ -2941,7 +2943,8 @@ void floppy_init(void)
}
floppy_grab_irq_and_dma();
for(fdc = 0 ; fdc < N_FDC; fdc++){
for (i = 0 ; i < N_FDC ; i++) {
fdc = i;
FDCS->rawcmd = 2;
if(user_reset_fdc(-1,FD_RESET_IF_NEEDED))
continue;
......@@ -2980,7 +2983,7 @@ int floppy_grab_irq_and_dma(void)
FLOPPY_IRQ);
return -1;
}
if (request_dma(FLOPPY_DMA)) {
if (request_dma(FLOPPY_DMA,"floppy")) {
printk(DEVICE_NAME
": Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA);
......
......@@ -35,6 +35,7 @@
#include <linux/genhd.h>
#include <linux/config.h>
#include <linux/malloc.h>
#include <linux/string.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
......@@ -234,16 +235,39 @@ static unsigned int mult_req [MAX_HD] = {0,}; /* requested MultMode count
static unsigned int mult_count [MAX_HD] = {0,}; /* currently enabled MultMode count */
static struct request WCURRENT;
static void rawstring (char *prefix, unsigned char *s, int n)
static void fixstring(unsigned char *s, int n)
{
if (prefix)
printk(prefix);
if (s && *s) {
int i;
for (i=0; i < n && s[i^1] == ' '; ++i); /* skip blanks */
for (; i < n && s[i^1]; ++i) /* flip bytes */
if (s[i^1] != ' ' || ((i+1) < n && s[(i+1)^1] != ' '))
printk("%c",s[i^1]);
unsigned short *ss = (unsigned short *) s;
/* convert from big-endian to little-endian */
for (i = n ; (i -= 2) >= 0 ; ss++)
*ss = (*ss >> 8) | (*ss << 8);
/* "strnlen()" */
for (i = 0 ; i < n ; i++) {
if (!s[i]) {
n = i;
break;
}
}
/* wipe out trailing spaces */
while (n > 0) {
if (s[n-1] != ' ')
break;
n--;
s[n] = '\0';
}
/* wipe out leading spaces */
if (*s == ' ') {
unsigned char *t = s;
while (n-- && *++s == ' ');
while (n-- >= 0) {
*t++ = *s;
*s++ = '\0';
}
}
}
......@@ -272,15 +296,21 @@ static void identify_intr(void)
hd_info[dev].head = id.cur_heads;
hd_info[dev].sect = id.cur_sectors;
}
printk (" hd%c: ", dev+'a');
rawstring(NULL, id.model, sizeof(id.model));
printk (", %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
id.cyls*id.heads*id.sectors/2048, id.buf_size/2,
hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect, id.max_multsect);
fixstring (id.serial_no, sizeof(id.serial_no));
fixstring (id.fw_rev, sizeof(id.fw_rev));
fixstring (id.model, sizeof(id.model));
printk (" hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
dev+'a', id.model, id.cyls*id.heads*id.sectors/2048,
id.buf_size/2, hd_info[dev].cyl, hd_info[dev].head,
hd_info[dev].sect, id.max_multsect);
/* save drive info for later query via HDIO_GETIDENTITY */
if (NULL != (hd_ident_info[dev] = (struct hd_driveid *)kmalloc(sizeof(id),GFP_ATOMIC)))
*hd_ident_info[dev] = id;
/* Quantum drives go weird at this point, so reset them! In */
/* fact, do a reset in any case in case we changed the geometry */
special_op[dev] += reset = 1;
/* flush remaining 384 (reserved/undefined) ID bytes: */
insw(HD_DATA,(char *)&id,sizeof(id)/2);
insw(HD_DATA,(char *)&id,sizeof(id)/2);
......@@ -335,7 +365,6 @@ static void reset_controller(void)
{
int i;
printk(KERN_DEBUG "HD-controller reset\n");
outb_p(4,HD_CMD);
for(i = 0; i < 1000; i++) nop();
outb(hd_info[0].ctl & 0x0f ,HD_CMD);
......@@ -361,12 +390,15 @@ static void reset_hd(void)
}
if (++i < NR_HD) {
if (unmask_intr[i]) {
printk("hd%c: disabled irq-unmasking\n",i+'a');
unmask_intr[i] = 0;
unmask_intr[i] = DEFAULT_UNMASK_INTR;
printk("hd%c: reset irq-unmasking to %d\n",i+'a',
DEFAULT_UNMASK_INTR);
}
if (mult_req[i] || mult_count[i]) {
printk("hd%c: disabled multiple mode\n",i+'a');
mult_req[i] = mult_count[i] = 0;
mult_count[i] = 0;
mult_req[i] = DEFAULT_MULT_COUNT;
printk("hd%c: reset multiple mode to %d\n",i+'a',
DEFAULT_MULT_COUNT);
}
hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
......@@ -399,7 +431,7 @@ static void bad_rw_intr(void)
if (!CURRENT)
return;
dev = MINOR(CURRENT->dev) >> 6;
dev = DEVICE_NR(CURRENT->dev);
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(0);
special_op[dev] += recalibrate[dev] = 1;
......@@ -607,10 +639,9 @@ static void hd_times_out(void)
{
DEVICE_INTR = NULL;
sti();
reset = 1;
if (!CURRENT)
return;
special_op [DEVICE_NR(CURRENT->dev)] ++;
special_op [DEVICE_NR(CURRENT->dev)] += reset = 1;
printk(KERN_DEBUG "HD timeout\n");
cli();
if (++CURRENT->errors >= MAX_ERRORS) {
......@@ -761,7 +792,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
if ((!inode) || (!inode->i_rdev))
return -EINVAL;
dev = MINOR(inode->i_rdev) >> 6;
dev = DEVICE_NR(inode->i_rdev);
if (dev >= NR_HD)
return -EINVAL;
switch (cmd) {
......@@ -877,7 +908,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
static int hd_open(struct inode * inode, struct file * filp)
{
int target;
target = DEVICE_NR(MINOR(inode->i_rdev));
target = DEVICE_NR(inode->i_rdev);
while (busy[target])
sleep_on(&busy_wait);
......@@ -894,7 +925,7 @@ static void hd_release(struct inode * inode, struct file * file)
int target;
sync_dev(inode->i_rdev);
target = DEVICE_NR(MINOR(inode->i_rdev));
target = DEVICE_NR(inode->i_rdev);
access_count[target]--;
}
......@@ -1073,7 +1104,7 @@ static int revalidate_hddisk(int dev, int maxusage)
int i;
long flags;
target = DEVICE_NR(MINOR(dev));
target = DEVICE_NR(dev);
gdev = &GENDISK_STRUCT;
save_flags(flags);
......
......@@ -189,6 +189,7 @@ void rd_load(void)
printk("Unable to grab floppy IRQ/DMA for loading ramdisk image\n");
return;
}
check_disk_change(ROOT_DEV);
do_load();
floppy_release_irq_and_dma();
}
......@@ -167,7 +167,7 @@ static void xd_geninit (void)
printk("xd_geninit: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors);
if (!request_irq(xd_irq,xd_interrupt_handler, 0, "XT harddisk")) {
if (request_dma(xd_dma)) {
if (request_dma(xd_dma,"xd")) {
printk("xd_geninit: unable to get DMA%d\n",xd_dma);
free_irq(xd_irq);
}
......
......@@ -2840,7 +2840,7 @@ static int qic02_get_resources(void)
}
/* After IRQ, allocate DMA channel */
if (request_dma(QIC02_TAPE_DMA)) {
if (request_dma(QIC02_TAPE_DMA,"QIC-02")) {
printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n",
QIC02_TAPE_DMA);
free_irq(QIC02_TAPE_IRQ);
......
......@@ -371,7 +371,7 @@ lance_open(struct device *dev)
return -EAGAIN;
}
if (request_dma(dev->dma)) {
if (request_dma(dev->dma,"lance")) {
free_irq(dev->irq);
return -EAGAIN;
}
......
......@@ -101,7 +101,7 @@ init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
*mem_startp += alloc_size;
} else
dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
memset(dev, 0, sizeof(alloc_size));
memset(dev, 0, alloc_size);
if (sizeof_private)
dev->priv = (void *) (dev + 1);
dev->name = sizeof_private + (char *)(dev + 1);
......
/*
* net-3-driver for the NI5210 card (i82586 Ethernet chip)
*
* This is an extension to the Linux operating system, and is covered by the
* same Gnu Public License that covers that work.
*
* Alphacode 0.51 (94/08/19) for Linux 1.1.47 (or later)
* Copyrights (c) 1994 by Michael Hipp (mhipp@student.uni-tuebingen.de)
* [feel free to mail ....]
*
* CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
*
* autoprobe for: base_addr: 0x300,0x280,0x360,0x320,0x340
* mem_start: 0xd0000,0xd4000,0xd8000 (8K and 16K)
*
* sources:
* skeleton.c from Donald Becker
*
* I have also done a look in the following sources: (mail me if you need them)
* crynwr-packet-driver by Russ Nelson
* Garret A. Wollman's (fourth) i82586-driver for BSD
* (before getting an i82596 manual, the existing drivers helped
* me a lot to understand this tricky chip.)
*
* Known Bugs:
* The internal sysbus seems to be slow. So we often lose packets because of
* overruns while receiving from a fast remote host.
* This can slow down TCP connections. Maybe the newer ni5210 cards are better.
*/
/*
* 19.Aug.94: changed request_irq() parameter (MH)
*
* 20.July.94: removed cleanup bugs, removed a 16K-mem-probe-bug (MH)
*
* 19.July.94: lotsa cleanups .. (MH)
*
* 17.July.94: some patches ... verified to run with 1.1.29 (MH)
*
* 4.July.94: patches for Linux 1.1.24 (MH)
*
* 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH)
*
* 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff, too (MH)
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "ni52.h"
#define DEBUG /* debug on */
/*
#define DEBUG1
#define DEBUG2
#define DEBUG3
*/
#define SYSBUSVAL 1
#define ni_attn586() {outb(0,dev->base_addr+NI52_ATTENTION);}
#define ni_reset586() {outb(0,dev->base_addr+NI52_RESET);}
#define make32(ptr16) (p->memtop + (short) (ptr16) )
#define make24(ptr32) ((char *) (ptr32) - p->base)
#define make16(ptr32) ((unsigned short) ((unsigned long) (ptr32) - (unsigned long) p->memtop ))
/******************* how to calc the buffers *****************************
IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, do also a
--------------- #define ONLY_ONE_XMIT_BUF
btw: it seems, that only the ONLY_ONE_XMIT_BUF Mode is stable
sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
sizeof(rfd) = 24; sizeof(rbd) = 12;
sizeof(tbd) = 8; sizeof(transmit_cmd) = 16;
sizeof(nop_cmd) = 8;
examples:
---------
->cfg1: NUM_RECV_FRAMES=16, NUM_RECV_BUFFS=48, RECV_BUFF_SIZE=256,
NUM_XMIT_BUFFS=2 ,XMIT_BUFF_SIZE=1514
NUM_RECV_FRAMES * sizeof(rfd) = 384;
NUM_RECV_BUFFS * ( sizeof(rbd) + RECV_BUFF_SIZE) = 12864
NUM_XMIT_BUFFS * ( sizeof(tbd+transmit_cmd+nop_cmd) + XMIT_BUFF_SIZE) = 3092
INIT = 36
--------------------
16358 (36 bytes left!)
************************
->cfg2: NUM_RECV_FRAMES=9, NUM_RECV_BUFFS=18, RECV_BUFF_SIZE=256,
NUM_XMIT_BUFFS=2 ,XMIT_BUFF_SIZE=1514
NUM_RECV_FRAMES * sizeof(rfd) = 216
NUM_RECV_BUFFS * ( sizeof(rbd) + RECV_BUFF_SIZE) = 4824
NUM_XMIT_BUFFS * ( sizeof(tbd+transmit_cmd+nop_cmd) + XMIT_BUFF_SIZE) = 3092
INIT = 36
------------------
8180 (24 bytes left!)
->cfg3: NUM_RECV_FRAMES=7, NUM_RECV_BUFFS=24, RECV_BUFF_SIZE=256,
NUM_XMIT_BUFFS=1, XMIT_BUFF_SIZE=1514
168 + 6432 + 1538 + 36 + 16 = 8190
***************************************************************************/
#if 0
/* config-1 for 16Kram card */
# define NUM_RECV_FRAMES 16 /* number of frames to allow for receive */
# define NUM_RECV_BUFFS 48 /* number of buffers to allocate */
# define RECV_BUFF_SIZE 256 /* size of each buffer, POWER OF 2 & EVEN*/
# define XMIT_BUFF_SIZE 1514 /* length of transmit buffer (EVEN) */
# define NUM_XMIT_BUFFS 2 /* number of Xmit-Buffs */
#elif 0
/* config-2 for 8Kram card */
# define NUM_RECV_FRAMES 9
# define NUM_RECV_BUFFS 18
# define RECV_BUFF_SIZE 256
# define XMIT_BUFF_SIZE 1514
# define NUM_XMIT_BUFFS 2
#elif 1
/*
* config-3 for 8Kram card ___use_this_config____ seems to be stable
*/
# define NUM_RECV_FRAMES 7
# define NUM_RECV_BUFFS 24
# define RECV_BUFF_SIZE 256
# define XMIT_BUFF_SIZE 1514
# define NUM_XMIT_BUFFS 1
# define ONLY_ONE_XMIT_BUF
# define NO_NOPCOMMANDS
#elif 0
/*
* cfg-4 for 16K, ONLY_ONE_XMIT_BUF
*/
# define NUM_RECV_FRAMES 20
# define NUM_RECV_BUFFS 27
# define RECV_BUFF_SIZE 512
# define XMIT_BUFF_SIZE 1514
# define NUM_XMIT_BUFFS 1
# define ONLY_ONE_XMIT_BUF
#else
# define NUM_RECV_FRAMES 4
# define NUM_RECV_BUFFS 4
# define RECV_BUFF_SIZE 1536
# define XMIT_BUFF_SIZE 1536
# define NUM_XMIT_BUFFS 1
# define ONLY_ONE_XMIT_BUF
# define NO_NOPCOMMANDS
#endif
#define DELAY(x) {int i=jiffies; \
if(loops_per_sec == 1) \
while(i+(x)>jiffies); \
else \
__delay((loops_per_sec>>5)*x); \
}
extern void autoirq_setup(int waittime);
extern int autoirq_report(int waittime);
extern void *irq2dev_map[16];
#ifndef HAVE_PORTRESERVE
#define check_region(ioaddr, size) 0
#define snarf_region(ioaddr, size); do ; while (0)
#endif
#define NI52_TOTAL_SIZE 16
#define NI52_ADDR0 0x02
#define NI52_ADDR1 0x07
#define NI52_ADDR2 0x01
static int ni52_probe1(struct device *dev,int ioaddr);
static void ni52_interrupt(int reg_ptr);
static int ni52_open(struct device *dev);
static int ni52_close(struct device *dev);
static int ni52_send_packet(struct sk_buff *,struct device *);
static struct enet_statistics *ni52_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
/* helper-functions */
static int init586(struct device *dev);
static int check586(struct device *dev,char *where,unsigned size);
static void alloc586(struct device *dev);
static void startrecv586(struct device *dev);
static void *alloc_rfa(struct device *dev,void *ptr);
static void ni52_rcv_int(struct device *dev);
static void ni52_xmt_int(struct device *dev);
static void ni52_rnr_int(struct device *dev);
struct priv
{
struct enet_statistics stats;
unsigned long base;
char *memtop,*max_cbuff32,*min_cbuff32,*max_cbuff24;
volatile struct rbd_struct *rbd_last;
volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first;
volatile struct scp_struct *scp; /* volatile is important */
volatile struct iscp_struct *iscp; /* volatile is important */
volatile struct scb_struct *scb; /* volatile is important */
volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS];
volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS];
#ifdef ONLY_ONE_XMIT_BUF
volatile struct nop_cmd_struct *nop_cmds[2];
#else
volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS];
#endif
volatile int nop_point;
volatile char *xmit_cbuffs[NUM_XMIT_BUFFS];
volatile int xmit_count,xmit_last;
};
/**********************************************
* close device
*/
static int ni52_close(struct device *dev)
{
free_irq(dev->irq);
irq2dev_map[dev->irq] = 0;
ni_reset586(); /* the hard way to stop the receiver */
dev->start = 0;
dev->tbusy = 0;
return 0;
}
/**********************************************
* open device
*/
static int ni52_open(struct device *dev)
{
alloc586(dev);
init586(dev);
startrecv586(dev);
if(request_irq(dev->irq, &ni52_interrupt,0,"ni52"))
{
ni_reset586();
return -EAGAIN;
}
irq2dev_map[dev->irq] = dev;
dev->interrupt = 0;
dev->tbusy = 0;
dev->start = 1;
return 0; /* most done by init */
}
/**********************************************
* Check to see if there's an 82586 out there.
*/
static int check586(struct device *dev,char *where,unsigned size)
{
struct priv *p = (struct priv *) dev->priv;
char *iscp_addrs[2];
int i;
p->base = (unsigned long) where + size - 0x01000000;
p->memtop = where + size;
p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS);
memset((char *)p->scp,0, sizeof(struct scp_struct));
p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus */
iscp_addrs[0] = where;
iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct);
for(i=0;i<2;i++)
{
p->iscp = (struct iscp_struct *) iscp_addrs[i];
memset((char *)p->iscp,0, sizeof(struct iscp_struct));
p->scp->iscp = make24(p->iscp);
p->iscp->busy = 1;
ni_reset586();
ni_attn586();
DELAY(2); /* wait a while... */
if(p->iscp->busy)
return 0;
}
return 1;
}
/******************************************************************
* set iscp at the right place, called by ni52_probe1 and open586.
*/
void alloc586(struct device *dev)
{
struct priv *p = (struct priv *) dev->priv;
p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS);
p->scb = (struct scb_struct *) (dev->mem_start);
p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct));
memset((char *) p->iscp,0,sizeof(struct iscp_struct));
memset((char *) p->scp ,0,sizeof(struct scp_struct));
p->scp->iscp = make24(p->iscp);
p->scp->sysbus = SYSBUSVAL;
p->iscp->scb_offset = make16(p->scb);
p->iscp->busy = 1;
ni_reset586();
ni_attn586();
#ifdef DEBUG
DELAY(2);
if(p->iscp->busy)
printk("%s: Init-Problems (alloc).\n",dev->name);
#endif
memset((char *)p->scb,0,sizeof(struct scb_struct));
}
/**********************************************
* probe the ni5210-card
*/
int ni52_probe(struct device *dev)
{
int *port, ports[] = {0x300, 0x280, 0x360 , 0x320 , 0x340, 0};
int base_addr = dev->base_addr;
if (base_addr > 0x1ff) /* Check a single specified location. */
if( (inb(base_addr+NI52_MAGIC1) == NI52_MAGICVAL1) &&
(inb(base_addr+NI52_MAGIC2) == NI52_MAGICVAL2))
return ni52_probe1(dev, base_addr);
else if (base_addr > 0) /* Don't probe at all. */
return ENXIO;
for (port = ports; *port; port++) {
int ioaddr = *port;
if (check_region(ioaddr, NI52_TOTAL_SIZE))
continue;
if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) ||
!(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2))
continue;
dev->base_addr = ioaddr;
if (ni52_probe1(dev, ioaddr) == 0)
return 0;
}
dev->base_addr = base_addr;
return ENODEV;
}
static int ni52_probe1(struct device *dev,int ioaddr)
{
long memaddrs[] = { 0xd0000,0xd2000,0xd4000,0xd6000,0xd8000, 0 };
int i,size;
for(i=0;i<ETH_ALEN;i++)
dev->dev_addr[i] = inb(dev->base_addr+i);
if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1
|| dev->dev_addr[2] != NI52_ADDR2)
return ENODEV;
printk("%s: Ni52 found at %#3x, ",dev->name,dev->base_addr);
snarf_region(ioaddr,NI52_TOTAL_SIZE);
dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
/* warning: we don't free it on errors */
memset((char *) dev->priv,0,sizeof(struct priv));
/*
* check (or search) IO-Memory, 8K and 16K
*/
if(dev->mem_start != 0) /* no auto-mem-probe */
{
size = 0x4000;
if(!check586(dev,(char *) dev->mem_start,size)) {
size = 0x2000;
if(!check586(dev,(char *) dev->mem_start,size)) {
printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start);
return ENODEV;
}
}
}
else
{
for(i=0;;i++)
{
if(!memaddrs[i]) {
printk("?memprobe, Can't find io-memory!\n");
return ENODEV;
}
dev->mem_start = memaddrs[i];
size = 0x2000;
if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */
break;
size = 0x4000;
if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */
break;
}
}
((struct priv *) (dev->priv))->base = dev->mem_start + size - 0x01000000;
alloc586(dev);
printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size);
if(dev->irq < 2)
{
autoirq_setup(0);
ni_reset586();
ni_attn586();
if(!(dev->irq = autoirq_report(2)))
{
printk("?autoirq, Failed to detect IRQ line!\n");
return 1;
}
}
else if(dev->irq == 2)
dev->irq = 9;
printk("IRQ %d.\n",dev->irq);
dev->open = &ni52_open;
dev->stop = &ni52_close;
dev->get_stats = &ni52_get_stats;
dev->hard_start_xmit = &ni52_send_packet;
dev->set_multicast_list = &set_multicast_list;
dev->if_port = 0;
ether_setup(dev);
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 0;
return 0;
}
/**********************************************
* init the chip (ni52-interrupt should be disabled?!)
* needs a correct 'allocated' memory
*/
static int init586(struct device *dev)
{
void *ptr;
unsigned long s;
int i,result=0;
struct priv *p = (struct priv *) dev->priv;
volatile struct configure_cmd_struct *cfg_cmd;
volatile struct iasetup_cmd_struct *ias_cmd;
volatile struct tdr_cmd_struct *tdr_cmd;
ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct));
cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */
cfg_cmd->byte_cnt = 0x04; /* number of cfg bytes */
cfg_cmd->fifo = 0xc8; /* fifo-limit (8=tx:32/rx:64) | monitor */
cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
cfg_cmd->cmd_status = 0;
cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST;
cfg_cmd->cmd_link = 0xffff;
p->scb->cbl_offset = make16(cfg_cmd);
p->scb->cmd = CUC_START; /* cmd.-unit start */
ni_attn586();
s = jiffies; /* warning: only active with interrupts on !! */
while(!(cfg_cmd->cmd_status & STAT_COMPL))
if(jiffies-s > 30) break;
if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK))
{
printk("%s (ni52): configure command failed: %x\n",dev->name,cfg_cmd->cmd_status);
return 1;
}
/*
* individual address setup
*/
ias_cmd = (struct iasetup_cmd_struct *)ptr;
ias_cmd->cmd_status = 0;
ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST;
ias_cmd->cmd_link = 0xffff;
memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN);
p->scb->cbl_offset = make16(ias_cmd);
p->scb->cmd = CUC_START; /* cmd.-unit start */
ni_attn586();
s = jiffies;
while(!(ias_cmd->cmd_status & STAT_COMPL))
if(jiffies-s > 30) break;
if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) {
printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status);
return 1;
}
/*
* TDR, wire check .. e.g. no resistor e.t.c
*/
tdr_cmd = (struct tdr_cmd_struct *)ptr;
tdr_cmd->cmd_status = 0;
tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST;
tdr_cmd->cmd_link = 0xffff;
tdr_cmd->status = 0;
p->scb->cbl_offset = make16(tdr_cmd);
p->scb->cmd = CUC_START; /* cmd.-unit start */
ni_attn586();
s = jiffies;
while(!(tdr_cmd->cmd_status & STAT_COMPL))
if(jiffies - s > 30) {
printk("%s: Problems while running the TDR.\n",dev->name);
result = 1;
}
if(!result)
{
DELAY(2); /* wait for result */
result = tdr_cmd->status;
p->scb->cmd = p->scb->status & STAT_MASK;
ni_attn586(); /* ack the interrupts */
if(result & TDR_LNK_OK) ;
else if(result & TDR_XCVR_PRB)
printk("%s: TDR: Transceiver problem!\n",dev->name);
else if(result & TDR_ET_OPN)
printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
else if(result & TDR_ET_SRT)
{
if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */
printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK);
}
else
printk("%s: TDR: Unknown status %04x\n",dev->name,result);
}
/*
* ack interrupts
*/
p->scb->cmd = p->scb->status & STAT_MASK;
ni_attn586();
/*
* alloc nop/xmit-cmds
*/
#ifdef ONLY_ONE_XMIT_BUF
for(i=0;i<2;i++)
{
p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
p->nop_cmds[i]->cmd_cmd = 0;
p->nop_cmds[i]->cmd_status = 0;
p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
ptr += sizeof(struct nop_cmd_struct);
}
p->xmit_cmds[0] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */
ptr += sizeof(struct transmit_cmd_struct);
#else
for(i=0;i<NUM_XMIT_BUFFS;i++)
{
p->nop_cmds[i] = (struct nop_cmd_struct *)ptr;
p->nop_cmds[i]->cmd_cmd = 0;
p->nop_cmds[i]->cmd_status = 0;
p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i]));
ptr += sizeof(struct nop_cmd_struct);
p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /* transmit cmd/buff 0 */
ptr += sizeof(struct transmit_cmd_struct);
}
#endif
ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */
/*
* alloc xmit-buffs
*/
for(i=0;i<NUM_XMIT_BUFFS;i++)
{
p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */
ptr += XMIT_BUFF_SIZE;
p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */
ptr += sizeof(struct tbd_struct);
if((void *)ptr > (void *)p->iscp)
{
printk("%s: not enough shared-mem for your configuration!\n",dev->name);
return 1;
}
memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct));
memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct));
p->xmit_cmds[i]->cmd_status = STAT_COMPL;
p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i]));
p->xmit_buffs[i]->next = 0xffff;
p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i]));
}
p->xmit_count = 0;
p->xmit_last = 0;
#ifndef NO_NOPCOMMANDS
p->nop_point = 0;
#endif
/*
* 'start transmitter' (nop-loop)
*/
#ifndef NO_NOPCOMMANDS
p->scb->cbl_offset = make16(p->nop_cmds[0]);
p->scb->cmd = CUC_START;
ni_attn586();
while(p->scb->cmd);
#else
/*
p->nop_cmds[0]->cmd_link = make16(p->nop_cmds[1]);
p->nop_cmds[1]->cmd_link = make16(p->xmit_cmds[0]);
*/
p->xmit_cmds[0]->cmd_link = 0xffff;
p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_LAST | CMD_INT;
#endif
return 0;
}
/******************************************************
* This is a helper routine for ni52_nr_int() and init586().
* It sets up the Receive Frame Area (RFA).
*/
static void *alloc_rfa(struct device *dev,void *ptr)
{
volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr;
volatile struct rbd_struct *rbd;
int i;
struct priv *p = (struct priv *) dev->priv;
memset((char *) rfd,0,sizeof(struct rfd_struct)*NUM_RECV_FRAMES);
p->rfd_first = rfd;
for(i = 0; i < NUM_RECV_FRAMES; i++)
rfd[i].next = make16(rfd + (i+1) % NUM_RECV_FRAMES);
rfd[NUM_RECV_FRAMES-1].last = RFD_LAST; /* set EOL (no RU suspend) */
ptr = (char *) (rfd + NUM_RECV_FRAMES);
rbd = (struct rbd_struct *) ptr;
ptr += sizeof(struct rbd_struct)*NUM_RECV_BUFFS;
/* clr descriptors */
memset((char *) rbd,0,sizeof(struct rbd_struct)*NUM_RECV_BUFFS);
p->min_cbuff32 = ptr;
for(i=0;i<NUM_RECV_BUFFS;i++)
{
rbd[i].next = make16((rbd + (i+1) % NUM_RECV_BUFFS));
rbd[i].size = RECV_BUFF_SIZE;
rbd[i].buffer = make24(ptr);
ptr += RECV_BUFF_SIZE;
}
rbd[NUM_RECV_BUFFS-1].size |= RBD_LAST; /* set eol */
p->max_cbuff32 = ptr;
p->max_cbuff24 = make24(p->max_cbuff32);
p->rfd_top = p->rfd_first;
p->rfd_last = p->rfd_first + NUM_RECV_FRAMES - 1;
p->rbd_last = rbd + NUM_RECV_BUFFS - 1;
p->scb->rfa_offset = make16(p->rfd_first);
p->rfd_first->rbd_offset = make16(rbd);
return ptr;
}
/**************************************************
* Interrupt Handler ...
*/
static void ni52_interrupt(int reg_ptr)
{
struct device *dev = (struct device *) irq2dev_map[-((struct pt_regs *)reg_ptr)->orig_eax-2];
unsigned short stat;
int pd = 0;
struct priv *p;
#ifdef DEBUG2
printk("(1)");
#endif
if (dev == NULL) {
printk ("ni52-interrupt: irq %d for unknown device.\n",(int) -(((struct pt_regs *)reg_ptr)->orig_eax+2));
return;
}
p = (struct priv *) dev->priv;
if(dev->interrupt)
{
printk("(ni52-I)");
return;
}
dev->interrupt = 1;
while((stat=p->scb->status & STAT_MASK))
{
p->scb->cmd = stat;
ni_attn586(); /* ack inter. */
if(pd)
printk("ni52-%04x/%04x-",(int) stat,(int) p->scb->status); /* debug */
if(stat & (STAT_FR | STAT_RNR))
ni52_rcv_int(dev);
if(stat & STAT_CX)
ni52_xmt_int(dev);
#ifndef NO_NOPCOMMANDS
if(stat & STAT_CNA)
#else
if( (stat & STAT_CNA) && !(stat & STAT_CX) )
#endif
printk("%s: oops! CU has left active state. stat: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status);
if(stat & STAT_RNR)
{
printk("%s: rnr: %04x/%04x.\n",dev->name,(int) stat,(int) p->scb->status);
ni52_rnr_int(dev);
pd = 1; /* local debug on */
}
#ifdef DEBUG2
pd++;
#endif
while(p->scb->cmd)
{
int i; /* wait for ack. (ni52_xmt_int can be faster than ack!!) */
for(i=0;i<200;i++);
}
}
#ifdef DEBUG
{
static int old_ovr=0;
int l;
if((l = p->scb->ovrn_errs - old_ovr))
{
if(l > 0)
p->stats.rx_over_errors += l;
else
old_ovr=0;
}
}
#endif
#ifdef DEBUG2
printk("(2)");
#endif
dev->interrupt = 0;
}
/*******************************************************
* receive-interrupt
*/
static void ni52_rcv_int(struct device *dev)
{
int status;
unsigned short totlen,pnt;
struct sk_buff *skb;
struct rbd_struct *rbd,*rbd_first;
struct priv *p = (struct priv *) dev->priv;
for(;(status = p->rfd_top->status) & STAT_COMPL;)
{
rbd = rbd_first = (struct rbd_struct *) make32(p->rfd_top->rbd_offset);
#ifdef DEBUG1
{
struct rbd_struct *rbd1 = rbd;
if(rbd1==p->rbd_last)
printk("L");
printk("S:%04x/%x/%02x >",(int) rbd1->status,(int) rbd1->size>>12,(int)((unsigned long) rbd1 & 0xff));
rbd1 = (struct rbd_struct *) make32(rbd1->next);
for(;rbd1 != rbd_first;rbd1 = (struct rbd_struct *) make32(rbd1->next))
{
if(rbd1 == p->rbd_last)
printk("L:");
printk("%04x/%x-",(int) rbd1->status>>12,(int) rbd1->size>>12);
}
printk("< ");
}
{
struct rfd_struct *rfd1 = p->rfd_top;
if(rfd1==p->rfd_last)
printk("L");
printk("S:%04x/%x/%02x >",(int) rfd1->status,(int) rfd1->last>>12,(int)((unsigned long) rfd1 & 0xff));
rfd1 = (struct rfd_struct *) make32(rfd1->next);
for(;rfd1 != p->rfd_top;rfd1 = (struct rfd_struct *) make32(rfd1->next))
{
if(rfd1 == p->rfd_last)
printk("L:");
printk("%x/%x-",(int) rfd1->status>>12,(int) rfd1->last>>12);
}
printk("<\n");
}
#endif
p->rfd_top->status = 0;
p->rfd_top->last = RFD_LAST;
p->rfd_last->last = 0; /* delete RFD_LAST, no RU suspend */
p->rfd_last = p->rfd_top;
p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next);
if(status & RFD_ERRMASK)
printk("%s: RFD-Error ... status: %04x.\n",dev->name,status);
if(status & STAT_OK)
{
for(totlen=0; !(rbd->status & RBD_LAST); rbd=(struct rbd_struct *) make32(rbd->next)) {
totlen += RECV_BUFF_SIZE;
rbd->status = 0;
}
totlen += rbd->status & RBD_MASK;
rbd->status = 0;
skb = (struct sk_buff *) alloc_skb(totlen, GFP_ATOMIC);
if (skb != NULL) /* copy header */
{
skb->len = totlen;
skb->dev = dev;
if(rbd->buffer < rbd_first->buffer)
{
pnt = p->max_cbuff24 - rbd_first->buffer;
memcpy( (char *) skb->data,p->max_cbuff32-pnt,pnt);
memcpy( (char *) skb->data+pnt,p->min_cbuff32,totlen-pnt);
}
else
memcpy( (char *) skb->data,(char *) p->base+(unsigned long) rbd_first->buffer, totlen);
rbd->size |= RBD_LAST;
p->rbd_last->size &= ~RBD_LAST;
p->rbd_last = rbd;
netif_rx(skb);
p->stats.rx_packets++;
}
else
{
rbd->size |= RBD_LAST;
p->rbd_last->size &= ~RBD_LAST;
p->rbd_last = rbd;
}
}
else /* frame !(ok), only with 'save-bad-frames' */
{
printk("%s: oops! rfd-error-status: %04x\n",dev->name,status);
p->stats.rx_errors++;
}
}
}
/**********************************************************
* I never got this error , (which should occure if someone
* wants to blast your machine) so I couldn't debug it for now.
* but we _try_ to fix the receiver not ready int.
*/
static void ni52_rnr_int(struct device *dev)
{
struct priv *p = (struct priv *) dev->priv;
p->stats.rx_errors++;
while(p->scb->cmd); /* wait for the last cmd */
p->scb->cmd = RUC_ABORT;
ni_attn586();
while(p->scb->cmd); /* wait for accept cmd. */
alloc_rfa(dev,(char *)p->rfd_first);
startrecv586(dev); /* restart */
}
/**********************************************************
* handle xmit - interrupt
*/
static void ni52_xmt_int(struct device *dev)
{
int status;
struct priv *p = (struct priv *) dev->priv;
/*
if(!(p->xmit_cmds[0]->cmd_status & STAT_COMPL))
return;
*/
if( (status=p->xmit_cmds[p->xmit_last]->cmd_status) & STAT_OK)
{
p->stats.tx_packets++;
p->stats.collisions += (status & TCMD_MAXCOLLMASK);
dev->tbusy = 0;
mark_bh(NET_BH);
}
else
{
p->stats.tx_errors++;
if(status & TCMD_LATECOLL) {
printk("%s: late collision detected.\n",dev->name);
p->stats.collisions++;
}
else if(status & TCMD_NOCARRIER) {
p->stats.tx_carrier_errors++;
printk("%s: no carrier detected.\n",dev->name);
}
else if(status & TCMD_LOSTCTS)
printk("%s: loss of CTS detected.\n",dev->name);
else if(status & TCMD_UNDERRUN) {
printk("%s: DMA underrun detected.\n",dev->name);
}
else if(status & TCMD_MAXCOLL) {
printk("%s: Max. collisions exceeded.\n",dev->name);
p->stats.collisions += 16;
}
}
#ifndef ONLY_ONE_XMIT_BUF
if( (++p->xmit_last) == NUM_XMIT_BUFFS)
p->xmit_last = 0;
#endif
}
/***********************************************************
* (re)start the receiver
*/
static void startrecv586(struct device *dev)
{
struct priv *p = (struct priv *) dev->priv;
p->scb->rfa_offset = make16(p->rfd_first);
p->scb->cmd = RUC_START;
ni_attn586(); /* start cmd. */
while(p->scb->cmd); /* wait for accept cmd. (no timeout!!) */
DELAY(2); /* isn't necess. */
p->scb->cmd = p->scb->status & STAT_MASK;
ni_attn586(); /* ack interr */
}
/******************************************************
* send frame
*/
static int ni52_send_packet(struct sk_buff *skb, struct device *dev)
{
int len;
#ifndef NO_NOPCOMMANDS
int next_nop;
#endif
struct priv *p = (struct priv *) dev->priv;
if(dev->tbusy)
{
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 30)
return 1;
#ifdef DEBUG
printk("%s: xmitter timed out, try to restart! stat: %04x\n",dev->name,p->scb->status);
printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status);
#endif
ni52_close(dev);
ni52_open(dev);
dev->trans_start = jiffies;
}
if(skb == NULL)
{
dev_tint(dev);
return 0;
}
if (skb->len <= 0)
return 0;
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
else
{
memcpy((char *)p->xmit_cbuffs[p->xmit_count],(char *)(skb->data),skb->len);
len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
#ifdef ONLY_ONE_XMIT_BUF
# ifdef NO_NOPCOMMANDS
p->xmit_buffs[0]->size = TBD_LAST | len;
p->xmit_cmds[0]->cmd_status = 0;
p->scb->cbl_offset = make16(p->xmit_cmds[0]);
p->scb->cmd = CUC_START;
dev->trans_start = jiffies;
ni_attn586();
while(p->scb->cmd)
for(len=0;len<256;len++);
/* DELAY(1); */ /* TEST;TEST;TEST */
# else
next_nop = (p->nop_point + 1) & 0x1;
p->xmit_buffs[0]->size = TBD_LAST | len;
p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_INT;
p->xmit_cmds[0]->cmd_status = 0;
p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
= make16((p->nop_cmds[next_nop]));
p->nop_cmds[next_nop]->cmd_status = 0;
p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0]));
dev->trans_start = jiffies;
p->nop_point = next_nop;
# endif
#else
p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len;
if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS )
next_nop = 0;
p->xmit_cmds[p->xmit_count]->cmd_cmd = CMD_XMIT | CMD_INT;
p->xmit_cmds[p->xmit_count]->cmd_status = 0;
p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link
= make16((p->nop_cmds[next_nop]));
p->nop_cmds[next_nop]->cmd_status = 0;
p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count]));
dev->trans_start = jiffies;
p->xmit_count = next_nop;
cli();
if(p->xmit_count != p->xmit_last)
dev->tbusy = 0;
sti();
#endif
}
dev_kfree_skb(skb,FREE_WRITE);
return 0;
}
static struct enet_statistics *ni52_get_stats(struct device *dev)
{
struct priv *p = (struct priv *) dev->priv;
#ifdef DEBUG3
printk("ni52: errs, crc %d, align %d, ressource %d, ovrn %d.\n",(int) p->scb->crc_errs,(int) p->scb->aln_errs,(int) p->scb->rsc_errs,(int) p->scb->ovrn_errs);
#endif
return &p->stats;
}
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
/*
struct priv *p = (struct priv *) dev->priv;
volatile struct configure_cmd_struct *cfg_cmd;
*/
if(!num_addrs)
printk("%s: Currently, the Ni52 driver doesn't support promiscous or multicast mode.\n",dev->name);
#if 0
p->scb->cmd = CUC_SUSPEND;
ni_attn586();
while(p->scb->cmd);
p->scb->cmd = RUC_SUSPEND;
ni_attn586();
while(p->scb->cmd);
cfg_cmd = (struct configure_cmd_struct *) p->xmit_cbuffs[0]; /* we're using a transmitcommand */
cfg_cmd->cmd_status = 0;
cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST;
cfg_cmd->cmd_link = 0xffff;
cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */
cfg_cmd->fifo = 0x08; /* fifo-limit (8=tx:32/rx:64) */
cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */
cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */
cfg_cmd->priority = 0x00;
cfg_cmd->ifd = 0x60;
cfg_cmd->time_low = 0x00;
cfg_cmd->time_high = 0xf2;
cfg_cmd->promisc = 0x01; /* promisc on */
cfg_cmd->carr_coll = 0x00;
p->scb->cbl_offset = make16(cfg_cmd);
p->scb->cmd = CUC_START; /* cmd.-unit start */
ni_attn586();
while(p->scb->cmd);
p->scb->cbl_offset = p->nop_cmds[0]->cmd_link = make16(p->nop_cmds[0]);
p->scb->cmd = CUC_START;
ni_atthn586();
while(p->scb->cmd);
p->scb->cmd = RUC_RESUME;
ni_atthn586();
while(p->scb->cmd);
#endif
}
/*
* Intel i82586 Ethernet definitions
*
* This is an extension to the Linux operating system, and is covered by the
* same Gnu Public License that covers that work.
*
* copyrights (c) 1994 by Michael Hipp (mhipp@student.uni-tuebingen.de)
*
* I have done a look in the following sources:
* crynwr-packet-driver by Russ Nelson
* Garret A. Wollman's i82586-driver for BSD
*/
#define NI52_RESET 0 /* writing to this address, resets the i82586 */
#define NI52_ATTENTION 1 /* channel attention, kick the 586 */
#define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
#define NI52_TDIS 2 /* Xmit disable */
#define NI52_INTENA 5 /* Interrupt enable */
#define NI52_INTDIS 4 /* Interrupt disable */
#define NI52_MAGIC1 6 /* dunno exact function */
#define NI52_MAGIC2 7 /* dunno exact function */
#define NI52_MAGICVAL1 0x00 /* magic-values for ni5210 card */
#define NI52_MAGICVAL2 0x55
/*
* where to find the System Configuration Pointer (SCP)
*/
#define SCP_DEFAULT_ADDRESS 0xfffff4
/*
* System Configuration Pointer Struct
*/
struct scp_struct
{
unsigned short zero_dum0; /* has to be zero */
unsigned char sysbus; /* 0=16Bit,1=8Bit */
unsigned char zero_dum1; /* has to be zero for 586 */
unsigned short zero_dum2;
unsigned short zero_dum3;
char *iscp; /* pointer to the iscp-block */
};
/*
* Intermediate System Configuration Pointer (ISCP)
*/
struct iscp_struct
{
unsigned char busy; /* 586 clears after succesful init */
unsigned char zero_dummy; /* hast to be zero */
unsigned short scb_offset; /* pointeroffset to the scb_base */
char *scb_base; /* base-address of all 16-bit offsets */
};
/*
* System Control Block (SCB)
*/
struct scb_struct
{
unsigned short status; /* status word */
unsigned short cmd; /* command word */
unsigned short cbl_offset; /* pointeroffset, command block list */
unsigned short rfa_offset; /* pointeroffset, receive frame area */
unsigned short crc_errs; /* CRC-Error counter */
unsigned short aln_errs; /* allignmenterror counter */
unsigned short rsc_errs; /* Resourceerror counter */
unsigned short ovrn_errs; /* OVerrunerror counter */
};
/*
* possbile command values for the command word
*/
#define RUC_MASK 0x0070 /* mask for RU commands */
#define RUC_NOP 0x0000 /* NOP-command */
#define RUC_START 0x0010 /* start RU */
#define RUC_RESUME 0x0020 /* resume RU after suspend */
#define RUC_SUSPEND 0x0030 /* suspend RU */
#define RUC_ABORT 0x0040 /* abort receiver operation immediately */
#define CUC_MASK 0x0700 /* mask for CU command */
#define CUC_NOP 0x0000 /* NOP-command */
#define CUC_START 0x0100 /* start execution of 1. cmd on the CBL */
#define CUC_RESUME 0x0200 /* resume after suspend */
#define CUC_SUSPEND 0x0300 /* Suspend CU */
#define CUC_ABORT 0x0400 /* abort command operation immediately */
#define ACK_MASK 0xf000 /* mask for ACK command */
#define ACK_CX 0x8000 /* acknowledges STAT_CX */
#define ACK_FR 0x4000 /* ack. STAT_FR */
#define ACK_CNA 0x2000 /* ack. STAT_CNA */
#define ACK_RNR 0x1000 /* ack. STAT_RNR */
/*
* possbile status values for the status word
*/
#define STAT_MASK 0xf000 /* mask for cause of interrupt */
#define STAT_CX 0x8000 /* CU finished cmd with its I bit set */
#define STAT_FR 0x4000 /* RU finished receiveing a frame */
#define STAT_CNA 0x2000 /* CU left active state */
#define STAT_RNR 0x1000 /* RU left ready state */
#define CU_STATUS 0x700 /* CU status, 0=idle */
#define CU_SUSPEND 0x100 /* CU is suspended */
#define CU_ACTIVE 0x200 /* CU is active */
#define RU_STATUS 0x70 /* RU status, 0=idle */
#define RU_SUSPEND 0x10 /* RU suspended */
#define RU_NOSPACE 0x20 /* RU no resources */
#define RU_READY 0x40 /* RU is ready */
/*
* Receive Frame Descriptor (RFD)
*/
struct rfd_struct
{
unsigned short status; /* status word */
unsigned short last; /* Bit15,Last Frame on List / Bit14,suspend */
unsigned short next; /* linkoffset to next RFD */
unsigned short rbd_offset; /* pointeroffset to RBD-buffer */
unsigned char dest[6]; /* ethernet-address, destination */
unsigned char source[6]; /* ethernet-address, source */
unsigned short length; /* 802.3 frame-length */
unsigned short zero_dummy; /* dummy */
};
#define RFD_LAST 0x8000 /* last: last rfd in the list */
#define RFD_SUSP 0x4000 /* last: suspend RU after */
#define RFD_ERRMASK 0x0fe1 /* status: errormask */
#define RFD_MATCHADD 0x0002 /* status: Destinationaddress !matchs IA */
#define RFD_RNR 0x0200 /* status: receiver out of resources */
/*
* Receive Buffer Descriptor (RBD)
*/
struct rbd_struct
{
unsigned short status; /* status word,number of used bytes in buff */
unsigned short next; /* pointeroffset to next RBD */
char *buffer; /* recevie buffer address pointer */
unsigned short size; /* size of this buffer */
unsigned short zero_dummy; /* dummy */
};
#define RBD_LAST 0x8000 /* last buffer */
#define RBD_USED 0x4000 /* this buffer has data */
#define RBD_MASK 0x3fff /* size-mask for length */
/*
* Statusvalues for Commands/RFD
*/
#define STAT_COMPL 0x8000 /* status: frame/command is complete */
#define STAT_BUSY 0x4000 /* status: frame/command is busy */
#define STAT_OK 0x2000 /* status: frame/command is ok */
/*
* Action-Commands
*/
#define CMD_NOP 0x0000 /* NOP */
#define CMD_IASETUP 0x0001 /* initial address setup command */
#define CMD_CONFIGURE 0x0002 /* configure command */
#define CMD_MCSETUP 0x0003 /* MC setup command */
#define CMD_XMIT 0x0004 /* transmit command */
#define CMD_TDR 0x0005 /* time domain reflectometer (TDR) command */
#define CMD_DUMP 0x0006 /* dump command */
#define CMD_DIAGNOSE 0x0007 /* diagnose command */
/*
* Action command bits
*/
#define CMD_LAST 0x8000 /* indicates last command in the CBL */
#define CMD_SUSPEND 0x4000 /* suspend CU after this CB */
#define CMD_INT 0x2000 /* generate interrupt after execution */
/*
* NOP - command
*/
struct nop_cmd_struct
{
unsigned short cmd_status; /* statius of this command */
unsigned short cmd_cmd; /* the command itself (+bits) */
unsigned short cmd_link; /* offsetpointer to next command */
};
/*
* IA Setup command
*/
struct iasetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned char iaddr[6];
};
/*
* Configure command
*/
struct configure_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned char byte_cnt; /* size of the config-cmd */
unsigned char fifo; /* fifo/recv monitor */
unsigned char sav_bf; /* save bad frames (bit7=1)*/
unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/
unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */
unsigned char ifs; /* inter frame spacing */
unsigned char time_low; /* slot time low */
unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */
unsigned char promisc; /* promisc-mode(0) , et al (1-7) */
unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */
unsigned char fram_len; /* minimal frame len */
unsigned char dummy; /* dummy */
};
/*
* Multicast Setup command
*/
struct mcsetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short mc_cnt; /* number of bytes in the MC-List */
unsigned char mc_list[16][6]; /* the list for 16 entries */
};
/*
* transmit command
*/
struct transmit_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short tbd_offset; /* pointeroffset to TBD */
unsigned char dest[6]; /* destination address of the frame */
unsigned short length; /* user defined: 802.3 length / Ether type */
};
#define TCMD_ERRMASK 0x0fa0
#define TCMD_MAXCOLLMASK 0x000f
#define TCMD_MAXCOLL 0x0020
#define TCMD_HEARTBEAT 0x0040
#define TCMD_DEFFERED 0x0080
#define TCMD_UNDERRUN 0x0100
#define TCMD_LOSTCTS 0x0200
#define TCMD_NOCARRIER 0x0400
#define TCMD_LATECOLL 0x0800
struct tdr_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
unsigned short cmd_link;
unsigned short status;
};
#define TDR_LNK_OK 0x8000 /* No link problem identified */
#define TDR_XCVR_PRB 0x4000 /* indiactes a transceiver problem */
#define TDR_ET_OPN 0x2000 /* open, no correct termination */
#define TDR_ET_SRT 0x1000 /* TDR detected a short circuit */
#define TDR_TIMEMASK 0x07ff /* mask for the time field */
/*
* Transmit Buffer Descriptor (TBD)
*/
struct tbd_struct
{
unsigned short size; /* size + EOF-Flag(15) */
unsigned short next; /* pointeroffset to next TBD */
char *buffer; /* pointer to buffer */
};
#define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */
/*
* ni6510 (am7990 'lance' chip) driver for Linux-net-3 by MH
* Alphacode v0.33 (94/08/22) for 1.1.47 (or later)
*
* ----------------------------------------------------------
* WARNING: DOESN'T WORK ON MACHINES WITH MORE THAN 16MB !!!!
* ----------------------------------------------------------
*
* copyright (c) 1994 M.Hipp
*
* This is an extension to the Linux operating system, and is covered by the
* same Gnu Public License that covers the Linux-kernel.
*
* comments/bugs/suggestions can be sent to:
* Michael Hipp
* email: mhipp@student.uni-tuebingen.de
*
* sources:
* some things are from the 'ni6510-packet-driver for dos by Russ Nelson'
* and from the original drivers by D.Becker
*/
/*
* Aug.22: changes in xmit_intr (ack more than one xmitted-packet), ni65_send_packet (p->lock) (MH)
*
* July.16: fixed bugs in recv_skb and skb-alloc stuff (MH)
*/
/*
* known BUGS: 16MB limit
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include "ni65.h"
/************************************
* skeleton-stuff
*/
#ifndef HAVE_PORTRESERVE
#define check_region(ioaddr, size) 0
#define snarf_region(ioaddr, size); do ; while (0)
#endif
#ifndef NET_DEBUG
#define NET_DEBUG 2
#endif
/*
static unsigned int net_debug = NET_DEBUG;
*/
#define NI65_TOTAL_SIZE 16
#define SA_ADDR0 0x02
#define SA_ADDR1 0x07
#define SA_ADDR2 0x01
#define CARD_ID0 0x00
#define CARD_ID1 0x55
/*****************************************/
#define PORT dev->base_addr
#define RMDNUM 8
#define RMDNUMMASK 0x6000 /* log2(RMDNUM)<<13 */
#define TMDNUM 4
#define TMDNUMMASK 0x4000 /* log2(TMDNUM)<<13 */
#define R_BUF_SIZE 1518
#define T_BUF_SIZE 1518
#define MEMSIZE 8+RMDNUM*8+TMDNUM*8
#define L_DATAREG 0x00
#define L_ADDRREG 0x02
#define L_RESET 0x04
#define L_CONFIG 0x05
#define L_EBASE 0x08
/*
* to access the am7990-regs, you have to write
* reg-number into L_ADDRREG, then you can access it using L_DATAREG
*/
#define CSR0 0x00
#define CSR1 0x01
#define CSR2 0x02
#define CSR3 0x03
/* if you #define NO_STATIC the driver is faster but you will have (more) problems with >16MB memory */
#undef NO_STATIC
#define writereg(val,reg) {outw(reg,PORT+L_ADDRREG);inw(PORT+L_ADDRREG); \
outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);}
#define readreg(reg) (outw(reg,PORT+L_ADDRREG),inw(PORT+L_ADDRREG),\
inw(PORT+L_DATAREG))
#define writedatareg(val) {outw(val,PORT+L_DATAREG);inw(PORT+L_DATAREG);}
static int ni65_probe1(struct device *dev,int);
static void ni65_interrupt(int reg_ptr);
static void recv_intr(struct device *dev);
static void xmit_intr(struct device *dev);
static int ni65_open(struct device *dev);
static int am7990_reinit(struct device *dev);
static int ni65_send_packet(struct sk_buff *skb, struct device *dev);
static int ni65_close(struct device *dev);
static struct enet_statistics *ni65_get_stats(struct device *);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
extern void *irq2dev_map[16];
struct priv
{
struct init_block ib;
void *memptr;
struct rmd *rmdhead;
struct tmd *tmdhead;
int rmdnum;
int tmdnum,tmdlast;
struct sk_buff *recv_skb[RMDNUM];
void *tmdbufs[TMDNUM];
int lock,xmit_queued;
struct enet_statistics stats;
};
int irqtab[] = { 9,12,15,5 }; /* irq config-translate */
int dmatab[] = { 0,3,5,6 }; /* dma config-translate */
/*
* open (most done by init)
*/
static int ni65_open(struct device *dev)
{
if(am7990_reinit(dev))
{
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
return 0;
}
else
{
dev->start = 0;
return -EAGAIN;
}
}
static int ni65_close(struct device *dev)
{
outw(0,PORT+L_RESET); /* that's the hard way */
dev->tbusy = 1;
dev->start = 0;
return 0;
}
/*
* Probe The Card (not the lance-chip)
* and set hardaddress
*/
int ni65_probe(struct device *dev)
{
int *port, ports[] = {0x300,0x320,0x340,0x360, 0};
int base_addr = dev->base_addr;
if (base_addr > 0x1ff) /* Check a single specified location. */
return ni65_probe1(dev, base_addr);
else if (base_addr > 0) /* Don't probe at all. */
return ENXIO;
for (port = ports; *port; port++)
{
int ioaddr = *port;
if (check_region(ioaddr, NI65_TOTAL_SIZE))
continue;
if( !(inb(ioaddr+L_EBASE+6) == CARD_ID0) ||
!(inb(ioaddr+L_EBASE+7) == CARD_ID1) )
continue;
dev->base_addr = ioaddr;
if (ni65_probe1(dev, ioaddr) == 0)
return 0;
}
dev->base_addr = base_addr;
return ENODEV;
}
static int ni65_probe1(struct device *dev,int ioaddr)
{
int i;
unsigned char station_addr[6];
struct priv *p;
for(i=0;i<6;i++)
station_addr[i] = dev->dev_addr[i] = inb(PORT+L_EBASE+i);
if(station_addr[0] != SA_ADDR0 || station_addr[1] != SA_ADDR1)
{
printk("%s: wrong Hardaddress \n",dev->name);
return ENODEV;
}
if(dev->irq == 0)
dev->irq = irqtab[(inw(PORT+L_CONFIG)>>2)&3];
if(dev->dma == 0)
dev->dma = dmatab[inw(PORT+L_CONFIG)&3];
printk("%s: %s found at %#3x, IRQ %d DMA %d.\n", dev->name,
"network card", dev->base_addr, dev->irq,dev->dma);
{
int irqval = request_irq(dev->irq, &ni65_interrupt,0,"ni65");
if (irqval) {
printk ("%s: unable to get IRQ %d (irqval=%d).\n",
dev->name,dev->irq, irqval);
return EAGAIN;
}
if(request_dma(dev->dma, "ni65") != 0)
{
printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
free_irq(dev->irq);
return EAGAIN;
}
}
irq2dev_map[dev->irq] = dev;
/* Grab the region so we can find another board if autoIRQ fails. */
snarf_region(ioaddr,NI65_TOTAL_SIZE);
p = dev->priv = (void *) kmalloc(sizeof(struct priv),GFP_KERNEL);
memset((char *) dev->priv,0,sizeof(struct priv));
dev->open = ni65_open;
dev->stop = ni65_close;
dev->hard_start_xmit = ni65_send_packet;
dev->get_stats = ni65_get_stats;
dev->set_multicast_list = set_multicast_list;
ether_setup(dev);
dev->interrupt = 0;
dev->tbusy = 0;
dev->start = 0;
if( (p->memptr = kmalloc(MEMSIZE,GFP_KERNEL)) == NULL) {
printk("%s: Can't alloc TMD/RMD-buffer.\n",dev->name);
return EAGAIN;
}
if( (unsigned long) (p->memptr + MEMSIZE) & 0xff000000) {
printk("%s: Can't alloc TMD/RMD buffer in lower 16MB!\n",dev->name);
return EAGAIN;
}
p->tmdhead = (struct tmd *) ((( (unsigned long)p->memptr ) + 8) & 0xfffffff8);
p->rmdhead = (struct rmd *) (p->tmdhead + TMDNUM);
#ifndef NO_STATIC
for(i=0;i<TMDNUM;i++)
{
if( (p->tmdbufs[i] = kmalloc(T_BUF_SIZE,GFP_ATOMIC)) == NULL) {
printk("%s: Can't alloc Xmit-Mem.\n",dev->name);
return EAGAIN;
}
if( (unsigned long) (p->tmdbufs[i]+T_BUF_SIZE) & 0xff000000) {
printk("%s: Can't alloc Xmit-Mem in lower 16MB!\n",dev->name);
return EAGAIN;
}
}
#endif
for(i=0;i<RMDNUM;i++)
{
if( (p->recv_skb[i] = (struct sk_buff *) alloc_skb(R_BUF_SIZE,GFP_ATOMIC)) == NULL) {
printk("%s: unable to alloc recv-mem\n",dev->name);
return EAGAIN;
}
if( (unsigned long) (p->recv_skb[i]->data + R_BUF_SIZE) & 0xff000000) {
printk("%s: unable to alloc receive-memory in lower 16MB!\n",dev->name);
return EAGAIN;
}
}
return 0; /* we've found everyting */
}
/*
* init lance (write init-values .. init-buffers) (open-helper)
*/
static int am7990_reinit(struct device *dev)
{
int i,j;
struct tmd *tmdp;
struct rmd *rmdp;
struct priv *p = (struct priv *) dev->priv;
p->lock = 0;
p->xmit_queued = 0;
disable_dma(dev->dma); /* I've never worked with dma, but we do it like the packetdriver */
set_dma_mode(dev->dma,DMA_MODE_CASCADE);
enable_dma(dev->dma);
outw(0,PORT+L_RESET); /* first: reset the card */
if(inw(PORT+L_DATAREG) != 0x4)
{
printk("%s: can't RESET ni6510 card: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
disable_dma(dev->dma);
free_dma(dev->dma);
free_irq(dev->irq);
return 0;
}
/* here: memset all buffs to zero */
memset(p->memptr,0,MEMSIZE);
p->tmdnum = 0; p->tmdlast = 0;
for(i=0;i<TMDNUM;i++)
{
tmdp = p->tmdhead + i;
#ifndef NO_STATIC
tmdp->u.buffer = (unsigned long) p->tmdbufs[i];
#endif
tmdp->u.s.status = XMIT_START | XMIT_END;
}
p->rmdnum = 0;
for(i=0;i<RMDNUM;i++)
{
rmdp = p->rmdhead + i;
rmdp->u.buffer = (unsigned long) p->recv_skb[i]->data;
rmdp->u.s.status = RCV_OWN;
rmdp->blen = -R_BUF_SIZE;
rmdp->mlen = 0;
}
for(i=0;i<6;i++)
{
p->ib.eaddr[i] = dev->dev_addr[i];
}
p->ib.mode = 0;
for(i=0;i<8;i++)
p->ib.filter[i] = 0;
p->ib.trplow = (unsigned short) (( (unsigned long) p->tmdhead ) & 0xffff);
p->ib.trphigh = (unsigned short) ((( (unsigned long) p->tmdhead )>>16) & 0x00ff) | TMDNUMMASK;
p->ib.rrplow = (unsigned short) (( (unsigned long) p->rmdhead ) & 0xffff);
p->ib.rrphigh = (unsigned short) ((( (unsigned long) p->rmdhead )>>16) & 0x00ff) | RMDNUMMASK;
writereg(0,CSR3); /* busmaster/no word-swap */
writereg((unsigned short) (((unsigned long) &(p->ib)) & 0xffff),CSR1);
writereg((unsigned short) (((unsigned long) &(p->ib))>>16),CSR2);
writereg(CSR0_INIT,CSR0); /* this changes L_ADDRREG to CSR0 */
/*
* NOW, WE NEVER WILL CHANGE THE L_ADDRREG, CSR0 IS ALWAYS SELECTED
*/
for(i=0;i<5;i++)
{
for(j=0;j<2000000;j++); /* wait a while */
if(inw(PORT+L_DATAREG) & CSR0_IDON) break; /* init ok ? */
}
if(i == 5)
{
printk("%s: can't init am7990, status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
disable_dma(dev->dma);
free_dma(dev->dma);
free_irq(dev->irq);
return 0; /* false */
}
writedatareg(CSR0_CLRALL | CSR0_INEA | CSR0_STRT); /* start lance , enable interrupts */
return 1; /* OK */
}
/*
* interrupt handler
*/
static void ni65_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
int csr0;
struct device *dev = (struct device *) irq2dev_map[irq];
if (dev == NULL) {
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return;
}
csr0 = inw(PORT+L_DATAREG);
writedatareg(csr0 & CSR0_CLRALL); /* ack interrupts, disable int. */
dev->interrupt = 1;
if(csr0 & CSR0_ERR)
{
struct priv *p = (struct priv *) dev->priv;
if(csr0 & CSR0_BABL)
p->stats.tx_errors++;
if(csr0 & CSR0_MISS)
p->stats.rx_errors++;
}
if(csr0 & CSR0_RINT) /* RECV-int? */
{
recv_intr(dev);
}
if(csr0 & CSR0_TINT) /* XMIT-int? */
{
xmit_intr(dev);
}
writedatareg(CSR0_INEA); /* reenable inter. */
dev->interrupt = 0;
return;
}
/*
* We have received an Xmit-Interrupt ..
* send a new packet if necessary
*/
static void xmit_intr(struct device *dev)
{
int tmdstat;
struct tmd *tmdp;
struct priv *p = (struct priv *) dev->priv;
#ifdef NO_STATIC
struct sk_buff *skb;
#endif
while(p->xmit_queued)
{
tmdp = p->tmdhead + p->tmdlast;
tmdstat = tmdp->u.s.status;
if(tmdstat & XMIT_OWN)
break;
#ifdef NO_STATIC
skb = (struct sk_buff *) p->tmdbufs[p->tmdlast];
dev_kfree_skb(skb,FREE_WRITE);
#endif
if(tmdstat & XMIT_ERR)
{
printk("%s: xmit-error: %04x %04x\n",dev->name,(int) tmdstat,(int) tmdp->status2);
if(tmdp->status2 & XMIT_TDRMASK)
printk("%s: tdr-problems (e.g. no resistor)\n",dev->name);
/* checking some errors */
if(tmdp->status2 & XMIT_RTRY)
p->stats.tx_aborted_errors++;
if(tmdp->status2 & XMIT_LCAR)
p->stats.tx_carrier_errors++;
p->stats.tx_errors++;
tmdp->status2 = 0;
}
else
p->stats.tx_packets++;
p->tmdlast = (p->tmdlast + 1) & (TMDNUM-1);
if(p->tmdlast == p->tmdnum)
p->xmit_queued = 0;
}
dev->tbusy = 0;
mark_bh(NET_BH);
}
/*
* We have received a packet
*/
static void recv_intr(struct device *dev)
{
struct rmd *rmdp;
int rmdstat,len;
struct sk_buff *skb,*skb1;
struct priv *p = (struct priv *) dev->priv;
rmdp = p->rmdhead + p->rmdnum;
while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN))
{
if( (rmdstat & (RCV_START | RCV_END)) != (RCV_START | RCV_END) ) /* is packet start & end? */
{
if(rmdstat & RCV_START)
{
p->stats.rx_errors++;
p->stats.rx_length_errors++;
printk("%s: packet too long\n",dev->name);
}
rmdp->u.s.status = RCV_OWN; /* change owner */
}
else if(rmdstat & RCV_ERR)
{
printk("%s: receive-error: %04x\n",dev->name,(int) rmdstat );
p->stats.rx_errors++;
if(rmdstat & RCV_FRAM) p->stats.rx_frame_errors++;
if(rmdstat & RCV_OFLO) p->stats.rx_over_errors++;
if(rmdstat & RCV_CRC) p->stats.rx_crc_errors++;
rmdp->u.s.status = RCV_OWN;
printk("%s: lance-status: %04x\n",dev->name,(int) inw(PORT+L_DATAREG));
}
else
{
len = (rmdp->mlen & 0x0fff) - 4; /* -4: ignore FCS */
skb = alloc_skb(R_BUF_SIZE,GFP_ATOMIC);
if(skb != NULL)
{
if( (unsigned long) (skb->data + R_BUF_SIZE) & 0xff000000) {
memcpy(skb->data,p->recv_skb[p->rmdnum]->data,len);
skb1 = skb;
}
else {
skb1 = p->recv_skb[p->rmdnum];
p->recv_skb[p->rmdnum] = skb;
rmdp->u.buffer = (unsigned long) (skb->data);
}
rmdp->u.s.status = RCV_OWN;
rmdp->mlen = 0; /* not necc ???? */
skb1->len = len;
skb1->dev = dev;
p->stats.rx_packets++;
netif_rx(skb1);
}
else
{
rmdp->u.s.status = RCV_OWN;
printk("%s: can't alloc new sk_buff\n",dev->name);
p->stats.rx_dropped++;
}
}
p->rmdnum++; p->rmdnum &= RMDNUM-1;
rmdp = p->rmdhead + p->rmdnum;
}
}
/*
* kick xmitter ..
*/
static int ni65_send_packet(struct sk_buff *skb, struct device *dev)
{
struct priv *p = (struct priv *) dev->priv;
struct tmd *tmdp;
if(dev->tbusy)
{
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 25)
return 1;
printk("%s: xmitter timed out, try to restart!\n",dev->name);
am7990_reinit(dev);
dev->tbusy=0;
dev->trans_start = jiffies;
}
if(skb == NULL)
{
dev_tint(dev);
return 0;
}
if (skb->len <= 0)
return 0;
if (set_bit(0, (void*)&dev->tbusy) != 0)
{
printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
}
if(set_bit(0,(void*) &p->lock) != 0)
{
printk("%s: Queue was locked!\n",dev->name);
return 1;
}
{
short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
tmdp = p->tmdhead + p->tmdnum;
#ifdef NO_STATIC
tmdp->u.buffer = (unsigned long) (skb->data);
p->tmdbufs[p->tmdnum] = skb;
#else
memcpy((char *) (tmdp->u.buffer & 0x00ffffff),(char *)skb->data,skb->len);
dev_kfree_skb (skb, FREE_WRITE);
#endif
tmdp->blen = -len;
tmdp->u.s.status = XMIT_OWN | XMIT_START | XMIT_END;
cli();
p->xmit_queued = 1;
writedatareg(CSR0_TDMD | CSR0_INEA); /* enable xmit & interrupt */
p->tmdnum++; p->tmdnum &= TMDNUM-1;
if( !((p->tmdhead + p->tmdnum)->u.s.status & XMIT_OWN) )
dev->tbusy = 0;
p->lock = 0;
sti();
dev->trans_start = jiffies;
}
return 0;
}
static struct enet_statistics *ni65_get_stats(struct device *dev)
{
return &((struct priv *) dev->priv)->stats;
}
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
}
/*
* END of ni65.c
*/
/* am7990 (lance) definitions
*
* This is a extension to the Linux operating system, and is covered by
* same Gnu Public License that covers that work.
*
* Michael Hipp
* email: mhipp@student.uni-tuebingen.de
*
* sources: (mail me or ask archie if you need them)
* crynwr-packet-driver
*/
/*
* Control and Status Register 0 (CSR0) bit definitions
* (R=Readable) (W=Writeable) (S=Set on write) (C-Clear on write)
*
*/
#define CSR0_ERR 0x8000 /* Error summary (R) */
#define CSR0_BABL 0x4000 /* Babble transmitter timeout error (RC) */
#define CSR0_CERR 0x2000 /* Collision Error (RC) */
#define CSR0_MISS 0x1000 /* Missed packet (RC) */
#define CSR0_MERR 0x0800 /* Memory Error (RC) */
#define CSR0_RINT 0x0400 /* Reciever Interrupt (RC) */
#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */
#define CSR0_IDON 0x0100 /* Initialization Done (RC) */
#define CSR0_INTR 0x0080 /* Interrupt Flag (R) */
#define CSR0_INEA 0x0040 /* Interrupt Enable (RW) */
#define CSR0_RXON 0x0020 /* Receiver on (R) */
#define CSR0_TXON 0x0010 /* Transmitter on (R) */
#define CSR0_TDMD 0x0008 /* Transmit Demand (RS) */
#define CSR0_STOP 0x0004 /* Stop (RS) */
#define CSR0_STRT 0x0002 /* Start (RS) */
#define CSR0_INIT 0x0001 /* Initialize (RS) */
#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */
/*
* Initialization Block Mode operation Bit Definitions.
*/
#define M_PROM 0x8000 /* Promiscuous Mode */
#define M_INTL 0x0040 /* Internal Loopback */
#define M_DRTY 0x0020 /* Disable Retry */
#define M_COLL 0x0010 /* Force Collision */
#define M_DTCR 0x0008 /* Disable Transmit CRC) */
#define M_LOOP 0x0004 /* Loopback */
#define M_DTX 0x0002 /* Disable the Transmitter */
#define M_DRX 0x0001 /* Disable the Reciever */
/*
* Receive message descriptor bit definitions.
*/
#define RCV_OWN 0x80 /* owner bit 0 = host, 1 = lance */
#define RCV_ERR 0x40 /* Error Summary */
#define RCV_FRAM 0x20 /* Framing Error */
#define RCV_OFLO 0x10 /* Overflow Error */
#define RCV_CRC 0x08 /* CRC Error */
#define RCV_BUF_ERR 0x04 /* Buffer Error */
#define RCV_START 0x02 /* Start of Packet */
#define RCV_END 0x01 /* End of Packet */
/*
* Transmit message descriptor bit definitions.
*/
#define XMIT_OWN 0x80 /* owner bit 0 = host, 1 = lance */
#define XMIT_ERR 0x40 /* Error Summary */
#define XMIT_RETRY 0x10 /* more the 1 retry needed to Xmit */
#define XMIT_1_RETRY 0x08 /* one retry needed to Xmit */
#define XMIT_DEF 0x04 /* Deferred */
#define XMIT_START 0x02 /* Start of Packet */
#define XMIT_END 0x01 /* End of Packet */
/*
* transmit status (2) (valid if XMIT_ERR == 1)
*/
#define XMIT_RTRY 0x0200 /* Failed after 16 retransmissions */
#define XMIT_LCAR 0x0400 /* Loss of Carrier */
#define XMIT_LCOL 0x1000 /* Late collision */
#define XMIT_RESERV 0x2000 /* Reserved */
#define XMIT_UFLO 0x4000 /* Underflow (late memory) */
#define XMIT_BUFF 0x8000 /* Buffering error (no ENP) */
#define XMIT_TDRMASK 0x003f /* time-domain-reflectometer-value */
struct init_block
{
unsigned short mode;
unsigned char eaddr[6];
unsigned char filter[8];
unsigned short rrplow; /* receive ring pointer (align 8) */
unsigned short rrphigh; /* bit 13-15: number of rmd's (power of 2) */
unsigned short trplow; /* transmit ring pointer (align 8) */
unsigned short trphigh; /* bit 13-15: number of tmd's (power of 2) */
};
struct rmd /* Receive Message Descriptor */
{
union
{
volatile unsigned long buffer;
struct
{
volatile unsigned char dummy[3];
volatile unsigned char status;
} s;
} u;
short blen;
volatile unsigned short mlen;
};
struct tmd
{
union
{
volatile unsigned long buffer;
struct
{
volatile unsigned char dummy[3];
volatile unsigned char status;
} s;
} u;
unsigned short blen;
volatile unsigned short status2;
};
......@@ -236,7 +236,7 @@ net_open(struct device *dev)
/* Always snarf a DMA channel after the IRQ. */
if (request_dma(dev->dma)) {
if (request_dma(dev->dma,"skeleton ethernet")) {
free_irq(dev->irq);
return -EAGAIN;
}
......
......@@ -248,8 +248,8 @@ int znet_probe(struct device *dev)
/* These should never fail. You can't add devices to a sealed box! */
if (request_irq(dev->irq, &znet_interrupt, 0, "ZNet")
|| request_dma(zn.rx_dma)
|| request_dma(zn.tx_dma)) {
|| request_dma(zn.rx_dma,"ZNet rx")
|| request_dma(zn.tx_dma,"ZNet tx")) {
printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
return EBUSY;
}
......
......@@ -876,7 +876,7 @@ int aha1542_detect(Scsi_Host_Template * tpnt)
}
if (dma_chan != 0xFF) {
if (request_dma(dma_chan)) {
if (request_dma(dma_chan,"aha1542")) {
printk("Unable to allocate DMA channel for Adaptec.\n");
free_irq(irq_level);
goto unregister;
......
......@@ -1082,7 +1082,7 @@ int buslogic_detect(Scsi_Host_Template *tpnt)
}
if (dma) {
if (request_dma(dma)) {
if (request_dma(dma,"buslogic")) {
buslogic_printk("Unable to allocate DMA channel for "
"BusLogic controller.\n");
free_irq(irq);
......
......@@ -654,7 +654,7 @@ static int sr_detect(Scsi_Device * SDp){
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n",
++sr_template.dev_noticed,
sr_template.dev_noticed++,
SDp->host->host_no , SDp->id, SDp->lun);
return 1;
......
......@@ -498,7 +498,7 @@ static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
config.interrupt);
return FALSE;
}
if (config.dma_channel && request_dma(config.dma_channel)) {
if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) {
printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
config.dma_channel);
free_irq(config.interrupt);
......
......@@ -1047,7 +1047,7 @@ int wd7000_init( Adapter *host )
printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return 0;
}
if (request_dma(host->dma)) {
if (request_dma(host->dma,"wd7000")) {
printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
free_irq(host->irq);
return 0;
......
......@@ -259,7 +259,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
/* These are in kernel/dma.c: */
extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */
extern int request_dma(unsigned int dmanr,char * deviceID); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
......
......@@ -832,7 +832,7 @@ DMAbuf_open_dma (int dev)
unsigned long flags;
int chan = audio_devs[dev]->dmachan;
if (ALLOC_DMA_CHN (chan))
if (ALLOC_DMA_CHN (chan,"audio"))
{
printk ("Unable to grab DMA%d for the audio driver\n", chan);
return RET_ERROR (EBUSY);
......
......@@ -93,7 +93,7 @@ struct snd_wait {
#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wake_up(&q);}
#define ALLOC_DMA_CHN(chn) request_dma(chn)
#define ALLOC_DMA_CHN(chn,deviceID) request_dma(chn,deviceID)
#define RELEASE_DMA_CHN(chn) free_dma(chn)
#define GET_TIME() jiffies
......
......@@ -228,7 +228,7 @@ sb16_dsp_open (int dev, int mode)
sb_reset_dsp ();
if (ALLOC_DMA_CHN (dma8))
if (ALLOC_DMA_CHN (dma8,"sb16 8bit"))
{
printk ("SB16: Unable to grab DMA%d\n", dma8);
sb_free_irq ();
......@@ -236,7 +236,7 @@ sb16_dsp_open (int dev, int mode)
}
if (dma16 != dma8)
if (ALLOC_DMA_CHN (dma16))
if (ALLOC_DMA_CHN (dma16,"sb16 16bit"))
{
printk ("SB16: Unable to grab DMA%d\n", dma16);
sb_free_irq ();
......
......@@ -8,6 +8,7 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/locks.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
#include <asm/system.h>
......@@ -117,6 +118,10 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
buf += chars;
bh->b_uptodate = 1;
mark_buffer_dirty(bh, 0);
if (filp->f_flags & O_SYNC) {
ll_rw_block(WRITE, 1, &bh);
wait_on_buffer(bh);
}
brelse(bh);
}
filp->f_reada = 1;
......
Changes from version 0.5 to version 0.5a
========================================
- Added a revision level in the superblock.
- Full support for O_SYNC flag of the open system call.
- New mount options: `bsddf' and `minixdf'. `bsddf' causes ext2fs
to remove the blocks used for FS structures from the total block
count in statfs. With `minixdf', ext2fs mimics Minix behavior
......
......@@ -258,6 +258,14 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
pos = inode->i_size;
else
pos = filp->f_pos;
/*
* If a file has been opened in synchronous mode, we have to ensure
* that meta-data will also be written synchronously. Thus, we
* set the i_osync field. This field is tested by the allocation
* routines.
*/
if (filp->f_flags & O_SYNC)
inode->u.ext2_i.i_osync++;
written = 0;
while (written < count) {
bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err);
......@@ -286,10 +294,16 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
buf += c;
bh->b_uptodate = 1;
mark_buffer_dirty(bh, 0);
if (filp->f_flags & O_SYNC) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
brelse (bh);
}
if (pos > inode->i_size)
inode->i_size = pos;
if (filp->f_flags & O_SYNC)
inode->u.ext2_i.i_osync--;
up(&inode->i_sem);
inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos;
......
......@@ -236,7 +236,7 @@ static struct buffer_head * inode_getblk (struct inode * inode, int nr,
inode->u.ext2_i.i_next_alloc_goal = tmp;
inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks;
if (IS_SYNC(inode))
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
inode->i_dirt = 1;
......@@ -307,7 +307,7 @@ static struct buffer_head * block_getblk (struct inode * inode,
}
*p = tmp;
mark_buffer_dirty(bh, 1);
if (IS_SYNC(inode)) {
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
......@@ -535,6 +535,7 @@ void ext2_read_inode (struct inode * inode)
inode->u.ext2_i.i_faddr = raw_inode->i_faddr;
inode->u.ext2_i.i_frag_no = raw_inode->i_frag;
inode->u.ext2_i.i_frag_size = raw_inode->i_fsize;
inode->u.ext2_i.i_osync = 0;
inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl;
inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl;
inode->u.ext2_i.i_version = raw_inode->i_version;
......
......@@ -463,6 +463,7 @@ extern int get_device_list(char *);
extern int get_filesystem_list(char *);
extern int get_ksyms_list(char *);
extern int get_irq_list(char *);
extern int get_dma_list(char *);
static int get_root_array(char * page, int type)
{
......@@ -501,6 +502,9 @@ static int get_root_array(char * page, int type)
case PROC_KSYMS:
return get_ksyms_list(page);
case PROC_DMA:
return get_dma_list(page);
}
return -EBADF;
}
......
......@@ -71,6 +71,7 @@ static struct proc_dir_entry root_dir[] = {
{ PROC_INTERRUPTS, 10,"interrupts" },
{ PROC_FILESYSTEMS, 11,"filesystems" },
{ PROC_KSYMS, 5, "ksyms" },
{ PROC_DMA, 3, "dma" },
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
......
......@@ -66,7 +66,7 @@ extern __inline__ int test_bit(int nr, void * addr)
/*
* Find-bit routines..
*/
extern inline int find_first_zero_bit (unsigned long * addr, unsigned size)
extern inline int find_first_zero_bit(void * addr, unsigned size)
{
int res;
......@@ -92,8 +92,7 @@ extern inline int find_first_zero_bit (unsigned long * addr, unsigned size)
return res;
}
extern inline int find_next_zero_bit (unsigned long * addr, int size,
int offset)
extern inline int find_next_zero_bit (void * addr, int size, int offset)
{
unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
int set = 0, bit = offset & 31, res;
......@@ -117,7 +116,7 @@ extern inline int find_next_zero_bit (unsigned long * addr, int size,
/*
* No zero yet, search remaining full bytes for a zero
*/
res = find_first_zero_bit (p, size - 32 * (p - addr));
res = find_first_zero_bit (p, size - 32 * (p - (unsigned long *) addr));
return (offset + set + res);
}
......
......@@ -259,7 +259,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
/* These are in kernel/dma.c: */
extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */
extern int request_dma(unsigned int dmanr, char * deviceID); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
......
......@@ -447,7 +447,7 @@ extern inline void * __constant_c_and_count_memset(void * s, unsigned long patte
return s;
case 3:
*(unsigned short *)s = pattern;
*(2+(unsigned char *)s) = pattern >> 16;
*(2+(unsigned char *)s) = pattern;
return s;
case 4:
*(unsigned long *)s = pattern;
......
......@@ -47,7 +47,7 @@
/*
* The second extended file system version
*/
#define EXT2FS_DATE "94/08/12"
#define EXT2FS_DATE "94/08/24"
#define EXT2FS_VERSION "0.5a"
/*
......@@ -348,13 +348,16 @@ struct ext2_super_block {
unsigned long s_lastcheck; /* time of last check */
unsigned long s_checkinterval; /* max. time between checks */
unsigned long s_creator_os; /* OS */
unsigned long s_reserved[237]; /* Padding to the end of the block */
unsigned long s_rev_level; /* Revision level */
unsigned long s_reserved[236]; /* Padding to the end of the block */
};
#define EXT2_OS_LINUX 0
#define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2
#define EXT2_CURRENT_REV 0
/*
* Structure of a directory entry
*/
......
......@@ -24,7 +24,7 @@ struct ext2_inode_info {
unsigned long i_faddr;
unsigned char i_frag_no;
unsigned char i_frag_size;
unsigned short i_pad1;
unsigned short i_osync;
unsigned long i_file_acl;
unsigned long i_dir_acl;
unsigned long i_dtime;
......
#ifndef _LINUX_FCNTL_H
#define _LINUX_FCNTL_H
/* open/fcntl - O_SYNC isn't implemented yet */
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on an ext2 file system */
#define O_ACCMODE 0003
#define O_RDONLY 00
#define O_WRONLY 01
......
......@@ -87,12 +87,12 @@ struct hd_driveid {
unsigned short vendor0; /* vendor unique */
unsigned short vendor1; /* vendor unique */
unsigned short vendor2; /* vendor unique */
unsigned char serial_no[20]; /* big_endian; 0 = not_specified */
unsigned char serial_no[20]; /* 0 = not_specified */
unsigned short buf_type;
unsigned short buf_size; /* 512 byte increments; 0 = not_specified */
unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */
unsigned char fw_rev[8]; /* big_endian; 0 = not_specified */
unsigned char model[40]; /* big_endian; 0 = not_specified */
unsigned char fw_rev[8]; /* 0 = not_specified */
unsigned char model[40]; /* 0 = not_specified */
unsigned char max_multsect; /* 0=not_implemented */
unsigned char vendor3; /* vendor unique */
unsigned short dword_io; /* 0=not_implemented; 1=implemented */
......
......@@ -23,7 +23,8 @@ enum root_directory_inos {
PROC_DEVICES,
PROC_INTERRUPTS,
PROC_FILESYSTEMS,
PROC_KSYMS
PROC_KSYMS,
PROC_DMA
};
enum pid_directory_inos {
......
......@@ -20,7 +20,6 @@ struct linger {
#define SOCK_RAW 3 /* raw socket */
#define SOCK_RDM 4 /* reliably-delivered message */
#define SOCK_SEQPACKET 5 /* sequential packet socket */
#define SOCK_NCP 6 /* Novell NCP socket */
#define SOCK_PACKET 10 /* linux specific way of */
/* getting packets at the dev */
/* level. For writing rarp and */
......
......@@ -496,7 +496,7 @@ asmlinkage void start_kernel(void)
if (hlt_works_ok) {
printk("Checking 'hlt' instruction... ");
__asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
printk(" Ok.\n");
printk("Ok.\n");
}
system_utsname.machine[1] = '0' + x86;
......
......@@ -16,7 +16,7 @@
.c.o:
$(CC) $(CFLAGS) -c $<
OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o exec_domain.o \
OBJS = sched.o entry.o traps.o irq.o dma.o fork.o exec_domain.o \
panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
signal.o ptrace.o ioport.o itimer.o \
info.o ldt.o time.o tqueue.o vm86.o bios32.o splx.o
......@@ -27,9 +27,9 @@ kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
sync
sys_call.s: sys_call.S
entry.s: entry.S
sys_call.o: sys_call.s
entry.o: entry.s
sched.o: sched.c
$(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $<
......
......@@ -29,11 +29,21 @@
* DMA0 used to be reserved for DRAM refresh, but apparently not any more...
* DMA4 is reserved for cascading.
*/
/*
static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = {
0, 0, 0, 0, 1, 0, 0, 0
};
*/
static volatile char * dma_chan_busy[MAX_DMA_CHANNELS] = {
0,
0,
0,
0,
"cascade",
0,
0,
0
};
/* Atomically swap memory location [32 bits] with `newval'.
* This avoid the cli()/sti() junk and related problems.
......@@ -60,15 +70,28 @@ static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsi
} /* mutex_atomic_swap */
int get_dma_list(char *buf)
{
int i, len = 0;
int request_dma(unsigned int dmanr)
for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
if (dma_chan_busy[i]) {
len += sprintf(buf+len, "%2d: %s\n",
i,
dma_chan_busy[i]);
}
}
return len;
}
int request_dma(unsigned int dmanr, char * deviceID)
{
if (dmanr >= MAX_DMA_CHANNELS)
return -EINVAL;
if (mutex_atomic_swap(&dma_chan_busy[dmanr], 1) != 0)
if (mutex_atomic_swap((unsigned int *) &dma_chan_busy[dmanr], (unsigned int) deviceID) != 0)
return -EBUSY;
else
/* old flag was 0, now contains 1 to indicate busy */
return 0;
} /* request_dma */
......@@ -81,7 +104,10 @@ void free_dma(unsigned int dmanr)
return;
}
if (mutex_atomic_swap(&dma_chan_busy[dmanr], 0) == 0)
if (mutex_atomic_swap((unsigned int *) &dma_chan_busy[dmanr], 0) == 0) {
printk("Trying to free free DMA%d\n", dmanr);
return;
}
} /* free_dma */
......@@ -41,7 +41,7 @@ extern char * ftape_big_buffer;
extern void (*do_floppy)(void);
#endif
extern int request_dma(unsigned int dmanr);
extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr);
extern int do_execve(char * filename, char ** argv, char ** envp,
......
......@@ -177,8 +177,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
switch(sel_type)
{
case SEL_IN:
if ((sk->type==SOCK_SEQPACKET || sk->type==SOCK_NCP)
&& sk->state==TCP_CLOSE)
if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
{
/* Connection closed: Wake up */
return(1);
......
......@@ -56,16 +56,8 @@
#include <linux/termios.h> /* For TIOCOUTQ/INQ */
#include <linux/interrupt.h>
#include "p8022.h"
#include "ncp.h"
#ifdef CONFIG_IPX
static void ipx_delete_timer (ipx_socket *sk);
static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
void *ubuf, int len, int flag, unsigned char type);
static void ipx_add_timer (ipx_socket *sk, int len);
static void ipx_reset_timer (ipx_socket *sk, int len);
/***********************************************************************************************************************\
* *
* Handlers for the socket list. *
......@@ -83,9 +75,7 @@ static ipx_socket *volatile ipx_socket_list=NULL;
static void ipx_remove_socket(ipx_socket *sk)
{
ipx_socket *s;
unsigned long flags;
save_flags(flags);
cli();
s=ipx_socket_list;
if(s==sk)
......@@ -99,23 +89,20 @@ static void ipx_remove_socket(ipx_socket *sk)
if(s->next==sk)
{
s->next=sk->next;
restore_flags(flags);
sti();
return;
}
s=s->next;
}
restore_flags(flags);
sti();
}
static void ipx_insert_socket(ipx_socket *sk)
{
unsigned long flags;
save_flags(flags);
cli();
sk->next=ipx_socket_list;
ipx_socket_list=sk;
restore_flags(flags);
sti();
}
static ipx_socket *ipx_find_socket(int port)
......@@ -146,10 +133,9 @@ static void ipx_destroy_socket(ipx_socket *sk)
ipx_remove_socket(sk);
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{
kfree_skb(skb,FREE_READ);
while((skb=skb_dequeue(&sk->write_queue))!=NULL)
kfree_skb(skb,FREE_WRITE);
}
kfree_s(sk,sizeof(*sk));
}
......@@ -165,24 +151,20 @@ int ipx_get_info(char *buffer, char **start, off_t offset, int length)
/* Theory.. Keep printing in the same place until we pass offset */
len += sprintf (buffer," local_address rem_address tx_queue rx_queue st uid\n");
len += sprintf (buffer,"Type local_address rem_address tx_queue rx_queue st uid\n");
for (s = ipx_socket_list; s != NULL; s = s->next)
{
len += sprintf (buffer+len,"%02X ", s->ipx_type);
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%04X ", htonl(s->ipx_source_addr.net),
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_source_addr.net),
s->ipx_source_addr.node[0], s->ipx_source_addr.node[1], s->ipx_source_addr.node[2],
s->ipx_source_addr.node[3], s->ipx_source_addr.node[4], s->ipx_source_addr.node[5],
htons(s->ipx_source_addr.sock));
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%04X ", htonl(s->ipx_dest_addr.net),
len += sprintf (buffer+len,"%08lX:%02X%02X%02X%02X%02X%02X:%02X ", htonl(s->ipx_dest_addr.net),
s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1], s->ipx_dest_addr.node[2],
s->ipx_dest_addr.node[3], s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5],
htons(s->ipx_dest_addr.sock));
len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc);
len += sprintf (buffer+len,"%02X ", s->state);
if (s->socket)
len += sprintf (buffer+len,"%d\n", SOCK_INODE(s->socket)->i_uid);
else
len += sprintf (buffer+len,"%d\n", SOCK_INODE(s->ncp.ncp->socket)->i_uid);
len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid);
/* Are we still dumping unwanted data then discard the record */
pos=begin+len;
......@@ -483,7 +465,7 @@ int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length)
static int ipx_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
/* ipx_socket *sk=(ipx_socket *)sock->data; */
ipx_socket *sk=(ipx_socket *)sock->data;
switch(cmd)
{
default:
......@@ -584,56 +566,20 @@ static void def_callback2(struct sock *sk, int len)
wake_up_interruptible(sk->sleep);
}
static void watch_callback(struct sock *sk, int len)
{
ipx_packet *ipx;
struct sk_buff *skb;
char *data;
skb=skb_dequeue(&sk->receive_queue);
if(skb==NULL)
return;
ipx = (ipx_packet *)(skb->h.raw);
data = (char *)(ipx+1);
if (*(data+1) == '?')
ipx_do_sendto(sk,&(ipx->ipx_source),"\0Y",2,0,sk->ipx_type);
kfree_skb(skb, FREE_READ);
}
static void mail_callback(struct sock *sk, int len)
static int ipx_create(struct socket *sock, int protocol)
{
ipx_packet *ipx;
struct sk_buff *skb;
char *data;
skb=skb_dequeue(&sk->receive_queue);
if(skb==NULL)
return;
ipx = (ipx_packet *)(skb->h.raw);
data = (char *)(ipx+1);
if (*(data+1) == '!')
ipx_socket *sk;
sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
if(sk==NULL)
return(-ENOMEM);
switch(sock->type)
{
struct ncp_request_sf req;
req.func=0x15;
req.s_func=0x01;
req.s_len=htons(1);
ipx_do_sendto(sk->ncp.ncp, &(sk->ncp.ncp->ipx_dest_addr),
&req, sizeof(req), 0,sk->ncp.ncp->ipx_type);
case SOCK_DGRAM:
break;
default:
kfree_s((void *)sk,sizeof(*sk));
return(-ESOCKTNOSUPPORT);
}
kfree_skb(skb, FREE_READ);
}
static void ipx_do_create(struct socket *sock, ipx_socket *sk)
{
sk->dead=0;
sk->next=NULL;
sk->broadcast=0;
......@@ -652,6 +598,7 @@ static void ipx_do_create(struct socket *sock, ipx_socket *sk)
skb_queue_head_init(&sk->back_log);
sk->state=TCP_CLOSE;
sk->socket=sock;
sk->type=sock->type;
sk->ipx_type=0; /* General user level IPX */
sk->debug=0;
......@@ -663,76 +610,14 @@ static void ipx_do_create(struct socket *sock, ipx_socket *sk)
{
sock->data=(void *)sk;
sk->sleep=sock->wait;
sk->type=sock->type;
}
else
sk->type=SOCK_DGRAM;
sk->priority=SOPRI_NORMAL;
sk->state_change=def_callback1;
sk->data_ready=def_callback2;
sk->write_space=def_callback1;
sk->error_report=def_callback1;
sk->zapped=1;
return;
}
static int ncp_create(struct socket *sock, int protocol)
{
ipx_socket *sk;
ipx_socket *skw;
ipx_socket *skm;
if ((sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL))==NULL)
return(-ENOMEM);
if ((skw=(ipx_socket *)kmalloc(sizeof(*skw),GFP_KERNEL))==NULL)
{
kfree_s((void *)sk, sizeof(*sk));
return(-ENOMEM);
}
if ((skm=(ipx_socket *)kmalloc(sizeof(*skm),GFP_KERNEL))==NULL)
{
kfree_s((void *)skw, sizeof(*skw));
kfree_s((void *)sk, sizeof(*sk));
return(-ENOMEM);
}
ipx_do_create(sock, sk);
sk->ncp.ncp=NULL;
sk->ncp.watchdog=skw;
sk->ncp.mail=skm;
ipx_do_create(NULL, skw);
skw->ncp.ncp=sk;
skw->data_ready=watch_callback;
ipx_do_create(NULL, skm);
skm->ncp.ncp=sk;
skm->data_ready=mail_callback;
return(0);
}
static int ipx_create(struct socket *sock, int protocol)
{
ipx_socket *sk;
switch(sock->type)
{
case SOCK_DGRAM:
break;
case SOCK_NCP:
return(ncp_create(sock, protocol));
default:
return(-ESOCKTNOSUPPORT);
}
if ((sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL))==NULL)
return(-ENOMEM);
ipx_do_create(sock, sk);
return(0);
}
......@@ -748,72 +633,40 @@ static int ipx_release(struct socket *sock, struct socket *peer)
return(0);
if(!sk->dead)
sk->state_change(sk);
sock->data=NULL;
if (sk->type == SOCK_NCP)
{
sk->ncp.watchdog->dead=1;
ipx_destroy_socket(sk->ncp.watchdog);
sk->ncp.mail->dead=1;
ipx_destroy_socket(sk->ncp.mail);
if ((sk->state == TCP_ESTABLISHED) || (sk->state == TCP_SYN_SENT))
{
struct ncp_request req;
sk->state=TCP_CLOSE_WAIT;
ipx_do_sendto(sk, &(sk->ipx_dest_addr), &req,
sizeof(req), 0, sk->ipx_type);
}
else
{
sk->dead=1;
if (sk->state != TCP_CLOSE)
ipx_delete_timer(sk);
ipx_destroy_socket(sk);
}
}
else
{
sk->dead=1;
sock->data=NULL;
ipx_destroy_socket(sk);
}
return(0);
}
static unsigned short first_free_socketnum(void)
{
static unsigned short socketNum = 0x3fff;
static unsigned short socketNum = 0x4000;
while (ipx_find_socket(htons(++socketNum)) != NULL)
if (socketNum > 0x7ffc) socketNum = 0x3fff;
while (ipx_find_socket(htons(socketNum)) != NULL)
if (socketNum > 0x7ffc) socketNum = 0x4000;
return htons(socketNum);
return htons(socketNum++);
}
static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
{
ipx_socket *sk=(ipx_socket *)sock->data;
ipx_socket *sk;
struct ipx_route *rt;
unsigned char *nodestart;
struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
sk=(ipx_socket *)sock->data;
if(sk->zapped==0)
return(-EIO);
if(addr_len!=sizeof(struct sockaddr_ipx))
return -EINVAL;
if (addr->sipx_port == 0)
{
addr->sipx_port = first_free_socketnum();
if (sk->type == SOCK_NCP)
while ((ipx_find_socket(htons(ntohs(addr->sipx_port)+1)))
|| (ipx_find_socket(htons(ntohs(addr->sipx_port)+2))))
addr->sipx_port = first_free_socketnum();
if (addr->sipx_port == 0)
return -EINVAL;
}
......@@ -832,19 +685,6 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
return -EADDRINUSE;
}
if (sk->type == SOCK_NCP)
{
if ((ipx_find_socket(htons(ntohs(addr->sipx_port)+1)))
|| (ipx_find_socket(htons(ntohs(addr->sipx_port)+2))))
{
if(sk->debug)
printk("IPX: bind failed because port %X in use.\n",
(int)addr->sipx_port);
return -EADDRINUSE;
}
addr->sipx_type=IPX_TYPE_NCP;
}
sk->ipx_source_addr.sock=addr->sipx_port;
if (addr->sipx_network == 0L)
......@@ -865,7 +705,6 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
}
sk->ipx_source_addr.net=rt->net;
sk->ipx_type=addr->sipx_type;
/* IPX addresses zero pad physical addresses less than 6 */
memset(sk->ipx_source_addr.node,'\0',6);
......@@ -874,102 +713,41 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
ipx_insert_socket(sk);
sk->zapped=0;
if (sk->type == SOCK_NCP)
{
sk->ncp.watchdog->ipx_source_addr.net=rt->net;
sk->ncp.watchdog->ipx_source_addr.sock=htons(ntohs(addr->sipx_port)+1);
memset(sk->ncp.watchdog->ipx_source_addr.node,'\0',6);
nodestart = sk->ncp.watchdog->ipx_source_addr.node + (6 - rt->dev->addr_len);
memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len);
ipx_insert_socket(sk->ncp.watchdog);
sk->ncp.watchdog->zapped=0;
sk->ncp.mail->ipx_source_addr.net=rt->net;
sk->ncp.mail->ipx_source_addr.sock=htons(ntohs(addr->sipx_port)+2);
memset(sk->ncp.mail->ipx_source_addr.node,'\0',6);
nodestart = sk->ncp.mail->ipx_source_addr.node + (6 - rt->dev->addr_len);
memcpy(nodestart,rt->dev->dev_addr,rt->dev->addr_len);
ipx_insert_socket(sk->ncp.mail);
sk->ncp.mail->zapped=0;
sk->mtu=rt->dev->mtu;
}
if(sk->debug)
printk("IPX: socket is bound.\n");
return(0);
}
static int ncp_connect(struct socket *sock, ipx_socket *sk)
{
struct ncp_request req;
int err;
sk->ncp.conn=0xffff;
sk->ncp.seq=0;
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
sk->rto = 0;
ipx_do_sendto(sk, &(sk->ipx_dest_addr), &req, sizeof(req), 0, sk->ipx_type);
while(sk->state != TCP_ESTABLISHED)
{
if (sk->err)
{
err=sk->err;
sk->err=0;
return -err;
}
interruptible_sleep_on(sk->sleep);
}
return(0);
}
static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags)
{
ipx_socket *sk=(ipx_socket *)sock->data;
struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
struct sockaddr_ipx *addr;
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
if(addr_len!=sizeof(struct sockaddr_ipx))
if(addr_len!=sizeof(addr))
return(-EINVAL);
addr=(struct sockaddr_ipx *)uaddr;
if(sk->ipx_source_addr.sock==0)
if(sk->ipx_source_addr.net==0)
/* put the autobinding in */
{
struct sockaddr_ipx uaddr;
int ret;
struct sockaddr_ipx addr;
addr.sipx_type = 0;
addr.sipx_port = 0;
addr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_ipx));
uaddr.sipx_port = 0;
uaddr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
sk->ipx_dest_addr.net=addr->sipx_network;
sk->ipx_dest_addr.sock=addr->sipx_port;
memcpy(sk->ipx_dest_addr.node,addr->sipx_node,sizeof(sk->ipx_source_addr.node));
if(ipxrtr_get_dev(sk->ipx_dest_addr.net)==NULL)
return -ENETUNREACH;
if (sk->type == SOCK_NCP)
return(ncp_connect(sock, sk));
sk->ipx_type=addr->sipx_type;
sock->state = SS_CONNECTED;
sk->state=TCP_ESTABLISHED;
return(0);
......@@ -992,8 +770,9 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
{
ipx_address *addr;
struct sockaddr_ipx sipx;
ipx_socket *sk=(ipx_socket *)sock->data;
ipx_socket *sk;
sk=(ipx_socket *)sock->data;
*uaddr_len = sizeof(struct sockaddr_ipx);
......@@ -1004,21 +783,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
addr=&sk->ipx_dest_addr;
}
else
{
if(sk->ipx_source_addr.sock==0)
/* put the autobinding in */
{
int ret;
sipx.sipx_type = 0;
sipx.sipx_port = 0;
sipx.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&sipx, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
addr=&sk->ipx_source_addr;
}
sipx.sipx_family = AF_IPX;
sipx.sipx_port = addr->sock;
......@@ -1028,472 +793,67 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
return(0);
}
static int ipx_build_header(ipx_address *ipx, struct sk_buff *skb,
ipx_socket *sk, int len, unsigned char type)
int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
ipx_packet *ipx_pack;
/* NULL here for pt means the packet was looped back */
ipx_socket *sock;
ipx_packet *ipx;
ipx_route *rt;
struct datalink_proto *dl = NULL;
ipx_route *ln;
unsigned char IPXaddr[6];
int self_addressing = 0;
int broadcast = 0;
if(sk->debug)
printk("IPX: build_header: Addresses built.\n");
ipx=(ipx_packet *)skb->h.raw;
if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0)
if(ipx->ipx_checksum!=IPX_NO_CHECKSUM)
{
if (!sk->broadcast)
return -ENETUNREACH;
broadcast = 1;
/* We don't do checksum options. We can't really. Novell don't seem to have documented them.
If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be
the same... */
kfree_skb(skb,FREE_READ);
return(0);
}
/* Build a packet */
if(sk->debug)
printk("IPX: build_header: building packet.\n");
/* Find out where this has to go */
if (ipx->net == 0L) {
rt = ipxrtr_get_default_net();
if (rt != NULL)
ipx->net = rt->net;
} else
rt=ipxrtr_get_dev(ipx->net);
if(rt==NULL)
/* Too small */
if(htons(ipx->ipx_pktsize)<sizeof(ipx_packet))
{
return -ENETUNREACH;
kfree_skb(skb,FREE_READ);
return(0);
}
dl=rt->datalink;
skb->mem_addr=skb;
skb->sk=sk;
skb->free=1;
skb->arp=1;
skb->tries=0;
if(sk->debug)
printk("Building MAC header.\n");
skb->dev=rt->dev;
/* Too many hops */
if(ipx->ipx_tctrl>16)
{
kfree_skb(skb,FREE_READ);
return(0);
}
/* Build Data Link header */
dl->datalink_header(dl, skb,
(rt->flags&IPX_RT_ROUTED)?rt->router_node:ipx->node);
/* Determine what local ipx endpoint this is */
ln = ipxrtr_get_local_net(dev, pt->type);
if (ln == NULL)
{
kfree_skb(skb,FREE_READ);
return(0);
}
/* See if we are sending to ourself */
memset(IPXaddr, '\0', 6);
memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr,
skb->dev->addr_len);
memcpy(IPXaddr+(6 - dev->addr_len), dev->dev_addr, dev->addr_len);
self_addressing = !memcmp(IPXaddr,
(rt->flags&IPX_RT_ROUTED)?rt->router_node
:ipx->node,
6);
/* Not us/broadcast */
if(memcmp(IPXaddr,ipx->ipx_dest.node,6)!=0
&& memcmp(ipx_broadcast_node,ipx->ipx_dest.node,6)!=0)
{
/**********************************************************************************************
/* Now the IPX */
if(sk->debug)
printk("Building IPX Header.\n");
ipx_pack=(ipx_packet *)skb->h.raw;
ipx_pack->ipx_checksum=0xFFFF;
ipx_pack->ipx_pktsize=htons(len+sizeof(ipx_packet));
ipx_pack->ipx_tctrl=0;
ipx_pack->ipx_type=type;
IPX router. Roughly as per the Novell spec. This doesn't handle netbios flood fill
broadcast frames. See the Novell IPX router specification for more details
(for ftp from ftp.novell.com)
memcpy(&ipx_pack->ipx_source,&sk->ipx_source_addr,sizeof(ipx_pack->ipx_source));
memcpy(&ipx_pack->ipx_dest,ipx,sizeof(ipx_pack->ipx_dest));
***********************************************************************************************/
if((skb->dev->flags&IFF_LOOPBACK) || self_addressing)
skb->pkt_type=PACKET_HOST;
else
if (broadcast)
skb->pkt_type=PACKET_BROADCAST;
else
skb->pkt_type=PACKET_OTHERHOST;
return 0;
}
static int ipx_xmit(struct sk_buff *skb)
{
struct sk_buff *skb1;
struct device *dev= skb->dev;
ipx_packet *ipx=(ipx_packet *)skb->h.raw;
ipx_route *rt;
struct packet_type pt;
if (ipx->ipx_dest.net == 0L)
rt = ipxrtr_get_default_net();
else
rt=ipxrtr_get_dev(ipx->ipx_dest.net);
if (rt == NULL)
return -ENETUNREACH;
pt.type=rt->dlink_type;
skb->tries++;
switch (skb->pkt_type)
{
case PACKET_HOST:
if (!skb->free)
{
skb1=alloc_skb(skb->len, GFP_ATOMIC);
if (skb1 != NULL)
{
skb1->mem_addr=skb1;
skb1->free=1;
skb1->arp=1;
skb1->len=skb->len;
skb1->sk = NULL;
skb1->h.raw = skb1->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb1->data, skb->data, skb->len);
ipx_rcv(skb1,dev,&pt);
}
}
else
{
/* loop back */
skb->sk->wmem_alloc-=skb->mem_len;
skb->sk = NULL;
ipx_rcv(skb,dev,&pt);
}
break;
case PACKET_BROADCAST:
skb1=alloc_skb(skb->len, GFP_ATOMIC);
if (skb1 != NULL)
{
skb1->mem_addr=skb1;
skb1->free=1;
skb1->arp=1;
skb1->len=skb->len;
skb1->sk = NULL;
skb1->h.raw = skb1->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb1->data, skb->data, skb->len);
ipx_rcv(skb1,dev,&pt);
}
default:
if (!skb->free)
{
skb1=alloc_skb(skb->len, GFP_ATOMIC);
if (skb1 != NULL)
{
skb1->mem_addr=skb1;
skb1->free=1;
skb1->arp=1;
skb1->len=skb->len;
skb1->sk = NULL;
skb1->h.raw = skb1->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb1->data, skb->data, skb->len);
}
}
else
skb1=skb;
if (skb1 != NULL)
{
if (skb1->sk)
dev_queue_xmit(skb1,dev,skb->sk->priority);
else
dev_queue_xmit(skb1,dev,SOPRI_NORMAL);
}
}
return(0);
}
static int ipx_retransmit(ipx_socket *sk)
{
struct sk_buff *skb = sk->write_queue.next;
int num=0;
ipx_packet *ipx;
struct ncp_request *req;
if (skb == NULL)
return(num);
if (skb == skb->next)
return(num);
do
{
ipx=(ipx_packet *)skb->h.raw;
req=(struct ncp_request *)(ipx+1);
ipx_xmit(skb);
num++;
skb=skb->next;
}
while (skb->next != sk->write_queue.next);
return (num);
}
static void ipx_timer (unsigned long data)
{
ipx_socket *sk = (ipx_socket *) data;
int num;
cli();
if (in_bh)
{
sk->timer.expires = 10;
add_timer(&sk->timer);
sti();
return;
}
sti();
num=ipx_retransmit(sk);
sk->rto++;
if (sk->rto >= MAX_TIMEOUT)
{
struct sk_buff *skb;
while((skb=skb_dequeue(&sk->write_queue))!=NULL)
kfree_skb(skb,FREE_WRITE);
sk->err=ETIMEDOUT;
sk->state=TCP_CLOSE;
sk->socket->state=SS_UNCONNECTED;
if(!sk->dead)
sk->error_report(sk);
return;
}
if (num)
ipx_reset_timer(sk, NCP_TIMEOUT);
return;
}
static void ipx_delete_timer (ipx_socket *sk)
{
unsigned long flags;
save_flags (flags);
cli();
del_timer (&sk->timer);
restore_flags(flags);
}
static void ipx_add_timer (ipx_socket *sk, int len)
{
init_timer (&sk->timer);
sk->timer.data = (unsigned long) sk;
sk->timer.function = &ipx_timer;
sk->timer.expires = len;
add_timer(&sk->timer);
}
static void ipx_reset_timer (ipx_socket *sk, int len)
{
ipx_delete_timer (sk);
sk->timer.data = (unsigned long) sk;
sk->timer.function = &ipx_timer;
sk->timer.expires = len;
add_timer(&sk->timer);
}
static struct sk_buff *find_req(ipx_socket *sk, unsigned char seq)
{
ipx_packet *ipx;
struct ncp_request *req;
struct sk_buff *skb = sk->write_queue.next;
if (skb == NULL)
return (NULL);
if (skb == skb->next)
return (NULL);
do
{
ipx=(ipx_packet *)skb->h.raw;
req=(struct ncp_request *)(ipx+1);
if (req->seq == seq)
{
skb_unlink(skb);
return (skb);
}
skb=skb->next;
}
while (skb->next != sk->write_queue.next);
return (NULL);
}
static int ncp_rcv(ipx_socket *sk, struct sk_buff *skb)
{
ipx_packet *ipx=(ipx_packet *)skb->h.raw;
struct ncp_reply *rep= (struct ncp_reply *)(ipx+1);
struct ncp_request_sf *req;
struct sk_buff *skb1;
if (rep->p_type != NCP_REPLY)
{
kfree_skb(skb, FREE_READ);
return (0);
}
skb1=find_req(sk, rep->seq);
if (skb1 == NULL)
{
kfree_skb(skb, FREE_READ);
return (0);
}
if (&sk->write_queue == sk->write_queue.next)
{
sk->rto=0;
ipx_delete_timer(sk);
}
ipx=(ipx_packet *)skb1->h.raw;
req=(struct ncp_request_sf *)(ipx+1);
switch (sk->state)
{
case TCP_CLOSE_WAIT:
kfree_skb(skb, FREE_READ);
sk->socket->data = NULL;
sk->state=TCP_CLOSE;
if(!sk->dead)
sk->state_change(sk);
sk->dead=1;
if (&sk->write_queue != sk->write_queue.next)
ipx_delete_timer(sk);
ipx_destroy_socket(sk);
break;
case TCP_SYN_SENT:
if ((rep->f_stat == 0) && (rep->c_stat == 0))
{
sk->state=TCP_ESTABLISHED;
sk->socket->state = SS_CONNECTED;
sk->ncp.conn=rep->c_low + (rep->c_high * 0xff);
if(!sk->dead)
sk->state_change(sk);
}
else
{
sk->state=TCP_CLOSE;
sk->socket->state = SS_UNCONNECTED;
sk->err=ECONNREFUSED;
if (&sk->write_queue != sk->write_queue.next)
ipx_delete_timer(sk);
if(!sk->dead)
sk->error_report(sk);
}
kfree_skb(skb, FREE_READ);
break;
default:
if ((req->func==0x15)&&(req->s_func==0x01))
{
char *data = (char *)(rep+1);
int len=(int)*data;
if (len != 0)
{
memcpy(data, data+1, len);
*(data+len)='\0';
printk("\007%s\n",data);
}
kfree_skb(skb, FREE_READ);
}
else
{
sk->rmem_alloc+=skb->mem_len;
skb->sk = sk;
skb_queue_tail(&sk->receive_queue,skb);
if(!sk->dead)
sk->data_ready(sk,skb->len);
}
}
kfree_skb(skb1, FREE_WRITE);
return(0);
}
int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{
/* NULL here for pt means the packet was looped back */
ipx_socket *sock;
ipx_packet *ipx;
ipx_route *rt;
ipx_route *ln;
unsigned char IPXaddr[6];
ipx=(ipx_packet *)skb->h.raw;
if(ipx->ipx_checksum!=IPX_NO_CHECKSUM)
{
/* We don't do checksum options. We can't really. Novell don't seem to have documented them.
If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be
the same... */
kfree_skb(skb,FREE_READ);
return(0);
}
/* Too small */
if(htons(ipx->ipx_pktsize)<sizeof(ipx_packet))
{
kfree_skb(skb,FREE_READ);
return(0);
}
/* Too many hops */
if(ipx->ipx_tctrl>16)
{
kfree_skb(skb,FREE_READ);
return(0);
}
/* Determine what local ipx endpoint this is */
ln = ipxrtr_get_local_net(dev, pt->type);
if (ln == NULL)
{
kfree_skb(skb,FREE_READ);
return(0);
}
memset(IPXaddr, '\0', 6);
memcpy(IPXaddr+(6 - dev->addr_len), dev->dev_addr, dev->addr_len);
/* Not us/broadcast */
if(memcmp(IPXaddr,ipx->ipx_dest.node,6)!=0
&& memcmp(ipx_broadcast_node,ipx->ipx_dest.node,6)!=0)
{
/**********************************************************************************************
IPX router. Roughly as per the Novell spec. This doesn't handle netbios flood fill
broadcast frames. See the Novell IPX router specification for more details
(for ftp from ftp.novell.com)
***********************************************************************************************/
int incoming_size;
int outgoing_size;
struct sk_buff *skb2;
int free_it=0;
int incoming_size;
int outgoing_size;
struct sk_buff *skb2;
int free_it=0;
/* Rule: Don't forward packets that have exceeded the hop limit. This is fixed at 16 in IPX */
if(ipx->ipx_tctrl==16)
......@@ -1583,9 +943,6 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0);
}
if (sock->type == SOCK_NCP)
return (ncp_rcv(sock, skb));
sock->rmem_alloc+=skb->mem_len;
skb->sk = sock;
......@@ -1595,27 +952,65 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0);
}
static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
void *ubuf, int len, int flag, unsigned char type)
static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
unsigned flags, struct sockaddr *usip, int addr_len)
{
ipx_socket *sk=(ipx_socket *)sock->data;
struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
struct sockaddr_ipx local_sipx;
struct sk_buff *skb;
struct device *dev;
ipx_packet *ipx_pack;
struct ipx_packet *ipx;
int size;
ipx_route *rt;
struct datalink_proto *dl = NULL;
unsigned char IPXaddr[6];
int self_addressing = 0;
int broadcast = 0;
if(flags)
return -EINVAL;
if(sk->debug)
printk("IPX: sendto: Addresses built.\n");
if(usipx)
{
if(sk->ipx_source_addr.net==0)
/* put the autobinding in */
{
struct sockaddr_ipx uaddr;
int ret;
uaddr.sipx_port = 0;
uaddr.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
if ((sk->type == SOCK_NCP) && (len < sizeof (struct ncp_request)))
if(addr_len <sizeof(*usipx))
return(-EINVAL);
if(usipx->sipx_family != AF_IPX)
return -EINVAL;
if(htons(usipx->sipx_port)<0x4000 && !suser())
return -EPERM;
}
else
{
if(sk->state!=TCP_ESTABLISHED)
return -ENOTCONN;
usipx=&local_sipx;
usipx->sipx_family=AF_IPX;
usipx->sipx_port=sk->ipx_dest_addr.sock;
usipx->sipx_network=sk->ipx_dest_addr.net;
memcpy(usipx->sipx_node,sk->ipx_dest_addr.node,sizeof(usipx->sipx_node));
}
if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0)
if(sk->debug)
printk("IPX: sendto: Addresses built.\n");
if(memcmp(&usipx->sipx_node,&ipx_broadcast_node,6)==0)
{
if (!sk->broadcast)
return -ENETUNREACH;
broadcast = 1;
}
/* Build a packet */
......@@ -1626,12 +1021,12 @@ static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
size=sizeof(ipx_packet)+len; /* For mac headers */
/* Find out where this has to go */
if (ipx->net == 0L) {
if (usipx->sipx_network == 0L) {
rt = ipxrtr_get_default_net();
if (rt != NULL)
ipx->net = rt->net;
usipx->sipx_network = rt->net;
} else
rt=ipxrtr_get_dev(ipx->net);
rt=ipxrtr_get_dev(usipx->sipx_network);
if(rt==NULL)
{
......@@ -1651,118 +1046,87 @@ static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
return -EAGAIN;
}
if (flag)
skb=alloc_skb(size,GFP_KERNEL);
else
skb=alloc_skb(size,GFP_ATOMIC);
if(skb==NULL)
return -ENOMEM;
sk->wmem_alloc+=skb->mem_len;
skb->mem_addr=skb;
skb->sk=sk;
skb->free=1;
skb->arp=1;
skb->len=size;
ipx_build_header(ipx, skb, sk, len, type);
ipx_pack = (ipx_packet *)(skb->h.raw);
/* User data follows immediately after the IPX data */
if (flag)
memcpy_fromfs((char *)(ipx_pack+1),ubuf,len);
else
memcpy((char *)(ipx_pack+1),ubuf,len);
if (sk->type == SOCK_NCP)
{
struct ncp_request *req=(struct ncp_request *)(ipx_pack+1);
sk->wmem_alloc+=skb->mem_len;
switch (sk->state)
{
case TCP_SYN_SENT:
req->p_type = NCP_OPEN;
break;
case TCP_CLOSE_WAIT:
req->p_type = NCP_CLOSE;
break;
default:
req->p_type = NCP_REQUEST;
}
req->c_low = (sk->ncp.conn) & 0xff;
req->c_high = (sk->ncp.conn >>8) & 0xff;
req->seq = (sk->ncp.seq)++;
req->task = 1;
if(sk->debug)
printk("Building MAC header.\n");
skb->dev=rt->dev;
skb->free=0;
/* Build Data Link header */
dl->datalink_header(dl, skb,
(rt->flags&IPX_RT_ROUTED)?rt->router_node:usipx->sipx_node);
if (&sk->write_queue == sk->write_queue.next)
ipx_add_timer(sk, NCP_TIMEOUT);
else
ipx_reset_timer(sk, NCP_TIMEOUT);
/* See if we are sending to ourself */
memset(IPXaddr, '\0', 6);
memcpy(IPXaddr+(6 - skb->dev->addr_len), skb->dev->dev_addr,
skb->dev->addr_len);
skb_queue_tail(&sk->write_queue,skb);
}
self_addressing = !memcmp(IPXaddr,
(rt->flags&IPX_RT_ROUTED)?rt->router_node
:usipx->sipx_node,
6);
/* Now the IPX */
if(sk->debug)
printk("Building IPX Header.\n");
ipx=(ipx_packet *)skb->h.raw;
ipx->ipx_checksum=0xFFFF;
ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
ipx->ipx_tctrl=0;
ipx->ipx_type=usipx->sipx_type;
memcpy(&ipx->ipx_source,&sk->ipx_source_addr,sizeof(ipx->ipx_source));
ipx->ipx_dest.net=usipx->sipx_network;
memcpy(ipx->ipx_dest.node,usipx->sipx_node,sizeof(ipx->ipx_dest.node));
ipx->ipx_dest.sock=usipx->sipx_port;
if(sk->debug)
printk("IPX: Appending user data.\n");
/* User data follows immediately after the IPX data */
memcpy_fromfs((char *)(ipx+1),ubuf,len);
if(sk->debug)
printk("IPX: Transmitting buffer\n");
if((dev->flags&IFF_LOOPBACK) || self_addressing) {
struct packet_type pt;
ipx_xmit(skb);
return len;
}
static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
unsigned flags, struct sockaddr *usip, int addr_len)
{
ipx_socket *sk=(ipx_socket *)sock->data;
ipx_address ipx;
struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
struct sockaddr_ipx local_sipx;
if(flags)
return -EINVAL;
if(usipx)
{
if (sk->type == SOCK_NCP)
return -EINVAL;
if(sk->ipx_source_addr.sock==0)
/* put the autobinding in */
{
int ret;
local_sipx.sipx_type = 0;
local_sipx.sipx_port = 0;
local_sipx.sipx_network = 0L;
ret = ipx_bind (sock, (struct sockaddr *)&local_sipx, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret);
}
/* loop back */
pt.type = rt->dlink_type;
sk->wmem_alloc-=skb->mem_len;
skb->sk = NULL;
ipx_rcv(skb,dev,&pt);
} else {
if (broadcast) {
struct packet_type pt;
struct sk_buff *skb2;
if(addr_len <sizeof(*usipx))
return(-EINVAL);
if(usipx->sipx_family != AF_IPX)
return -EINVAL;
if(htons(usipx->sipx_port)<0x4000 && !suser())
return -EPERM;
/* loop back */
pt.type = rt->dlink_type;
ipx.net=usipx->sipx_network;
ipx.sock=usipx->sipx_port;
memcpy(ipx.node,usipx->sipx_node, sizeof(ipx.node));
return (ipx_do_sendto(sk, &ipx, ubuf, len, 1,
usipx->sipx_type));
skb2=alloc_skb(skb->len, GFP_ATOMIC);
skb2->mem_addr=skb2;
skb2->free=1;
skb2->arp=1;
skb2->len=skb->len;
skb2->sk = NULL;
skb2->h.raw = skb2->data + rt->datalink->header_length
+ dev->hard_header_len;
memcpy(skb2->data, skb->data, skb->len);
ipx_rcv(skb2,dev,&pt);
}
else
{
if(sk->state!=TCP_ESTABLISHED)
return -ENOTCONN;
return (ipx_do_sendto(sk, &(sk->ipx_dest_addr), ubuf,
len, 1, sk->ipx_type));
dev_queue_xmit(skb,dev,SOPRI_NORMAL);
}
return len;
}
static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
{
return ipx_sendto(sock,ubuf,size,noblock,flags,NULL,0);
......@@ -1806,14 +1170,12 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
sipx->sipx_type = ipx->ipx_type;
}
skb_free_datagram(skb);
return(copied);
}
static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock)
{
return ipx_send(sock,ubuf,size,noblock,0);
}
......
......@@ -41,7 +41,6 @@
#endif
#ifdef CONFIG_IPX
#include "ipx.h"
#include "ncp.h"
#endif
#define SOCK_ARRAY_SIZE 64
......@@ -138,7 +137,6 @@ struct sock {
#ifdef CONFIG_IPX
ipx_address ipx_source_addr,ipx_dest_addr;
unsigned short ipx_type;
struct ncp_info ncp;
#endif
#ifdef CONFIG_AX25
/* Really we want to add a per protocol private area */
......
......@@ -592,8 +592,7 @@ static int sock_socket(int family, int type, int protocol)
if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
type != SOCK_SEQPACKET && type != SOCK_RAW &&
type != SOCK_PACKET && type != SOCK_NCP)
|| protocol < 0)
type != SOCK_PACKET) || protocol < 0)
return(-EINVAL);
/*
......
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