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

Import 1.1.48

parent 74beaae0
...@@ -228,6 +228,13 @@ S: West Hanningfield Road ...@@ -228,6 +228,13 @@ S: West Hanningfield Road
S: Great Baddow, Essex CM2 8HN S: Great Baddow, Essex CM2 8HN
S: UK 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 N: Dirk Hohndel
E: hohndel@informatik.uni-wuerzburg.de E: hohndel@informatik.uni-wuerzburg.de
D: XFree86 D: XFree86
......
VERSION = 1 VERSION = 1
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 47 SUBLEVEL = 48
ARCH = i386 ARCH = i386
...@@ -110,7 +110,10 @@ boot: ...@@ -110,7 +110,10 @@ boot:
include/asm: include/asm:
( cd include ; ln -sf asm-$(ARCH) 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 config.in: arch/$(ARCH)/config.in
cp $< $@ cp $< $@
...@@ -183,7 +186,7 @@ mrproper: clean ...@@ -183,7 +186,7 @@ mrproper: clean
rm -f include/linux/autoconf.h tools/version.h rm -f include/linux/autoconf.h tools/version.h
rm -f drivers/sound/local.h rm -f drivers/sound/local.h
rm -f .version .config* config.in config.old 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` rm -f .depend `find . -name .depend -print`
distclean: mrproper distclean: mrproper
......
...@@ -108,6 +108,8 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then ...@@ -108,6 +108,8 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
if [ "$CONFIG_NET_ALPHA" = "y" ]; then if [ "$CONFIG_NET_ALPHA" = "y" ]; then
bool 'EtherExpress support' CONFIG_EEXPRESS n bool 'EtherExpress support' CONFIG_EEXPRESS n
bool 'AT1700 support' CONFIG_AT1700 n bool 'AT1700 support' CONFIG_AT1700 n
bool 'NI5210 support' CONFIG_NI52 n
bool 'NI6510 support' CONFIG_NI65 n
fi fi
bool 'HP PCLAN support' CONFIG_HPLAN n bool 'HP PCLAN support' CONFIG_HPLAN n
bool 'NE2000/NE1000 support' CONFIG_NE2000 y bool 'NE2000/NE1000 support' CONFIG_NE2000 y
...@@ -118,8 +120,6 @@ bool 'EISA and on board controllers' CONFIG_NET_EISA n ...@@ -118,8 +120,6 @@ bool 'EISA and on board controllers' CONFIG_NET_EISA n
bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
fi fi
bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n 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 bool 'Pocket and portable adaptors' CONFIG_NET_POCKET n
if [ "$CONFIG_NET_POCKET" = "y" ]; then if [ "$CONFIG_NET_POCKET" = "y" ]; then
bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n 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) ...@@ -2035,7 +2035,7 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
dma_channel = cdu31a_addresses[i].dma_num; dma_channel = cdu31a_addresses[i].dma_num;
if (dma_channel > 0) if (dma_channel > 0)
{ {
if (request_dma(dma_channel)) if (request_dma(dma_channel,"cdu31a"))
{ {
dma_channel = -1; dma_channel = -1;
printk("Unable to grab DMA%d for the CDU31A driver\n", printk("Unable to grab DMA%d for the CDU31A driver\n",
......
...@@ -280,8 +280,8 @@ static struct floppy_struct floppy_type[32] = { ...@@ -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" */ { 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" */ { 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" */ { 2080,13,2,80,0,0x1C,0x01,0xCF,0x6C,"D1040" }, /* 21 1.04MB 3.5" */
{ 2240,14,2,80,0,0x1C,0x1A,0xCF,0x6C,"D1120" }, /* 22 1.12MB 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" */ { 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" */ { 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" */ { 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] = { ...@@ -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" */ { 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" */ { 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" */ { 3200,20,2,80,0,0x1C,0x00,0xCF,0x6C,"H1600" }, /* 31 1.6MB 3.5" */
}; };
...@@ -2923,7 +2923,8 @@ void floppy_init(void) ...@@ -2923,7 +2923,8 @@ void floppy_init(void)
#if N_FDC > 1 #if N_FDC > 1
fdc_state[1].address = 0x370; fdc_state[1].address = 0x370;
#endif #endif
for(fdc = 0 ; fdc < N_FDC; fdc++){ for (i = 0 ; i < N_FDC ; i++) {
fdc = i;
FDCS->dtr = -1; FDCS->dtr = -1;
FDCS->dor = 0; FDCS->dor = 0;
FDCS->reset = 0; FDCS->reset = 0;
...@@ -2932,8 +2933,9 @@ void floppy_init(void) ...@@ -2932,8 +2933,9 @@ void floppy_init(void)
} }
/* initialise drive state */ /* initialise drive state */
for ( current_drive=0; current_drive < N_DRIVE ; current_drive++){ for (i = 0; i < N_DRIVE ; i++) {
DRS->flags = 0; current_drive = i;
DRS->flags = FD_VERIFY;
DRS->generation = 0; DRS->generation = 0;
DRS->keep_data = 0; DRS->keep_data = 0;
DRS->fd_ref = 0; DRS->fd_ref = 0;
...@@ -2941,7 +2943,8 @@ void floppy_init(void) ...@@ -2941,7 +2943,8 @@ void floppy_init(void)
} }
floppy_grab_irq_and_dma(); floppy_grab_irq_and_dma();
for(fdc = 0 ; fdc < N_FDC; fdc++){ for (i = 0 ; i < N_FDC ; i++) {
fdc = i;
FDCS->rawcmd = 2; FDCS->rawcmd = 2;
if(user_reset_fdc(-1,FD_RESET_IF_NEEDED)) if(user_reset_fdc(-1,FD_RESET_IF_NEEDED))
continue; continue;
...@@ -2980,7 +2983,7 @@ int floppy_grab_irq_and_dma(void) ...@@ -2980,7 +2983,7 @@ int floppy_grab_irq_and_dma(void)
FLOPPY_IRQ); FLOPPY_IRQ);
return -1; return -1;
} }
if (request_dma(FLOPPY_DMA)) { if (request_dma(FLOPPY_DMA,"floppy")) {
printk(DEVICE_NAME printk(DEVICE_NAME
": Unable to grab DMA%d for the floppy driver\n", ": Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA); FLOPPY_DMA);
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/malloc.h> #include <linux/malloc.h>
#include <linux/string.h>
#define REALLY_SLOW_IO #define REALLY_SLOW_IO
#include <asm/system.h> #include <asm/system.h>
...@@ -234,16 +235,39 @@ static unsigned int mult_req [MAX_HD] = {0,}; /* requested MultMode count ...@@ -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 unsigned int mult_count [MAX_HD] = {0,}; /* currently enabled MultMode count */
static struct request WCURRENT; static struct request WCURRENT;
static void rawstring (char *prefix, unsigned char *s, int n) static void fixstring(unsigned char *s, int n)
{ {
if (prefix) int i;
printk(prefix); unsigned short *ss = (unsigned short *) s;
if (s && *s) {
int i; /* convert from big-endian to little-endian */
for (i=0; i < n && s[i^1] == ' '; ++i); /* skip blanks */ for (i = n ; (i -= 2) >= 0 ; ss++)
for (; i < n && s[i^1]; ++i) /* flip bytes */ *ss = (*ss >> 8) | (*ss << 8);
if (s[i^1] != ' ' || ((i+1) < n && s[(i+1)^1] != ' '))
printk("%c",s[i^1]); /* "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) ...@@ -272,15 +296,21 @@ static void identify_intr(void)
hd_info[dev].head = id.cur_heads; hd_info[dev].head = id.cur_heads;
hd_info[dev].sect = id.cur_sectors; hd_info[dev].sect = id.cur_sectors;
} }
printk (" hd%c: ", dev+'a'); fixstring (id.serial_no, sizeof(id.serial_no));
rawstring(NULL, id.model, sizeof(id.model)); fixstring (id.fw_rev, sizeof(id.fw_rev));
printk (", %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n", fixstring (id.model, sizeof(id.model));
id.cyls*id.heads*id.sectors/2048, id.buf_size/2, printk (" hd%c: %.40s, %dMB w/%dKB Cache, CHS=%d/%d/%d, MaxMult=%d\n",
hd_info[dev].cyl, hd_info[dev].head, hd_info[dev].sect, id.max_multsect); 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 */ /* save drive info for later query via HDIO_GETIDENTITY */
if (NULL != (hd_ident_info[dev] = (struct hd_driveid *)kmalloc(sizeof(id),GFP_ATOMIC))) if (NULL != (hd_ident_info[dev] = (struct hd_driveid *)kmalloc(sizeof(id),GFP_ATOMIC)))
*hd_ident_info[dev] = id; *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: */ /* flush remaining 384 (reserved/undefined) ID bytes: */
insw(HD_DATA,(char *)&id,sizeof(id)/2); insw(HD_DATA,(char *)&id,sizeof(id)/2);
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) ...@@ -335,7 +365,6 @@ static void reset_controller(void)
{ {
int i; int i;
printk(KERN_DEBUG "HD-controller reset\n");
outb_p(4,HD_CMD); outb_p(4,HD_CMD);
for(i = 0; i < 1000; i++) nop(); for(i = 0; i < 1000; i++) nop();
outb(hd_info[0].ctl & 0x0f ,HD_CMD); outb(hd_info[0].ctl & 0x0f ,HD_CMD);
...@@ -361,12 +390,15 @@ static void reset_hd(void) ...@@ -361,12 +390,15 @@ static void reset_hd(void)
} }
if (++i < NR_HD) { if (++i < NR_HD) {
if (unmask_intr[i]) { if (unmask_intr[i]) {
printk("hd%c: disabled irq-unmasking\n",i+'a'); unmask_intr[i] = DEFAULT_UNMASK_INTR;
unmask_intr[i] = 0; printk("hd%c: reset irq-unmasking to %d\n",i+'a',
DEFAULT_UNMASK_INTR);
} }
if (mult_req[i] || mult_count[i]) { if (mult_req[i] || mult_count[i]) {
printk("hd%c: disabled multiple mode\n",i+'a'); mult_count[i] = 0;
mult_req[i] = 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_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
hd_info[i].cyl,WIN_SPECIFY,&reset_hd); hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
...@@ -399,7 +431,7 @@ static void bad_rw_intr(void) ...@@ -399,7 +431,7 @@ static void bad_rw_intr(void)
if (!CURRENT) if (!CURRENT)
return; return;
dev = MINOR(CURRENT->dev) >> 6; dev = DEVICE_NR(CURRENT->dev);
if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
end_request(0); end_request(0);
special_op[dev] += recalibrate[dev] = 1; special_op[dev] += recalibrate[dev] = 1;
...@@ -607,10 +639,9 @@ static void hd_times_out(void) ...@@ -607,10 +639,9 @@ static void hd_times_out(void)
{ {
DEVICE_INTR = NULL; DEVICE_INTR = NULL;
sti(); sti();
reset = 1;
if (!CURRENT) if (!CURRENT)
return; return;
special_op [DEVICE_NR(CURRENT->dev)] ++; special_op [DEVICE_NR(CURRENT->dev)] += reset = 1;
printk(KERN_DEBUG "HD timeout\n"); printk(KERN_DEBUG "HD timeout\n");
cli(); cli();
if (++CURRENT->errors >= MAX_ERRORS) { if (++CURRENT->errors >= MAX_ERRORS) {
...@@ -761,7 +792,7 @@ static int hd_ioctl(struct inode * inode, struct file * file, ...@@ -761,7 +792,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
if ((!inode) || (!inode->i_rdev)) if ((!inode) || (!inode->i_rdev))
return -EINVAL; return -EINVAL;
dev = MINOR(inode->i_rdev) >> 6; dev = DEVICE_NR(inode->i_rdev);
if (dev >= NR_HD) if (dev >= NR_HD)
return -EINVAL; return -EINVAL;
switch (cmd) { switch (cmd) {
...@@ -877,7 +908,7 @@ static int hd_ioctl(struct inode * inode, struct file * file, ...@@ -877,7 +908,7 @@ static int hd_ioctl(struct inode * inode, struct file * file,
static int hd_open(struct inode * inode, struct file * filp) static int hd_open(struct inode * inode, struct file * filp)
{ {
int target; int target;
target = DEVICE_NR(MINOR(inode->i_rdev)); target = DEVICE_NR(inode->i_rdev);
while (busy[target]) while (busy[target])
sleep_on(&busy_wait); sleep_on(&busy_wait);
...@@ -894,7 +925,7 @@ static void hd_release(struct inode * inode, struct file * file) ...@@ -894,7 +925,7 @@ static void hd_release(struct inode * inode, struct file * file)
int target; int target;
sync_dev(inode->i_rdev); sync_dev(inode->i_rdev);
target = DEVICE_NR(MINOR(inode->i_rdev)); target = DEVICE_NR(inode->i_rdev);
access_count[target]--; access_count[target]--;
} }
...@@ -1073,7 +1104,7 @@ static int revalidate_hddisk(int dev, int maxusage) ...@@ -1073,7 +1104,7 @@ static int revalidate_hddisk(int dev, int maxusage)
int i; int i;
long flags; long flags;
target = DEVICE_NR(MINOR(dev)); target = DEVICE_NR(dev);
gdev = &GENDISK_STRUCT; gdev = &GENDISK_STRUCT;
save_flags(flags); save_flags(flags);
......
...@@ -189,6 +189,7 @@ void rd_load(void) ...@@ -189,6 +189,7 @@ void rd_load(void)
printk("Unable to grab floppy IRQ/DMA for loading ramdisk image\n"); printk("Unable to grab floppy IRQ/DMA for loading ramdisk image\n");
return; return;
} }
check_disk_change(ROOT_DEV);
do_load(); do_load();
floppy_release_irq_and_dma(); floppy_release_irq_and_dma();
} }
...@@ -167,7 +167,7 @@ static void xd_geninit (void) ...@@ -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); 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_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); printk("xd_geninit: unable to get DMA%d\n",xd_dma);
free_irq(xd_irq); free_irq(xd_irq);
} }
......
...@@ -2840,7 +2840,7 @@ static int qic02_get_resources(void) ...@@ -2840,7 +2840,7 @@ static int qic02_get_resources(void)
} }
/* After IRQ, allocate DMA channel */ /* 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", printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n",
QIC02_TAPE_DMA); QIC02_TAPE_DMA);
free_irq(QIC02_TAPE_IRQ); free_irq(QIC02_TAPE_IRQ);
......
...@@ -371,7 +371,7 @@ lance_open(struct device *dev) ...@@ -371,7 +371,7 @@ lance_open(struct device *dev)
return -EAGAIN; return -EAGAIN;
} }
if (request_dma(dev->dma)) { if (request_dma(dev->dma,"lance")) {
free_irq(dev->irq); free_irq(dev->irq);
return -EAGAIN; return -EAGAIN;
} }
......
...@@ -101,7 +101,7 @@ init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp) ...@@ -101,7 +101,7 @@ init_etherdev(struct device *dev, int sizeof_private, unsigned long *mem_startp)
*mem_startp += alloc_size; *mem_startp += alloc_size;
} else } else
dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL);
memset(dev, 0, sizeof(alloc_size)); memset(dev, 0, alloc_size);
if (sizeof_private) if (sizeof_private)
dev->priv = (void *) (dev + 1); dev->priv = (void *) (dev + 1);
dev->name = sizeof_private + (char *)(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) ...@@ -236,7 +236,7 @@ net_open(struct device *dev)
/* Always snarf a DMA channel after the IRQ. */ /* Always snarf a DMA channel after the IRQ. */
if (request_dma(dev->dma)) { if (request_dma(dev->dma,"skeleton ethernet")) {
free_irq(dev->irq); free_irq(dev->irq);
return -EAGAIN; return -EAGAIN;
} }
......
...@@ -248,8 +248,8 @@ int znet_probe(struct device *dev) ...@@ -248,8 +248,8 @@ int znet_probe(struct device *dev)
/* These should never fail. You can't add devices to a sealed box! */ /* These should never fail. You can't add devices to a sealed box! */
if (request_irq(dev->irq, &znet_interrupt, 0, "ZNet") if (request_irq(dev->irq, &znet_interrupt, 0, "ZNet")
|| request_dma(zn.rx_dma) || request_dma(zn.rx_dma,"ZNet rx")
|| request_dma(zn.tx_dma)) { || request_dma(zn.tx_dma,"ZNet tx")) {
printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name); printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name);
return EBUSY; return EBUSY;
} }
......
...@@ -876,7 +876,7 @@ int aha1542_detect(Scsi_Host_Template * tpnt) ...@@ -876,7 +876,7 @@ int aha1542_detect(Scsi_Host_Template * tpnt)
} }
if (dma_chan != 0xFF) { if (dma_chan != 0xFF) {
if (request_dma(dma_chan)) { if (request_dma(dma_chan,"aha1542")) {
printk("Unable to allocate DMA channel for Adaptec.\n"); printk("Unable to allocate DMA channel for Adaptec.\n");
free_irq(irq_level); free_irq(irq_level);
goto unregister; goto unregister;
......
...@@ -1082,7 +1082,7 @@ int buslogic_detect(Scsi_Host_Template *tpnt) ...@@ -1082,7 +1082,7 @@ int buslogic_detect(Scsi_Host_Template *tpnt)
} }
if (dma) { if (dma) {
if (request_dma(dma)) { if (request_dma(dma,"buslogic")) {
buslogic_printk("Unable to allocate DMA channel for " buslogic_printk("Unable to allocate DMA channel for "
"BusLogic controller.\n"); "BusLogic controller.\n");
free_irq(irq); free_irq(irq);
......
...@@ -654,7 +654,7 @@ static int sr_detect(Scsi_Device * SDp){ ...@@ -654,7 +654,7 @@ static int sr_detect(Scsi_Device * SDp){
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0; 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", 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); SDp->host->host_no , SDp->id, SDp->lun);
return 1; return 1;
......
...@@ -498,7 +498,7 @@ static int ultrastor_14f_detect(Scsi_Host_Template * tpnt) ...@@ -498,7 +498,7 @@ static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
config.interrupt); config.interrupt);
return FALSE; 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", printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
config.dma_channel); config.dma_channel);
free_irq(config.interrupt); free_irq(config.interrupt);
......
...@@ -1047,7 +1047,7 @@ int wd7000_init( Adapter *host ) ...@@ -1047,7 +1047,7 @@ int wd7000_init( Adapter *host )
printk("wd7000_init: can't get IRQ %d.\n", host->irq); printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return 0; 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); printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
free_irq(host->irq); free_irq(host->irq);
return 0; return 0;
......
...@@ -259,7 +259,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr) ...@@ -259,7 +259,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
/* These are in kernel/dma.c: */ /* 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 */ extern void free_dma(unsigned int dmanr); /* release it again */
......
...@@ -832,7 +832,7 @@ DMAbuf_open_dma (int dev) ...@@ -832,7 +832,7 @@ DMAbuf_open_dma (int dev)
unsigned long flags; unsigned long flags;
int chan = audio_devs[dev]->dmachan; 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); printk ("Unable to grab DMA%d for the audio driver\n", chan);
return RET_ERROR (EBUSY); return RET_ERROR (EBUSY);
......
...@@ -93,7 +93,7 @@ struct snd_wait { ...@@ -93,7 +93,7 @@ struct snd_wait {
#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP) #define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP)
#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wake_up(&q);} #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 RELEASE_DMA_CHN(chn) free_dma(chn)
#define GET_TIME() jiffies #define GET_TIME() jiffies
......
...@@ -228,7 +228,7 @@ sb16_dsp_open (int dev, int mode) ...@@ -228,7 +228,7 @@ sb16_dsp_open (int dev, int mode)
sb_reset_dsp (); sb_reset_dsp ();
if (ALLOC_DMA_CHN (dma8)) if (ALLOC_DMA_CHN (dma8,"sb16 8bit"))
{ {
printk ("SB16: Unable to grab DMA%d\n", dma8); printk ("SB16: Unable to grab DMA%d\n", dma8);
sb_free_irq (); sb_free_irq ();
...@@ -236,7 +236,7 @@ sb16_dsp_open (int dev, int mode) ...@@ -236,7 +236,7 @@ sb16_dsp_open (int dev, int mode)
} }
if (dma16 != dma8) if (dma16 != dma8)
if (ALLOC_DMA_CHN (dma16)) if (ALLOC_DMA_CHN (dma16,"sb16 16bit"))
{ {
printk ("SB16: Unable to grab DMA%d\n", dma16); printk ("SB16: Unable to grab DMA%d\n", dma16);
sb_free_irq (); sb_free_irq ();
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/locks.h> #include <linux/locks.h>
#include <linux/fcntl.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -117,6 +118,10 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -117,6 +118,10 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
buf += chars; buf += chars;
bh->b_uptodate = 1; bh->b_uptodate = 1;
mark_buffer_dirty(bh, 0); mark_buffer_dirty(bh, 0);
if (filp->f_flags & O_SYNC) {
ll_rw_block(WRITE, 1, &bh);
wait_on_buffer(bh);
}
brelse(bh); brelse(bh);
} }
filp->f_reada = 1; filp->f_reada = 1;
......
Changes from version 0.5 to version 0.5a 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 - New mount options: `bsddf' and `minixdf'. `bsddf' causes ext2fs
to remove the blocks used for FS structures from the total block to remove the blocks used for FS structures from the total block
count in statfs. With `minixdf', ext2fs mimics Minix behavior count in statfs. With `minixdf', ext2fs mimics Minix behavior
......
...@@ -258,6 +258,14 @@ static int ext2_file_write (struct inode * inode, struct file * filp, ...@@ -258,6 +258,14 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
pos = inode->i_size; pos = inode->i_size;
else else
pos = filp->f_pos; 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; written = 0;
while (written < count) { while (written < count) {
bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err); 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, ...@@ -286,10 +294,16 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
buf += c; buf += c;
bh->b_uptodate = 1; bh->b_uptodate = 1;
mark_buffer_dirty(bh, 0); mark_buffer_dirty(bh, 0);
if (filp->f_flags & O_SYNC) {
ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh);
}
brelse (bh); brelse (bh);
} }
if (pos > inode->i_size) if (pos > inode->i_size)
inode->i_size = pos; inode->i_size = pos;
if (filp->f_flags & O_SYNC)
inode->u.ext2_i.i_osync--;
up(&inode->i_sem); up(&inode->i_sem);
inode->i_ctime = inode->i_mtime = CURRENT_TIME; inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos; filp->f_pos = pos;
......
...@@ -236,7 +236,7 @@ static struct buffer_head * inode_getblk (struct inode * inode, int nr, ...@@ -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->u.ext2_i.i_next_alloc_goal = tmp;
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
inode->i_blocks += blocks; inode->i_blocks += blocks;
if (IS_SYNC(inode)) if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode); ext2_sync_inode (inode);
else else
inode->i_dirt = 1; inode->i_dirt = 1;
...@@ -307,7 +307,7 @@ static struct buffer_head * block_getblk (struct inode * inode, ...@@ -307,7 +307,7 @@ static struct buffer_head * block_getblk (struct inode * inode,
} }
*p = tmp; *p = tmp;
mark_buffer_dirty(bh, 1); 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); ll_rw_block (WRITE, 1, &bh);
wait_on_buffer (bh); wait_on_buffer (bh);
} }
...@@ -535,6 +535,7 @@ void ext2_read_inode (struct inode * inode) ...@@ -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_faddr = raw_inode->i_faddr;
inode->u.ext2_i.i_frag_no = raw_inode->i_frag; 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_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_file_acl = raw_inode->i_file_acl;
inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl; inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl;
inode->u.ext2_i.i_version = raw_inode->i_version; inode->u.ext2_i.i_version = raw_inode->i_version;
......
...@@ -463,6 +463,7 @@ extern int get_device_list(char *); ...@@ -463,6 +463,7 @@ extern int get_device_list(char *);
extern int get_filesystem_list(char *); extern int get_filesystem_list(char *);
extern int get_ksyms_list(char *); extern int get_ksyms_list(char *);
extern int get_irq_list(char *); extern int get_irq_list(char *);
extern int get_dma_list(char *);
static int get_root_array(char * page, int type) static int get_root_array(char * page, int type)
{ {
...@@ -501,6 +502,9 @@ 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: case PROC_KSYMS:
return get_ksyms_list(page); return get_ksyms_list(page);
case PROC_DMA:
return get_dma_list(page);
} }
return -EBADF; return -EBADF;
} }
......
...@@ -71,6 +71,7 @@ static struct proc_dir_entry root_dir[] = { ...@@ -71,6 +71,7 @@ static struct proc_dir_entry root_dir[] = {
{ PROC_INTERRUPTS, 10,"interrupts" }, { PROC_INTERRUPTS, 10,"interrupts" },
{ PROC_FILESYSTEMS, 11,"filesystems" }, { PROC_FILESYSTEMS, 11,"filesystems" },
{ PROC_KSYMS, 5, "ksyms" }, { PROC_KSYMS, 5, "ksyms" },
{ PROC_DMA, 3, "dma" },
}; };
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0]))) #define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
......
...@@ -66,7 +66,7 @@ extern __inline__ int test_bit(int nr, void * addr) ...@@ -66,7 +66,7 @@ extern __inline__ int test_bit(int nr, void * addr)
/* /*
* Find-bit routines.. * 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; int res;
...@@ -92,8 +92,7 @@ extern inline int find_first_zero_bit (unsigned long * addr, unsigned size) ...@@ -92,8 +92,7 @@ extern inline int find_first_zero_bit (unsigned long * addr, unsigned size)
return res; return res;
} }
extern inline int find_next_zero_bit (unsigned long * addr, int size, extern inline int find_next_zero_bit (void * addr, int size, int offset)
int offset)
{ {
unsigned long * p = ((unsigned long *) addr) + (offset >> 5); unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
int set = 0, bit = offset & 31, res; int set = 0, bit = offset & 31, res;
...@@ -117,7 +116,7 @@ extern inline int find_next_zero_bit (unsigned long * addr, int size, ...@@ -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 * 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); return (offset + set + res);
} }
......
...@@ -259,7 +259,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr) ...@@ -259,7 +259,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr)
/* These are in kernel/dma.c: */ /* 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 */ 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 ...@@ -447,7 +447,7 @@ extern inline void * __constant_c_and_count_memset(void * s, unsigned long patte
return s; return s;
case 3: case 3:
*(unsigned short *)s = pattern; *(unsigned short *)s = pattern;
*(2+(unsigned char *)s) = pattern >> 16; *(2+(unsigned char *)s) = pattern;
return s; return s;
case 4: case 4:
*(unsigned long *)s = pattern; *(unsigned long *)s = pattern;
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
/* /*
* The second extended file system version * The second extended file system version
*/ */
#define EXT2FS_DATE "94/08/12" #define EXT2FS_DATE "94/08/24"
#define EXT2FS_VERSION "0.5a" #define EXT2FS_VERSION "0.5a"
/* /*
...@@ -348,13 +348,16 @@ struct ext2_super_block { ...@@ -348,13 +348,16 @@ struct ext2_super_block {
unsigned long s_lastcheck; /* time of last check */ unsigned long s_lastcheck; /* time of last check */
unsigned long s_checkinterval; /* max. time between checks */ unsigned long s_checkinterval; /* max. time between checks */
unsigned long s_creator_os; /* OS */ 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_LINUX 0
#define EXT2_OS_HURD 1 #define EXT2_OS_HURD 1
#define EXT2_OS_MASIX 2 #define EXT2_OS_MASIX 2
#define EXT2_CURRENT_REV 0
/* /*
* Structure of a directory entry * Structure of a directory entry
*/ */
......
...@@ -24,7 +24,7 @@ struct ext2_inode_info { ...@@ -24,7 +24,7 @@ struct ext2_inode_info {
unsigned long i_faddr; unsigned long i_faddr;
unsigned char i_frag_no; unsigned char i_frag_no;
unsigned char i_frag_size; unsigned char i_frag_size;
unsigned short i_pad1; unsigned short i_osync;
unsigned long i_file_acl; unsigned long i_file_acl;
unsigned long i_dir_acl; unsigned long i_dir_acl;
unsigned long i_dtime; unsigned long i_dtime;
......
#ifndef _LINUX_FCNTL_H #ifndef _LINUX_FCNTL_H
#define _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_ACCMODE 0003
#define O_RDONLY 00 #define O_RDONLY 00
#define O_WRONLY 01 #define O_WRONLY 01
......
...@@ -87,12 +87,12 @@ struct hd_driveid { ...@@ -87,12 +87,12 @@ struct hd_driveid {
unsigned short vendor0; /* vendor unique */ unsigned short vendor0; /* vendor unique */
unsigned short vendor1; /* vendor unique */ unsigned short vendor1; /* vendor unique */
unsigned short vendor2; /* 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_type;
unsigned short buf_size; /* 512 byte increments; 0 = not_specified */ unsigned short buf_size; /* 512 byte increments; 0 = not_specified */
unsigned short ecc_bytes; /* for r/w long cmds; 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 fw_rev[8]; /* 0 = not_specified */
unsigned char model[40]; /* big_endian; 0 = not_specified */ unsigned char model[40]; /* 0 = not_specified */
unsigned char max_multsect; /* 0=not_implemented */ unsigned char max_multsect; /* 0=not_implemented */
unsigned char vendor3; /* vendor unique */ unsigned char vendor3; /* vendor unique */
unsigned short dword_io; /* 0=not_implemented; 1=implemented */ unsigned short dword_io; /* 0=not_implemented; 1=implemented */
......
...@@ -23,7 +23,8 @@ enum root_directory_inos { ...@@ -23,7 +23,8 @@ enum root_directory_inos {
PROC_DEVICES, PROC_DEVICES,
PROC_INTERRUPTS, PROC_INTERRUPTS,
PROC_FILESYSTEMS, PROC_FILESYSTEMS,
PROC_KSYMS PROC_KSYMS,
PROC_DMA
}; };
enum pid_directory_inos { enum pid_directory_inos {
......
...@@ -20,7 +20,6 @@ struct linger { ...@@ -20,7 +20,6 @@ struct linger {
#define SOCK_RAW 3 /* raw socket */ #define SOCK_RAW 3 /* raw socket */
#define SOCK_RDM 4 /* reliably-delivered message */ #define SOCK_RDM 4 /* reliably-delivered message */
#define SOCK_SEQPACKET 5 /* sequential packet socket */ #define SOCK_SEQPACKET 5 /* sequential packet socket */
#define SOCK_NCP 6 /* Novell NCP socket */
#define SOCK_PACKET 10 /* linux specific way of */ #define SOCK_PACKET 10 /* linux specific way of */
/* getting packets at the dev */ /* getting packets at the dev */
/* level. For writing rarp and */ /* level. For writing rarp and */
......
...@@ -496,7 +496,7 @@ asmlinkage void start_kernel(void) ...@@ -496,7 +496,7 @@ asmlinkage void start_kernel(void)
if (hlt_works_ok) { if (hlt_works_ok) {
printk("Checking 'hlt' instruction... "); printk("Checking 'hlt' instruction... ");
__asm__ __volatile__("hlt ; hlt ; hlt ; hlt"); __asm__ __volatile__("hlt ; hlt ; hlt ; hlt");
printk(" Ok.\n"); printk("Ok.\n");
} }
system_utsname.machine[1] = '0' + x86; system_utsname.machine[1] = '0' + x86;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.c.o: .c.o:
$(CC) $(CFLAGS) -c $< $(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 \ panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \
signal.o ptrace.o ioport.o itimer.o \ signal.o ptrace.o ioport.o itimer.o \
info.o ldt.o time.o tqueue.o vm86.o bios32.o splx.o info.o ldt.o time.o tqueue.o vm86.o bios32.o splx.o
...@@ -27,9 +27,9 @@ kernel.o: $(OBJS) ...@@ -27,9 +27,9 @@ kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS) $(LD) -r -o kernel.o $(OBJS)
sync 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 sched.o: sched.c
$(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $< $(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $<
......
...@@ -29,11 +29,21 @@ ...@@ -29,11 +29,21 @@
* DMA0 used to be reserved for DRAM refresh, but apparently not any more... * DMA0 used to be reserved for DRAM refresh, but apparently not any more...
* DMA4 is reserved for cascading. * DMA4 is reserved for cascading.
*/ */
/*
static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = { static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = {
0, 0, 0, 0, 1, 0, 0, 0 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'. /* Atomically swap memory location [32 bits] with `newval'.
* This avoid the cli()/sti() junk and related problems. * This avoid the cli()/sti() junk and related problems.
...@@ -60,17 +70,30 @@ static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsi ...@@ -60,17 +70,30 @@ static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsi
} /* mutex_atomic_swap */ } /* mutex_atomic_swap */
int get_dma_list(char *buf)
{
int i, len = 0;
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) int request_dma(unsigned int dmanr, char * deviceID)
{ {
if (dmanr >= MAX_DMA_CHANNELS) if (dmanr >= MAX_DMA_CHANNELS)
return -EINVAL; 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; return -EBUSY;
else
/* old flag was 0, now contains 1 to indicate busy */ /* old flag was 0, now contains 1 to indicate busy */
return 0; return 0;
} /* request_dma */ } /* request_dma */
...@@ -81,7 +104,10 @@ void free_dma(unsigned int dmanr) ...@@ -81,7 +104,10 @@ void free_dma(unsigned int dmanr)
return; 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); printk("Trying to free free DMA%d\n", dmanr);
return;
}
} /* free_dma */ } /* free_dma */
...@@ -41,7 +41,7 @@ extern char * ftape_big_buffer; ...@@ -41,7 +41,7 @@ extern char * ftape_big_buffer;
extern void (*do_floppy)(void); extern void (*do_floppy)(void);
#endif #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 void free_dma(unsigned int dmanr);
extern int do_execve(char * filename, char ** argv, char ** envp, 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) ...@@ -177,8 +177,7 @@ int datagram_select(struct sock *sk, int sel_type, select_table *wait)
switch(sel_type) switch(sel_type)
{ {
case SEL_IN: case SEL_IN:
if ((sk->type==SOCK_SEQPACKET || sk->type==SOCK_NCP) if (sk->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE)
&& sk->state==TCP_CLOSE)
{ {
/* Connection closed: Wake up */ /* Connection closed: Wake up */
return(1); return(1);
......
...@@ -56,16 +56,8 @@ ...@@ -56,16 +56,8 @@
#include <linux/termios.h> /* For TIOCOUTQ/INQ */ #include <linux/termios.h> /* For TIOCOUTQ/INQ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include "p8022.h" #include "p8022.h"
#include "ncp.h"
#ifdef CONFIG_IPX #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. * * Handlers for the socket list. *
...@@ -83,9 +75,7 @@ static ipx_socket *volatile ipx_socket_list=NULL; ...@@ -83,9 +75,7 @@ static ipx_socket *volatile ipx_socket_list=NULL;
static void ipx_remove_socket(ipx_socket *sk) static void ipx_remove_socket(ipx_socket *sk)
{ {
ipx_socket *s; ipx_socket *s;
unsigned long flags;
save_flags(flags);
cli(); cli();
s=ipx_socket_list; s=ipx_socket_list;
if(s==sk) if(s==sk)
...@@ -99,23 +89,20 @@ static void ipx_remove_socket(ipx_socket *sk) ...@@ -99,23 +89,20 @@ static void ipx_remove_socket(ipx_socket *sk)
if(s->next==sk) if(s->next==sk)
{ {
s->next=sk->next; s->next=sk->next;
restore_flags(flags); sti();
return; return;
} }
s=s->next; s=s->next;
} }
restore_flags(flags); sti();
} }
static void ipx_insert_socket(ipx_socket *sk) static void ipx_insert_socket(ipx_socket *sk)
{ {
unsigned long flags;
save_flags(flags);
cli(); cli();
sk->next=ipx_socket_list; sk->next=ipx_socket_list;
ipx_socket_list=sk; ipx_socket_list=sk;
restore_flags(flags); sti();
} }
static ipx_socket *ipx_find_socket(int port) static ipx_socket *ipx_find_socket(int port)
...@@ -146,10 +133,9 @@ static void ipx_destroy_socket(ipx_socket *sk) ...@@ -146,10 +133,9 @@ static void ipx_destroy_socket(ipx_socket *sk)
ipx_remove_socket(sk); ipx_remove_socket(sk);
while((skb=skb_dequeue(&sk->receive_queue))!=NULL) while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
{
kfree_skb(skb,FREE_READ); kfree_skb(skb,FREE_READ);
}
while((skb=skb_dequeue(&sk->write_queue))!=NULL)
kfree_skb(skb,FREE_WRITE);
kfree_s(sk,sizeof(*sk)); kfree_s(sk,sizeof(*sk));
} }
...@@ -165,24 +151,20 @@ int ipx_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -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 */ /* 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) for (s = ipx_socket_list; s != NULL; s = s->next)
{ {
len += sprintf (buffer+len,"%02X ", s->ipx_type); 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[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], s->ipx_source_addr.node[3], s->ipx_source_addr.node[4], s->ipx_source_addr.node[5],
htons(s->ipx_source_addr.sock)); 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[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], s->ipx_dest_addr.node[3], s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5],
htons(s->ipx_dest_addr.sock)); htons(s->ipx_dest_addr.sock));
len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc); len += sprintf (buffer+len,"%08lX:%08lX ", s->wmem_alloc, s->rmem_alloc);
len += sprintf (buffer+len,"%02X ", s->state); len += sprintf (buffer+len,"%02X %d\n", s->state, SOCK_INODE(s->socket)->i_uid);
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);
/* Are we still dumping unwanted data then discard the record */ /* Are we still dumping unwanted data then discard the record */
pos=begin+len; pos=begin+len;
...@@ -483,7 +465,7 @@ int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -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) 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) switch(cmd)
{ {
default: default:
...@@ -584,56 +566,20 @@ static void def_callback2(struct sock *sk, int len) ...@@ -584,56 +566,20 @@ static void def_callback2(struct sock *sk, int len)
wake_up_interruptible(sk->sleep); wake_up_interruptible(sk->sleep);
} }
static void watch_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_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)
{ {
ipx_packet *ipx; ipx_socket *sk;
struct sk_buff *skb; sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
char *data; if(sk==NULL)
return(-ENOMEM);
skb=skb_dequeue(&sk->receive_queue); switch(sock->type)
if(skb==NULL)
return;
ipx = (ipx_packet *)(skb->h.raw);
data = (char *)(ipx+1);
if (*(data+1) == '!')
{ {
struct ncp_request_sf req; case SOCK_DGRAM:
break;
req.func=0x15; default:
req.s_func=0x01; kfree_s((void *)sk,sizeof(*sk));
req.s_len=htons(1); return(-ESOCKTNOSUPPORT);
ipx_do_sendto(sk->ncp.ncp, &(sk->ncp.ncp->ipx_dest_addr),
&req, sizeof(req), 0,sk->ncp.ncp->ipx_type);
} }
kfree_skb(skb, FREE_READ);
}
static void ipx_do_create(struct socket *sock, ipx_socket *sk)
{
sk->dead=0; sk->dead=0;
sk->next=NULL; sk->next=NULL;
sk->broadcast=0; sk->broadcast=0;
...@@ -652,6 +598,7 @@ static void ipx_do_create(struct socket *sock, ipx_socket *sk) ...@@ -652,6 +598,7 @@ static void ipx_do_create(struct socket *sock, ipx_socket *sk)
skb_queue_head_init(&sk->back_log); skb_queue_head_init(&sk->back_log);
sk->state=TCP_CLOSE; sk->state=TCP_CLOSE;
sk->socket=sock; sk->socket=sock;
sk->type=sock->type;
sk->ipx_type=0; /* General user level IPX */ sk->ipx_type=0; /* General user level IPX */
sk->debug=0; sk->debug=0;
...@@ -663,76 +610,14 @@ static void ipx_do_create(struct socket *sock, ipx_socket *sk) ...@@ -663,76 +610,14 @@ static void ipx_do_create(struct socket *sock, ipx_socket *sk)
{ {
sock->data=(void *)sk; sock->data=(void *)sk;
sk->sleep=sock->wait; sk->sleep=sock->wait;
sk->type=sock->type;
} }
else
sk->type=SOCK_DGRAM;
sk->priority=SOPRI_NORMAL;
sk->state_change=def_callback1; sk->state_change=def_callback1;
sk->data_ready=def_callback2; sk->data_ready=def_callback2;
sk->write_space=def_callback1; sk->write_space=def_callback1;
sk->error_report=def_callback1; sk->error_report=def_callback1;
sk->zapped=1; 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); return(0);
} }
...@@ -748,79 +633,47 @@ static int ipx_release(struct socket *sock, struct socket *peer) ...@@ -748,79 +633,47 @@ static int ipx_release(struct socket *sock, struct socket *peer)
return(0); return(0);
if(!sk->dead) if(!sk->dead)
sk->state_change(sk); sk->state_change(sk);
sk->dead=1;
sock->data=NULL; sock->data=NULL;
ipx_destroy_socket(sk);
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;
ipx_destroy_socket(sk);
}
return(0); return(0);
} }
static unsigned short first_free_socketnum(void) static unsigned short first_free_socketnum(void)
{ {
static unsigned short socketNum = 0x3fff; static unsigned short socketNum = 0x4000;
while (ipx_find_socket(htons(++socketNum)) != NULL) while (ipx_find_socket(htons(socketNum)) != NULL)
if (socketNum > 0x7ffc) socketNum = 0x3fff; if (socketNum > 0x7ffc) socketNum = 0x4000;
return htons(socketNum); return htons(socketNum++);
} }
static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) 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; struct ipx_route *rt;
unsigned char *nodestart; unsigned char *nodestart;
struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr; struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
sk=(ipx_socket *)sock->data;
if(sk->zapped==0) if(sk->zapped==0)
return(-EIO); return(-EIO);
if(addr_len!=sizeof(struct sockaddr_ipx)) if(addr_len!=sizeof(struct sockaddr_ipx))
return -EINVAL; return -EINVAL;
if (addr->sipx_port == 0) if (addr->sipx_port == 0)
{ {
addr->sipx_port = first_free_socketnum(); 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) if (addr->sipx_port == 0)
return -EINVAL; return -EINVAL;
} }
if(ntohs(addr->sipx_port)<0x4000 && !suser()) if(ntohs(addr->sipx_port)<0x4000 && !suser())
return(-EPERM); /* protect IPX system stuff like routing/sap */ return(-EPERM); /* protect IPX system stuff like routing/sap */
/* Source addresses are easy. It must be our network:node pair for /* Source addresses are easy. It must be our network:node pair for
an interface routed to IPX with the ipx routing ioctl() */ an interface routed to IPX with the ipx routing ioctl() */
...@@ -832,19 +685,6 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) ...@@ -832,19 +685,6 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
return -EADDRINUSE; 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; sk->ipx_source_addr.sock=addr->sipx_port;
if (addr->sipx_network == 0L) if (addr->sipx_network == 0L)
...@@ -865,7 +705,6 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len) ...@@ -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_source_addr.net=rt->net;
sk->ipx_type=addr->sipx_type;
/* IPX addresses zero pad physical addresses less than 6 */ /* IPX addresses zero pad physical addresses less than 6 */
memset(sk->ipx_source_addr.node,'\0',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) ...@@ -874,102 +713,41 @@ static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
ipx_insert_socket(sk); ipx_insert_socket(sk);
sk->zapped=0; 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) if(sk->debug)
printk("IPX: socket is bound.\n"); printk("IPX: socket is bound.\n");
return(0); 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, static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
int addr_len, int flags) int addr_len, int flags)
{ {
ipx_socket *sk=(ipx_socket *)sock->data; ipx_socket *sk=(ipx_socket *)sock->data;
struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr; struct sockaddr_ipx *addr;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
if(addr_len!=sizeof(struct sockaddr_ipx)) if(addr_len!=sizeof(addr))
return(-EINVAL); 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 */ /* put the autobinding in */
{ {
struct sockaddr_ipx uaddr;
int ret; int ret;
struct sockaddr_ipx addr;
addr.sipx_type = 0; uaddr.sipx_port = 0;
addr.sipx_port = 0; uaddr.sipx_network = 0L;
addr.sipx_network = 0L; ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
ret = ipx_bind (sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_ipx));
if (ret != 0) return (ret); if (ret != 0) return (ret);
} }
sk->ipx_dest_addr.net=addr->sipx_network; sk->ipx_dest_addr.net=addr->sipx_network;
sk->ipx_dest_addr.sock=addr->sipx_port; sk->ipx_dest_addr.sock=addr->sipx_port;
memcpy(sk->ipx_dest_addr.node,addr->sipx_node,sizeof(sk->ipx_source_addr.node)); 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) if(ipxrtr_get_dev(sk->ipx_dest_addr.net)==NULL)
return -ENETUNREACH; return -ENETUNREACH;
if (sk->type == SOCK_NCP)
return(ncp_connect(sock, sk));
sk->ipx_type=addr->sipx_type;
sock->state = SS_CONNECTED; sock->state = SS_CONNECTED;
sk->state=TCP_ESTABLISHED; sk->state=TCP_ESTABLISHED;
return(0); return(0);
...@@ -992,9 +770,10 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -992,9 +770,10 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
{ {
ipx_address *addr; ipx_address *addr;
struct sockaddr_ipx sipx; 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); *uaddr_len = sizeof(struct sockaddr_ipx);
if(peer) if(peer)
...@@ -1004,21 +783,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -1004,21 +783,7 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
addr=&sk->ipx_dest_addr; addr=&sk->ipx_dest_addr;
} }
else 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; addr=&sk->ipx_source_addr;
}
sipx.sipx_family = AF_IPX; sipx.sipx_family = AF_IPX;
sipx.sipx_port = addr->sock; sipx.sipx_port = addr->sock;
...@@ -1028,411 +793,6 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -1028,411 +793,6 @@ static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
return(0); return(0);
} }
static int ipx_build_header(ipx_address *ipx, struct sk_buff *skb,
ipx_socket *sk, int len, unsigned char type)
{
ipx_packet *ipx_pack;
ipx_route *rt;
struct datalink_proto *dl = NULL;
unsigned char IPXaddr[6];
int self_addressing = 0;
int broadcast = 0;
if(sk->debug)
printk("IPX: build_header: Addresses built.\n");
if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0)
{
if (!sk->broadcast)
return -ENETUNREACH;
broadcast = 1;
}
/* 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)
{
return -ENETUNREACH;
}
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;
/* Build Data Link header */
dl->datalink_header(dl, skb,
(rt->flags&IPX_RT_ROUTED)?rt->router_node:ipx->node);
/* 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);
self_addressing = !memcmp(IPXaddr,
(rt->flags&IPX_RT_ROUTED)?rt->router_node
:ipx->node,
6);
/* 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;
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) int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
{ {
/* NULL here for pt means the packet was looped back */ /* NULL here for pt means the packet was looped back */
...@@ -1582,9 +942,6 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1582,9 +942,6 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
kfree_skb(skb,FREE_READ); /* Socket is full */ kfree_skb(skb,FREE_READ); /* Socket is full */
return(0); return(0);
} }
if (sock->type == SOCK_NCP)
return (ncp_rcv(sock, skb));
sock->rmem_alloc+=skb->mem_len; sock->rmem_alloc+=skb->mem_len;
skb->sk = sock; skb->sk = sock;
...@@ -1595,27 +952,65 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ...@@ -1595,27 +952,65 @@ int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
return(0); return(0);
} }
static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx, static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
void *ubuf, int len, int flag, unsigned char type) 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 sk_buff *skb;
struct device *dev; struct device *dev;
ipx_packet *ipx_pack; struct ipx_packet *ipx;
int size; int size;
ipx_route *rt; ipx_route *rt;
struct datalink_proto *dl = NULL; struct datalink_proto *dl = NULL;
unsigned char IPXaddr[6];
int self_addressing = 0;
int broadcast = 0;
if(flags)
return -EINVAL;
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(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(sk->debug) if(sk->debug)
printk("IPX: sendto: Addresses built.\n"); printk("IPX: sendto: Addresses built.\n");
if ((sk->type == SOCK_NCP) && (len < sizeof (struct ncp_request))) if(memcmp(&usipx->sipx_node,&ipx_broadcast_node,6)==0)
return -EINVAL;
if(memcmp(&ipx->node,&ipx_broadcast_node,6)==0)
{ {
if (!sk->broadcast) if (!sk->broadcast)
return -ENETUNREACH; return -ENETUNREACH;
broadcast = 1;
} }
/* Build a packet */ /* Build a packet */
...@@ -1626,12 +1021,12 @@ static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx, ...@@ -1626,12 +1021,12 @@ static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
size=sizeof(ipx_packet)+len; /* For mac headers */ size=sizeof(ipx_packet)+len; /* For mac headers */
/* Find out where this has to go */ /* Find out where this has to go */
if (ipx->net == 0L) { if (usipx->sipx_network == 0L) {
rt = ipxrtr_get_default_net(); rt = ipxrtr_get_default_net();
if (rt != NULL) if (rt != NULL)
ipx->net = rt->net; usipx->sipx_network = rt->net;
} else } else
rt=ipxrtr_get_dev(ipx->net); rt=ipxrtr_get_dev(usipx->sipx_network);
if(rt==NULL) if(rt==NULL)
{ {
...@@ -1651,117 +1046,86 @@ static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx, ...@@ -1651,117 +1046,86 @@ static int ipx_do_sendto(ipx_socket *sk, ipx_address *ipx,
return -EAGAIN; return -EAGAIN;
} }
if (flag) skb=alloc_skb(size,GFP_KERNEL);
skb=alloc_skb(size,GFP_KERNEL);
else
skb=alloc_skb(size,GFP_ATOMIC);
if(skb==NULL) if(skb==NULL)
return -ENOMEM; return -ENOMEM;
sk->wmem_alloc+=skb->mem_len;
skb->mem_addr=skb;
skb->sk=sk;
skb->free=1;
skb->arp=1;
skb->len=size; skb->len=size;
ipx_build_header(ipx, skb, sk, len, type); sk->wmem_alloc+=skb->mem_len;
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);
switch (sk->state) if(sk->debug)
{ printk("Building MAC header.\n");
case TCP_SYN_SENT: skb->dev=rt->dev;
req->p_type = NCP_OPEN;
break; /* Build Data Link header */
case TCP_CLOSE_WAIT: dl->datalink_header(dl, skb,
req->p_type = NCP_CLOSE; (rt->flags&IPX_RT_ROUTED)?rt->router_node:usipx->sipx_node);
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;
skb->free=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);
if (&sk->write_queue == sk->write_queue.next) self_addressing = !memcmp(IPXaddr,
ipx_add_timer(sk, NCP_TIMEOUT); (rt->flags&IPX_RT_ROUTED)?rt->router_node
else :usipx->sipx_node,
ipx_reset_timer(sk, NCP_TIMEOUT); 6);
skb_queue_tail(&sk->write_queue,skb);
}
/* 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) if(sk->debug)
printk("IPX: Transmitting buffer\n"); printk("IPX: Transmitting buffer\n");
if((dev->flags&IFF_LOOPBACK) || self_addressing) {
struct packet_type pt;
/* 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;
ipx_xmit(skb); /* loop back */
pt.type = rt->dlink_type;
return len;
} skb2=alloc_skb(skb->len, GFP_ATOMIC);
skb2->mem_addr=skb2;
static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock, skb2->free=1;
unsigned flags, struct sockaddr *usip, int addr_len) skb2->arp=1;
{ skb2->len=skb->len;
ipx_socket *sk=(ipx_socket *)sock->data; skb2->sk = NULL;
ipx_address ipx; skb2->h.raw = skb2->data + rt->datalink->header_length
struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip; + dev->hard_header_len;
struct sockaddr_ipx local_sipx; memcpy(skb2->data, skb->data, skb->len);
ipx_rcv(skb2,dev,&pt);
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);
} }
dev_queue_xmit(skb,dev,SOPRI_NORMAL);
if(addr_len <sizeof(*usipx))
return(-EINVAL);
if(usipx->sipx_family != AF_IPX)
return -EINVAL;
if(htons(usipx->sipx_port)<0x4000 && !suser())
return -EPERM;
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));
}
else
{
if(sk->state!=TCP_ESTABLISHED)
return -ENOTCONN;
return (ipx_do_sendto(sk, &(sk->ipx_dest_addr), ubuf,
len, 1, sk->ipx_type));
} }
return len;
} }
static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags) static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
{ {
...@@ -1778,7 +1142,7 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, ...@@ -1778,7 +1142,7 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
int copied = 0; int copied = 0;
struct sk_buff *skb; struct sk_buff *skb;
int er; int er;
if(sk->err) if(sk->err)
{ {
er= -sk->err; er= -sk->err;
...@@ -1806,14 +1170,12 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, ...@@ -1806,14 +1170,12 @@ static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
sipx->sipx_type = ipx->ipx_type; sipx->sipx_type = ipx->ipx_type;
} }
skb_free_datagram(skb); skb_free_datagram(skb);
return(copied); return(copied);
} }
static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock) static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock)
{ {
return ipx_send(sock,ubuf,size,noblock,0); return ipx_send(sock,ubuf,size,noblock,0);
} }
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#endif #endif
#ifdef CONFIG_IPX #ifdef CONFIG_IPX
#include "ipx.h" #include "ipx.h"
#include "ncp.h"
#endif #endif
#define SOCK_ARRAY_SIZE 64 #define SOCK_ARRAY_SIZE 64
...@@ -138,7 +137,6 @@ struct sock { ...@@ -138,7 +137,6 @@ struct sock {
#ifdef CONFIG_IPX #ifdef CONFIG_IPX
ipx_address ipx_source_addr,ipx_dest_addr; ipx_address ipx_source_addr,ipx_dest_addr;
unsigned short ipx_type; unsigned short ipx_type;
struct ncp_info ncp;
#endif #endif
#ifdef CONFIG_AX25 #ifdef CONFIG_AX25
/* Really we want to add a per protocol private area */ /* Really we want to add a per protocol private area */
......
...@@ -592,8 +592,7 @@ static int sock_socket(int family, int type, int protocol) ...@@ -592,8 +592,7 @@ static int sock_socket(int family, int type, int protocol)
if ((type != SOCK_STREAM && type != SOCK_DGRAM && if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
type != SOCK_SEQPACKET && type != SOCK_RAW && type != SOCK_SEQPACKET && type != SOCK_RAW &&
type != SOCK_PACKET && type != SOCK_NCP) type != SOCK_PACKET) || protocol < 0)
|| protocol < 0)
return(-EINVAL); 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