D: NFS mmap()
D: XF86_S3
D: Kernel modules
-S: C/ Teodosio 43
-S: Portal 6 1-A
-S: Sevilla 41002
+S: C/ Carlos de Cepeda 36 2-5
+S: Sevilla 41005
S: Spain
N: Linus Torvalds
VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 71
+SUBLEVEL = 72
ARCH = i386
$(CC) $(CFLAGS) -c -o $*.o $<
Version: dummy
- rm -f tools/version.h
+ rm -f include/linux/version.h
boot:
ln -sf arch/$(ARCH)/boot boot
linuxsubdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done
-tools/./version.h: tools/version.h
+$(TOPDIR)/include/linux/version.h: include/linux/version.h
-tools/version.h: $(CONFIGURE) Makefile
+include/linux/version.h: $(CONFIGURE) Makefile
@./makever.sh
- @echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > tools/version.h
+ @echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > include/linux/version.h
@if [ -f .name ]; then \
echo \#define UTS_VERSION \"\#`cat .version`-`cat .name` `date`\"; \
else \
echo \#define UTS_VERSION \"\#`cat .version` `date`\"; \
- fi >> tools/version.h
- @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
- @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
- @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h
+ fi >> include/linux/version.h
+ @echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> include/linux/version.h
+ @echo \#define LINUX_COMPILE_BY \"`whoami`\" >> include/linux/version.h
+ @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> include/linux/version.h
@if [ -x /bin/dnsdomainname ]; then \
echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"; \
else \
echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\"; \
- fi >> tools/version.h
- @echo \#define LINUX_COMPILER \"`$(HOSTCC) -v 2>&1 | tail -1`\" >> tools/version.h
+ fi >> include/linux/version.h
+ @echo \#define LINUX_COMPILER \"`$(HOSTCC) -v 2>&1 | tail -1`\" >> include/linux/version.h
tools/build: tools/build.c $(CONFIGURE)
$(HOSTCC) $(CFLAGS) -o $@ $<
boot/head.s: boot/head.S $(CONFIGURE) include/linux/tasks.h
$(CPP) -traditional $< -o $@
-tools/version.o: tools/version.c tools/version.h
+tools/version.o: tools/version.c include/linux/version.h
init/main.o: $(CONFIGURE) init/main.c
$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
rm -f .tmp* drivers/sound/configure
mrproper: clean
- rm -f include/linux/autoconf.h tools/version.h
+ rm -f include/linux/autoconf.h include/linux/version.h
rm -f drivers/sound/local.h
rm -f .version .config* config.in config.old
rm -f boot include/asm kernel/entry.S
sync
depend dep:
- touch tools/version.h
+ touch include/linux/version.h
for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .tmpdepend
for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .tmpdepend
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done
- rm -f tools/version.h
+ rm -f include/linux/version.h
mv .tmpdepend .depend
ifdef CONFIGURATION
+/* boot.S: The initial boot code for the Sparc port of Linux.
+
+ Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+
+ This file has to serve three purposes.
+
+ 1) determine the prom-version and cpu/architecture
+ 2) print enough useful info before we start to execute
+ c-code that I can possibly begin to debug things
+ 3) Hold the vector of trap entry points
+
+ The Sparc offers many challenges to kernel design. Here I will
+ document those I have come across thus far. Upon bootup the boot
+ prom loads your a.out image into memory. This memory the prom has
+ already mapped for you, however as far as I can tell the virtual
+ adress cache is not turned on although the MMU is translating
+ things. You get loaded at 0xf8004000 exactly. So, when you link
+ a boot-loadable object you want to do something like:
+
+ ld -e start -T f8004000 -o mykernel myobj1.o myobj2.o ....
+
+ to produce a proper image.
+
+ At boot time you are given (as far as I can tell at this time)
+ one key to figure out what machine you are one and what devices
+ are available. The prom when it loads you leaves a pointer to
+ the 'rom vector' in register %o0 right before it jumps to your
+ starting address. This is a pointer to a struct that is full of
+ pointer to functions (ie. printf, halt, reboot), pointers to
+ linked lists (ie. memory mappings), and pointer to imperical
+ constants (ie. stdin and stdout magic cookies + rom version).
+ Starting with this piece of information you can figure out
+ just about anything you want about the machine you are on.
+*/
+
#include "boot.h"
#include "version.h"
.data
-/* First thing to go in the data segment is the interrupt stack */
+/* First thing to go in the data segment is the interrupt stack. */
.globl _intstack
.globl _eintstack
_cputypvallen = _cputypvar - _cputypval
+/* This hold the prom-interface-version number for either v0 or v2. */
+
+ .align 4
+ .globl _prom_iface_vers
+
+_prom_iface_vers: .skip 4
/* WARNING: evil messages follow */
.asciz "Sparc-Linux: sun4d support does not exist\n\n"
.align 4
-
-/* The following will disappear real soon as the implementation is easy */
-
-v2_prom_notyet:
- .asciz "Sparc-Linux: v2 boot-prom support not implemented\n\n"
+you_lose:
+ .asciz "You lose..... Thanks for playing...\n"
.align 4
-
/*
Fill up the prom vector, note in particular the kind first element,
no joke.
_prom_vector_p: .skip 4
prom_magic: .skip 4 ! magic mushroom, beware...
prom_rom_vers: .skip 4 ! interface version (v0 or v2)
-prom_pluginvers: .skip 4 ! XXX help help help
+prom_pluginvers: .skip 4 ! XXX help help help ???
prom_revision: .skip 4 ! PROM revision (ie. 1.4)
prom_bootstr: .skip 4 ! what we are invoked with
prom_putchar: .skip 4 ! void putchar(int ch) BLOCKING.
prom_putstring: .skip 4 ! prom putstring()
prom_bootme: .skip 4 ! reset()
prom_printf: .skip 4 ! minimal printf()
+
+/* The prom_abort pointer MUST be mapped in all contexts, because if you
+ don't then if a user process is running when you press the abort key
+ sequence, all sorts of bad things can happen
+*/
+
prom_abort: .skip 4 ! "L1-A" magic cookie
! must be mapped in ALL contexts
prom_ticks: .skip 4 ! number of ticks since reset
+
+/* prom_sync is a place where the kernel should place a pointer to a kernel
+ function that when called will sync all pending information to the drives
+ and then promptly return. If the kernel gets aborted with 'L1-A' one can
+ give the 'sync' command to the boot prompt and this magic cookie gets
+ executed. Nice feature eh?
+*/
+
prom_sync: .skip 4 ! hook in prom for "sync" func
prom_v0bootarg: .skip 4 ! v0 prom boot arguements
prom_v2bootarg: .skip 4 ! same as above for v2 proms
.globl boot_msg
-/*
- This gets forth eval'd, just 'cause I think forth is neat to have in a boot
- monitor :-) We may not need no steenkin BIOS but we do need the prom!
-*/
+/* memory descriptor property strings, v2 = yuk yuk yuk */
+/* XXX how to figure out vm mapped by prom? May have to scan magic addresses */
+
+mem_prop_physavail: .asciz "available"
+mem_prop_phystot: .asciz "reg"
+
+/* v2_memory descriptor struct kludged here for assembly, if it ain't broke */
+
+ .align 4
+v2_mem_struct: .skip 0xff
+
+ .align 4
+v2_printf_physavail: .asciz "Physical Memory Available: 0x%x bytes"
+v2_printf_phystot: .asciz "Physical Memory: 0x%x bytes"
+
+/* A place to store property strings returned from the prom 'node' funcs */
+
+ .align 4
+prop_string_buf: .skip 32
+
+prop_name: .asciz "name"
+ .align 4
+
+current_node: .skip 4
+ .align 4
+
+
+/* nice little boot message */
boot_msg:
- .ascii "Booting Sparc-Linux V0.00PRE-ALPHA (SUN4C) "
+ .ascii "Booting Sparc-Linux V0.00PRE-ALPHA "
.ascii WHO_COMPILED_ME
.asciz " \n"
.align 4
get them in the right place for load time
*/
-whereis_bootmsg = boot_msg-KERNBASE
-whereis_kernbase = KERNBASE
+whereis_kernbase = KERNBASE
whereis_prom_vector_p = _prom_vector_p-KERNBASE
-whereis_prom_eval = prom_eval-KERNBASE
-whereis_prom_halt = prom_halt-KERNBASE
+/* Ok, things start to get interesting. We get linked such that 'start'
+ is the entry symbol. However, it is real low in kernel address space
+ and as such a nifty place to place the trap table. We achieve this goal
+ by just jumping to 'dostart' for the first trap's entry as the sparc
+ never receives the zero trap as it is real special.
+
+ Each trap entry point is the size of 4 sparc instructions (or 4 bytes
+ * 4 insns = 16 bytes). There are 128 hardware traps (some undefined
+ or unimplemented) and 128 software traps (ditto).
+
+ One of the instructions must be a branch. More often than not this
+ will be to a trap handler entry point becuase it is completely
+ impossible to handle any trap in 4 insns. I welcome anyone to
+ challenge this theory. :-)
+
+ On entry into this table the hardware has loaded the program counter
+ at which the trap occurred into register %l1 and the next program
+ counter into %l2, this way we can return from the trap with a simple
+
+ jmp %l1; rett %l2
+
+ after properly servicing the trap. It wouldn't be a bad idea to load
+ some more information into the local regs since we have technically
+ 2 or 3 instructions to play with besides the jmp to the 'real' trap
+ handler (one can even go in the delay slot). For now I am going to put
+ the %psr (processor status register) and the trap-type value in %l0
+ and %l3 respectively.
+
+ TODO: Write cheesy macros to make this table more manageable.
+ Ugh, this shit is long...
+
+*/
+
.globl start
.globl _trapbase
start:
.word 1
- .data
- .skip 32 ! alignment byte & negative indicies
-uwtab: .skip 32 ! u_char uwtab[-31..31];
-wmask: .skip 32 ! u_char wmask[0..31];
+/* The following two things point to window management tables. The first
+ one is used to quickly look up how many user windows there are from
+ trap-land. The second is used in a trap handler to determine if a rett
+ instruction will land us smack inside the invalid window that possibly
+ the trap was called to fix-up.
+*/
+
+ .data
+ .skip 32 ! alignment byte & negative indicies
+lnx_uw: .skip 32 ! u_char uwtab[-31..31];
+lnx_winmask: .skip 32 ! u_char wmask[0..31];
.text
-
+/* Cool, here we go. Pick up the romvec pointer in %o0 and stash it in
+ %g7 and at _prom_vector_p. And also quickly check whether we are on
+ a v0 or v2 prom.
+*/
+
dostart: mov %o0, %g7
st %o0, [_prom_vector_p] ! we will need it later
ld [%g7 + 0x4], %o2
cmp %o2, 2 ! a v2 prom?
- be _no_v2_here
+ be found_v2
nop
+/* Old sun4's pass our load address into %o0 instead of the prom
+ pointer. On sun4's you have to hard code the romvec pointer into
+ your code. Sun probably still does that because they don't even
+ trust their own "OpenBoot" specifications.
+*/
+
set 0x4000, %g6
cmp %o0, %g6 ! an old sun4?
beq no_sun4_here
nop
+ st %g0, [_prom_iface_vers] ! useless, disappear soon
+ b not_v2
+ nop
+
+found_v2:
+ set 0x2, %o5
+ st %o5, [_prom_iface_vers]
+
+not_v2:
+
+/* Get the machine type via the mysterious romvec node operations.
+ Here we can find out whether we are on a sun4 sun4c, sun4m, or
+ a sun4m. The "nodes" are set up as a bunch of n-ary trees which
+ you can traverse to get information about devices and such. The
+ information acquisition happens via the node-ops which are defined
+ in the linux_openprom.h header file. Of particular interest is the
+ 'nextnode(int node)' function as it does the smart thing when
+ presented with a value of '0', it gives you the first node in the
+ tree. These node integers probably offset into some internal prom
+ pointer table the openboot has. It's completely undocumented, so
+ I'm not about to go sifting through the prom address space, but may
+ do so if I get suspicious enough. :-)
+*/
+
+ mov 0, %o0 ! next_node(0) = first_node
ld [%g7 + 0x1c], %o4
ld [%o4], %o4
call %o4
- mov 0, %o0
- set _cputypvar, %o1
- set _cputypval, %o2
- ld [%g7 + 0x1c], %o4
- ld [%o4 + 0x0c], %o4
- call %o4
nop
+ set _cputypvar, %o1 ! first node has cpu-arch
+ set _cputypval, %o2 ! information, the string
+ ld [%g7 + 0x1c], %o4 ! 'compatability' tells
+ ld [%o4 + 0x0c], %o4 ! that we want 'sun4x' where
+ call %o4 ! x is one of '', 'c', 'm',
+ nop ! 'd' or 'e'. %o2 holds pointer
+ ! to a buf where above string
+ ! will get stored by the prom.
set _cputypval, %o2
ldub [%o2 + 4], %o0
- cmp %o0, 'c'
- beq is_sun4c
- nop
- cmp %o0, 'm'
- beq no_sun4m_here
- nop
- b no_sun4d_here
+ cmp %o0, 'c' ! we already know we are not
+ beq is_sun4c ! on a plain sun4 because of
+ nop ! the check for 0x4000 in %o0
+ cmp %o0, 'm' ! at start:
+ beq is_sun4m
nop
+ b no_sun4d_here ! god bless the person who
+ nop ! tried to run this on sun4d
+is_sun4m:
is_sun4c: ! OK, this is a sun4c, yippie
- mov %g7, %g6 ! load up them promvec offsets
+ mov %g7, %g6 ! load up the promvec offsets
st %g6, [prom_magic] ! magic mushroom :>
add %g7, 0x4, %g6
st %g6, [prom_rom_vers]
add %g7, 0x104, %g6
st %g6, [prom_setcontext]
+/* That was easy, now lets try to print some message on the screen.
+ We have to be careful because the prom addressed things weird and
+ we aren't really mapped into memory as far as the rom routines are
+ concerned. So all addresses we have ourselves and would like the
+ prom to actually use must be calculated as (addr - KERNBASE) in order
+ for anything to work at all. We will map ourselves later before we
+ call any c-code to avoid this hassle.
+*/
set boot_msg-KERNBASE, %o0
ld [prom_printf-KERNBASE], %o2
ld [%o2], %o1
call %o1 ! print boot message #1
nop
- set newline-KERNBASE, %o0
+
+_newline: set newline-KERNBASE, %o0
ld [prom_printf-KERNBASE], %o2
ld [%o2], %o1
call %o1
nop
b 0f
- nop
-
+ nop ! damn delay slots...
0: nop ! duh
set pstring1-KERNBASE, %o0
set pstring2-KERNBASE, %o0
ld [prom_printf-KERNBASE], %o3
ld [%o3], %o2
- ld [prom_rom_vers-KERNBASE], %o3
+ ld [_prom_iface_vers], %o3
ld [%o3], %o1
call %o2
nop; nop; nop
+/* Print out various bits of memory information. At this point
+ I just cycle through the documented v0_prom memory lists for
+ the values. They are linked lists and allow for description of
+ non-contiguous physical memory configurations, thus the 'memloop'
+ things to traverse the linked lists.
+*/
+
+/* Things are different for v0 and v2. v2 requires traversing the node trees
+ and that really sucks.
+*/
+
+/* Another Note:
+ The prom printf() function can take up to 5 arguements in registers
+ %o1 -- %o5 , the format string goes in %o0. It is your usual libc
+ printf() believe it or not.
+*/
+
+ cmp %o0, 0x2
+ be v2_mem_probe
+ nop
+
set pstring4-KERNBASE, %o0
ld [prom_printf-KERNBASE], %o5
ld [%o5], %o4
ld [_prom_vector_p], %l1
ld [%l1+16], %l2
ld [%l2], %l3
- ld [%l3 + 8], %o1
+ ld [%l3 + 8], %o1 ! 'nbytes' memory accumulator
-/*
- ld [%l1], %l2
- ld [%l2 + 0x8], %o1 ! physical memory accumulator
-*/
ld [_prom_vector_p], %l1
ld [%l1 + 16], %l2
ld [%l2], %l3
ld [%l3], %l4
-/* ld [%l3], %l4 */
memloop:
cmp %l4, 0
be mv_to_vmprom ! is there more?
b halt_me
nop
- .globl _no_v2_here
-_no_v2_here:
- ld [%g7 + 0x68], %o1
- set v2_prom_notyet-KERNBASE, %o0
- call %o1
- nop
- b halt_me
- nop
-
no_sun4_here:
ld [%g7 + 0x68], %o1
set sun4_notsup, %o0
call %o1
nop
- b halt_me
+ b rest_of_boot ! next stage...
nop
-no_sun4m_here:
- ld [%g7 + 0x68], %o1
- set sun4m_notsup, %o0
+v2_mem_probe:
+ set you_lose-KERNBASE, %o0 ! I just print this
+ ld [prom_printf-KERNBASE], %o1 ! crap to debug my node
+ ld [%o1], %o2 ! routines :-)
+ call %o2
+ nop
+
+ st %g0, [current_node]
+ set prop_string_buf, %o2
+ or %g0, %g0, %o0
+ ld [prop_name], %o1
+ or %g0, 31, %o3
+
+node_find_loop:
+ ld [prom_nodefuncs], %o4
+ ld [%o4 + 0xc], %o4
+ call %o4
+ nop
+ ld [prop_string_buf], %l3
+ cmp %l3, 'm'
+ bne node_find_loop2
+ ld [prop_string_buf + 1], %l3
+ cmp %l3, 'e'
+ bne node_find_loop2
+ ld [prop_string_buf + 2], %l3
+ cmp %l3, 'm'
+ bne node_find_loop2
+ nop
+ b found_mem_node
+ nop
+
+node_find_loop2:
+ ld [current_node], %o0 ! get next node
+ ld [prom_nodefuncs], %o1
+ ld [%o1], %o1
call %o1
nop
- b halt_me
+ st %o0, [current_node]
+ set prop_string_buf, %o2
+ set prop_name, %o1
+ b node_find_loop
+ or %g0, 31, %o3
+
+found_mem_node:
+ set v2_mem_struct-KERNBASE, %o2
+ set 0xff, %o3
+ set mem_prop_physavail-KERNBASE, %o1
+ ld [current_node], %o0
+ ld [prom_nodefuncs], %o4
+ ld [%o4 + 0xc], %o4
+ call %o4
nop
+ set v2_printf_physavail-KERNBASE, %o0
+ ld [v2_mem_struct + 0x8], %o1
+ ld [prom_printf], %o4
+ ld [%o4], %o4
+ call %o4
+
+ set v2_mem_struct-KERNBASE, %o2
+ set 0xff, %o3
+ set mem_prop_phystot-KERNBASE, %o1
+ ld [current_node], %o0
+ ld [prom_nodefuncs], %o4
+ ld [%o4 + 0xc], %o4
+ call %o4
+ nop
+
+ set v2_printf_physavail-KERNBASE, %o0
+ ld [v2_mem_struct + 0x8], %o1
+ ld [prom_printf], %o4
+ ld [%o4], %o4
+ call %o4
+ nop
+
+ b rest_of_boot
+ nop
+
+rest_of_boot:
+ call halt_me
+ nop ! who cares at this point
+
+/* There, happy now adrian? */
+
no_sun4d_here:
ld [%g7 + 0x68], %o1
set sun4d_notsup, %o0
ret
nop
+
+
+
+
--- /dev/null
+/* string.h: Efficient string functions in sparc-assembly for
+ the linux kernel.
+
+ Copyright 1994 (c) David S. Miller (davem@caip.rutgers.edu)
+*/
+
+
+/* If we are smart we will use only the output and global registers
+ as that will allow us to avoid a window save which would be nice.
+*/
+
+/* Believe it or not the following strlen is not optimized enough!
+ In the future I may play games with doing word reads and reducing
+ the per-word comparisons to *one*, yes I have seen it done.
+*/
+ .align 4
+ .globl _strlen
+_strlen:
+ mov %o0, %g3 ! leaf-proceedure optimization, here
+ ldsb [%g3], %g2 ! I only use the register sent to me
+ cmp %g2, 0 ! and the globals. Now, this routine
+ be 1f ! is callable from boot code.
+ nop
+ add %o0, 1, %o0
+0: ldsb [%o0], %g2
+ cmp %g2, 0
+ bne,a 0b ! annuling branch, yuck
+ add %o0, 1, %o0
+
+1: retl
+ sub %o0, %g3, %o0 ! since %g3 holds the origional pointer
+ ! and %o0 is at the end byte, we can
+ ! subtract and the result is strlen.
+
+/* String concatenate function. I am too lazy to honor the third count
+ arguement at this time. Once again, this could be optimized so much
+ more to use word accesses instead of slooow byte loads.
+*/
+ .align 4
+ .globl _strcat
+_strcat:
+ mov %o0, %g4
+ ldsb [%g4], %g3
+ cmp %g3, 0
+ be,a 2f
+ ldub [%o1], %g3
+ add %o0, 1, %o0
+
+0: ldsb [%o0], %g3
+ cmp %g3, 0
+ bne,a 0b
+ add %o0, 1, %o0
+
+1: ldub [%o1], %g3
+
+2: add %o1, 1, %o1
+ stb %g3, [%o0]
+ cmp %g3, 0
+ bne 1b
+ add %o0, 1, %o0
+ retl
+ mov %g4, %o0
+
+/* Aieee, this code is starting to give me a headache. I shouldn't
+ have tried to do this in one sitting :-(
+*/
+
+ .align 4
+ .globl _strcmp
+_strcmp: b 2f
+ ldsb [%o1], %g4
+
+0: sll %o2, 24, %g3
+ cmp %g3, 0
+ bne 1f
+ add %o0, 1, %o0
+ b 3f
+ or %g0, %g0, %o0
+
+1: ldsb [%o1], %g4
+
+2: ldsb [%o0], %g3
+ add %o1, 1, %o1
+ cmp %g3, %g4
+ be 0b
+ mov %g3, %o2
+ ldub [%o2], %g3
+ ldub [%o1-1], %o0 ! oh man, no joke
+ sub %g2, %o0, %o0
+
+3: retl
+ nop
+
+/* Ok, strcpy() should be easy enough. Maybe I catch some sleep after
+ this one....
+*/
+ .align 4
+ .globl _strcpy
+_strcpy: ldub [%o1], %g3
+ mov %o0, %g4
+ cmp %g3, 0
+ be 1f
+ stb %g3, [%g4]
+
+0: add %o1, 1, %o1
+ ldub [%o1], %g3
+ add %o0, 1, %o0
+ cmp %g3, 0
+ bne 0b
+ stb %g3, [%o0]
+
+1: retl
+ mov %g4, %o0
+
+
\ No newline at end of file
*/
#define CONFIG_FLOPPY_SANITY
-#undef CONFIG_FLOPPY_23
-#undef CONFIG_FLOPPY_2_FDC
+#define CONFIG_FLOPPY_2_FDC
#undef CONFIG_FLOPPY_SILENT_DCL_CLEAR
#define REALLY_SLOW_IO
* motor of these drives causes system hangs on some PCI computers. drive
* 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if
* a drive is allowed. */
-#ifdef CONFIG_FLOPPY_23
-#define ALLOWED_DRIVE_MASK 0xff
-#else
-#define ALLOWED_DRIVE_MASK 0x33
-#endif
+static int ALLOWED_DRIVE_MASK=0x33;
#define FLOPPY_IRQ 6
#define FLOPPY_DMA 2
#define FDC1 0x3f0
-#define FDC2 0x370
+static int FDC2=-1;
#endif
#define MODULE_AWARE_DRIVER
#define R_SECTOR (reply_buffer[5])
#define R_SIZECODE (reply_buffer[6])
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof( (x)[0] ))
/*
* this struct defines the different floppy drive types.
*/
printk("floppy driver state\n");
printk("-------------------\n");
for(i=0; i<N_FDC; i++){
- printk("dor %d = %x\n", i, fdc_state[i].dor );
- outb_p(fdc_state[i].address+2, fdc_state[i].dor);
- udelay(1000); /* maybe we'll catch an interrupt... */
+ if(FDCS->address != -1){
+ printk("dor %d = %x\n", i, fdc_state[i].dor );
+ outb_p(fdc_state[i].address+2, fdc_state[i].dor);
+ udelay(1000); /* maybe we'll catch an interrupt... */
+ }
}
printk("status=%x\n", inb_p(FD_STATUS));
printk("fdc_busy=%d\n", fdc_busy);
return FDC_82077; /* Revised 82077AA passes all the tests */
} /* get_fdc_version */
+#ifndef FD_MODULE
+/* lilo configuration */
+static void invert_dcl(int *ints)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(default_drive_params); i++)
+ default_drive_params[i].params.flags |= 0x80;
+ DPRINT("Configuring drives for inverted dcl\n");
+}
+
+static void allow_drives(int *ints)
+{
+ if (ints[1] >= 1 ){
+ ALLOWED_DRIVE_MASK=ints[1];
+ DPRINT1("setting allowed_drive_mask to 0x%x\n", ints[1]);
+ } else
+ DPRINT("allowed_drive_mask needs a parameter\n");
+}
+
+#ifdef CONFIG_FLOPPY_2_FDC
+static void twofdc(int *ints)
+{
+ FDC2 = 0x370;
+ DPRINT("enabling second fdc at address 0x370\n");
+}
+#endif
+
+static struct param_table {
+ char *name;
+ void (*fn)(int *ints);
+} config_params[]={
+{ "allowed_drive_mask", allow_drives },
+#ifdef CONFIG_FLOPPY_2_FDC
+{ "two_fdc", twofdc },
+#endif
+{ "thinkpad", invert_dcl } };
+
+void floppy_setup(char *str, int *ints)
+{
+ int i;
+ for(i=0; i< ARRAY_SIZE(config_params); i++){
+ if (strcmp(str,config_params[i].name) == 0 ){
+ config_params[i].fn(ints);
+ return;
+ }
+ }
+ printk("unknown floppy paramter %s\n", str);
+}
+#endif
+
#ifdef FD_MODULE
static
#endif
if (FDCS->address == -1 )
continue;
FDCS->rawcmd = 2;
- if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
+ if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)){
+ FDCS->address = -1;
continue;
+ }
/* Try to determine the floppy controller type */
FDCS->version = get_fdc_version();
- if (FDCS->version == FDC_NONE)
+ if (FDCS->version == FDC_NONE){
+ FDCS->address = -1;
continue;
+ }
have_no_fdc = 0;
/* Not all FDCs seem to be able to handle the version command
#ifdef FD_MODULE
MOD_INC_USE_COUNT;
#endif
- for(i=0; i< N_FDC; i++){
- fdc = i;
- reset_fdc_info(1);
- outb_p(FDCS->dor, FD_DOR);
+ for(i=0; i< N_FDC; i++){
+ if(FDCS->address != -1){
+ fdc = i;
+ reset_fdc_info(1);
+ outb_p(FDCS->dor, FD_DOR);
+ }
}
set_dor(0, ~0, 8); /* avoid immediate interrupt */
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
/*
if (testvalue == LP_DUMMY) {
LP_F(offset) |= LP_EXIST;
lp_reset(offset);
- printk("lp_init: lp%d exists, ", offset);
+ printk("lp%d at 0x%04x, ", offset,LP_B(offset));
snarf_region(LP_B(offset), 3);
if (LP_IRQ(offset))
printk("using IRQ%d\n", LP_IRQ(offset));
if (testvalue == LP_DUMMY) {
LP_F(offset) |= LP_EXIST;
lp_reset(offset);
- printk("lp_init: lp%d exists, ", offset);
+ printk("lp%d at 0x%04x, ", offset,LP_B(offset));
+ snarf_region(LP_B(offset),3);
if (LP_IRQ(offset))
printk("using IRQ%d\n", LP_IRQ(offset));
else
void cleanup_module(void)
{
- if(MOD_IN_USE)
+ int offset;
+ if(MOD_IN_USE)
printk("lp: busy - remove delayed\n");
- else
+ else
unregister_chrdev(LP_MAJOR,"lp");
+ for (offset = 0; offset < LP_NO; offset++)
+ if(LP_F(offset) && LP_EXIST)
+ release_region(LP_B(offset),3);
}
#endif
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
extern struct device *init_etherdev(struct device *dev, int sizeof_private,
#include <linux/skbuff.h>
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
/* These are the operational function interfaces to board-specific
de600.o \
de620.o \
3c501.o \
+ apricot.o \
eexpress.o \
plip.o \
8390.o
#include <linux/netdevice.h>
#include <linux/errno.h>
-#define LOOPBACK /* always present, right? */
-
#define NEXT_DEV NULL
extern int at1500_probe(struct device *);
extern int at1700_probe(struct device *);
extern int depca_probe(struct device *);
+extern int apricot_probe(struct device *);
extern int ewrk3_probe(struct device *);
extern int el1_probe(struct device *);
extern int el16_probe(struct device *);
#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */
&& ewrk3_probe(dev)
#endif
+#ifdef CONFIG_APRICOT /* Apricot I82596 */
+ && apricot_probe(dev)
+#endif
#ifdef CONFIG_EL1 /* 3c501 */
&& el1_probe(dev)
#endif
# define NEXT_DEV (&dummy_dev)
#endif
-#ifdef LOOPBACK
- extern int loopback_init(struct device *dev);
- static struct device loopback_dev = {
+extern int loopback_init(struct device *dev);
+struct device loopback_dev = {
"lo", /* Software Loopback interface */
0x0, /* recv memory end */
0x0, /* recv memory start */
0, 0, 0, /* flags */
NEXT_DEV, /* next device */
loopback_init /* loopback_init should set up the rest */
- };
-# undef NEXT_DEV
-# define NEXT_DEV (&loopback_dev)
-#endif
-
+};
-struct device *dev_base = NEXT_DEV;
+struct device *dev_base = &loopback_dev;
Apricot
Written 1994 by Mark Evans.
This driver is for the Apricot 82596 bus-master interface
+
+ Modularised 12/94 Mark Evans
Driver skeleton
Written 1993 by Donald Becker.
*/
-static char *version = "apricot.c:v0.02 19/05/94\n";
+static char *version = "apricot.c:v0.2 05/12/94\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
#ifndef HAVE_PORTRESERVE
#define check_region(addr, size) 0
#define snarf_region(addr, size) do ; while(0)
#define kfree_skbmem(buff, size) kfree_s(buff,size)
#endif
-struct device *init_etherdev(struct device *dev, int sizeof_private,
- unsigned long *mem_start);
-
#define APRICOT_DEBUG 1
#ifdef APRICOT_DEBUG
#define APRICOT_TOTAL_SIZE 17
+#define I596_NULL -1
+
#define CMD_EOL 0x8000 /* The last command of the list, stop. */
#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
char data[1532];
};
-#define RX_RING_SIZE 16
+#define RX_RING_SIZE 8
struct i596_scb {
unsigned short status;
char i596_config[16];
struct i596_cmd tdr;
unsigned long stat;
- struct i596_rfd rx[RX_RING_SIZE];
int last_restart;
struct i596_rfd *rx_tail;
struct i596_cmd *cmd_tail;
0x00,
0x7f /* *multi IA */ };
-char adds[] = {0x00, 0x00, 0x49, 0x20, 0x54, 0xDA, 0x80, 0x00, 0x4e, 0x02, 0xb7, 0xb8};
-
static int i596_open(struct device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct device *dev);
static void i596_interrupt(int reg_ptr);
#endif
\f
-static inline void
-init_rx_bufs(struct device *dev)
+static inline int
+init_rx_bufs(struct device *dev, int num)
{
struct i596_private *lp = (struct i596_private *)dev->priv;
int i;
- int boguscnt = 100;
- short ioaddr = dev->base_addr;
+ struct i596_rfd *rfd;
+
+ lp->scb.rfd = (struct i596_rfd *)I596_NULL;
- if (i596_debug > 1) printk ("%s: init_rx_bufs.\n", dev->name);
+ if (i596_debug > 1) printk ("%s: init_rx_bufs %d.\n", dev->name, num);
- for (i = 0; i < RX_RING_SIZE; i++)
+ for (i = 0; i < num; i++)
{
- if (i == 0)
- {
- lp->scb.rfd = &lp->rx[0];
- }
- if (i == (RX_RING_SIZE - 1))
- {
- lp->rx_tail = &(lp->rx[i]);
- lp->rx[i].next = &lp->rx[0];
- lp->rx[i].cmd = CMD_EOL;
- }
- else
- {
- lp->rx[i].next = &lp->rx[i+1];
- lp->rx[i].cmd = 0x0000;
- }
- lp->rx[i].stat = 0x0000;
- lp->rx[i].rbd = 0xffffffff;
- lp->rx[i].count = 0;
- lp->rx[i].size = 1532;
+ if (!(rfd = (struct i596_rfd *)kmalloc(sizeof(struct i596_rfd), GFP_KERNEL)))
+ break;
+
+ rfd->stat = 0x0000;
+ rfd->rbd = I596_NULL;
+ rfd->count = 0;
+ rfd->size = 1532;
+ if (i == 0)
+ {
+ rfd->cmd = CMD_EOL;
+ lp->rx_tail = rfd;
+ }
+ else
+ rfd->cmd = 0x0000;
+
+ rfd->next = lp->scb.rfd;
+ lp->scb.rfd = rfd;
}
- while (lp->scb.status, lp->scb.command)
- if (--boguscnt == 0)
- {
- printk("%s: init_rx_bufs timed out with status %4.4x, cmd %4.4x.\n",
- dev->name, lp->scb.status, lp->scb.command);
- break;
- }
+ if (i != 0)
+ lp->rx_tail->next = lp->scb.rfd;
- lp->scb.command = RX_START;
- outw(0, ioaddr+4);
+ return (i);
+}
- return;
+static inline void
+remove_rx_bufs(struct device *dev)
+{
+ struct i596_private *lp = (struct i596_private *)dev->priv;
+ struct i596_rfd *rfd = lp->scb.rfd;
+ lp->rx_tail->next = (struct i596_rfd *)I596_NULL;
+
+ do
+ {
+ lp->scb.rfd = rfd->next;
+ kfree_s(rfd, sizeof(struct i596_rfd));
+ rfd = lp->scb.rfd;
+ }
+ while (rfd != lp->rx_tail);
}
static inline void
outw(((((int)&lp->scp) & 0xffff) | 2), ioaddr);
outw((((int)&lp->scp)>>16) & 0xffff, ioaddr);
- lp->last_cmd=jiffies;
+ lp->last_cmd = jiffies;
lp->scp.sysbus = 0x00440000;
lp->scp.iscp = &(lp->iscp);
lp->iscp.stat = 0x0001;
lp->cmd_backlog = 0;
- lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) -1;
+ lp->cmd_head = lp->scb.cmd = (struct i596_cmd *) I596_NULL;
if (i596_debug > 2) printk("%s: starting i82596.\n", dev->name);
break;
}
+ lp->scb.command = 0;
+
memcpy (lp->i596_config, init_setup, 14);
lp->set_conf.command = CmdConfigure;
i596_add_cmd(dev, &lp->set_conf);
lp->tdr.command = CmdTDR;
i596_add_cmd(dev, &lp->tdr);
- init_rx_bufs(dev);
+ boguscnt = 200;
+ while (lp->scb.status, lp->scb.command)
+ if (--boguscnt == 0)
+ {
+ printk("%s: recieve unit start timed out with status %4.4x, cmd %4.4x.\n",
+ dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
- boguscnt=200;
+ lp->scb.command = RX_START;
+ outw(0, ioaddr+4);
+
+ boguscnt = 200;
while (lp->scb.status, lp->scb.command)
if (--boguscnt == 0)
{
i596_rx(struct device *dev)
{
struct i596_private *lp = (struct i596_private *)dev->priv;
- int frames=0;
+ int frames = 0;
if (i596_debug > 3) printk ("i596_rx()\n");
}
skb->len = pkt_len;
- skb->dev=dev;
+ skb->dev = dev;
memcpy(skb->data, lp->scb.rfd->data, pkt_len);
netif_rx(skb);
if ((lp->scb.rfd->stat) & 0x1000) lp->stats.rx_length_errors++;
}
- lp->scb.rfd->stat=0;
- lp->rx_tail->cmd=0;
- lp->rx_tail=lp->scb.rfd;
- lp->scb.rfd=lp->scb.rfd->next;
- lp->rx_tail->count=0;
- lp->rx_tail->cmd=CMD_EOL;
+ lp->scb.rfd->stat = 0;
+ lp->rx_tail->cmd = 0;
+ lp->rx_tail = lp->scb.rfd;
+ lp->scb.rfd = lp->scb.rfd->next;
+ lp->rx_tail->count = 0;
+ lp->rx_tail->cmd = CMD_EOL;
}
if (i596_debug > 4) printk ("i596_cleanup_cmd\n");
- while (lp->cmd_head != (struct i596_cmd *) -1)
+ while (lp->cmd_head != (struct i596_cmd *) I596_NULL)
{
ptr = lp->cmd_head;
lp->stats.tx_errors++;
lp->stats.tx_aborted_errors++;
- ptr->next = (struct i596_cmd * ) -1;
+ ptr->next = (struct i596_cmd * ) I596_NULL;
kfree_s((unsigned char *)tx_cmd, (sizeof (struct tx_cmd) + sizeof (struct i596_tbd)));
break;
}
{
unsigned short count = *((unsigned short *) (ptr + 1));
- ptr->next = (struct i596_cmd * ) -1;
+ ptr->next = (struct i596_cmd * ) I596_NULL;
kfree_s((unsigned char *)ptr, (sizeof (struct i596_cmd) + count + 2));
break;
}
default:
- ptr->next = (struct i596_cmd * ) -1;
+ ptr->next = (struct i596_cmd * ) I596_NULL;
}
}
break;
}
- dev->start=0;
- dev->tbusy=1;
+ dev->start = 0;
+ dev->tbusy = 1;
- lp->scb.command=CUC_ABORT|RX_ABORT;
+ lp->scb.command = CUC_ABORT|RX_ABORT;
outw(0, ioaddr+4);
/* wait for shutdown */
i596_cleanup_cmd(lp);
i596_rx(dev);
- dev->start=1;
- dev->tbusy=0;
- dev->interrupt=0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ dev->interrupt = 0;
init_i596_mem(dev);
}
cmd->status = 0;
cmd->command |= (CMD_EOL|CMD_INTR);
- cmd->next = (struct i596_cmd *) -1;
+ cmd->next = (struct i596_cmd *) I596_NULL;
save_flags(flags);
cli();
- if (lp->cmd_head != (struct i596_cmd *) -1)
+ if (lp->cmd_head != (struct i596_cmd *) I596_NULL)
lp->cmd_tail->next = cmd;
else
{
- lp->cmd_head=cmd;
+ lp->cmd_head = cmd;
while (lp->scb.status, lp->scb.command)
if (--boguscnt == 0)
{
lp->scb.command = CUC_START;
outw (0, ioaddr+4);
}
- lp->cmd_tail=cmd;
+ lp->cmd_tail = cmd;
lp->cmd_backlog++;
- lp->cmd_head=lp->scb.cmd;
+ lp->cmd_head = lp->scb.cmd;
restore_flags(flags);
if (lp->cmd_backlog > 16)
static int
i596_open(struct device *dev)
{
- if (request_irq(dev->irq, &i596_interrupt, 0, "apricot")) {
+ int i;
+
+ if (i596_debug > 1)
+ printk("%s: i596_open() irq %d.\n", dev->name, dev->irq);
+
+ if (request_irq(dev->irq, &i596_interrupt, 0, "apricot"))
return -EAGAIN;
- }
irq2dev_map[dev->irq] = dev;
- if (i596_debug > 1)
- printk("%s: i596_open() irq %d.\n",
- dev->name, dev->irq);
+ i = init_rx_bufs(dev, RX_RING_SIZE);
+
+ if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE)
+ printk("%s: only able to allocate %d receive buffers\n", dev->name, i);
+
+ if (i < 4)
+ {
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = 0;
+ return -EAGAIN;
+ }
dev->tbusy = 0;
dev->interrupt = 0;
dev->start = 1;
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
/* Initialize the 82596 memory */
init_i596_mem(dev);
/* Issue a channel attention signal */
if (i596_debug > 1) printk ("Kicking board.\n");
- lp->scb.command=CUC_START|RX_START;
+ lp->scb.command = CUC_START|RX_START;
outw(0, ioaddr+4);
lp->last_restart = lp->stats.tx_packets;
else
{
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- dev->trans_start=jiffies;
+ dev->trans_start = jiffies;
tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
if (tx_cmd == NULL)
else
{
tx_cmd->tbd = (struct i596_tbd *) (tx_cmd + 1);
- tx_cmd->tbd->next = (struct i596_tbd *) -1;
+ tx_cmd->tbd->next = (struct i596_tbd *) I596_NULL;
tx_cmd->cmd.command = CMD_FLEX|CmdTx;
printk ("type %2.2X%2.2X\n", (unsigned char)add[12], (unsigned char)add[13]);
}
-unsigned long apricot_init(unsigned long mem_start, unsigned long mem_end)
+int apricot_probe(struct device *dev)
{
- struct device *dev;
int i;
+ struct i596_private *lp;
int checksum = 0;
int ioaddr = 0x300;
char eth_addr[6];
/* first check nothing is already registered here */
if (check_region(ioaddr, APRICOT_TOTAL_SIZE))
- return mem_start;
+ return ENODEV;
for (i = 0; i < 8; i++)
- checksum += inb(ioaddr + 8 + i);
+ {
+ eth_addr[i] = inb(ioaddr+8+i);
+ checksum += eth_addr[i];
+ }
/* checksum is a multiple of 0x100, got this wrong first time
some machines have 0x100, some 0x200. The DOS driver doesn't
even bother with the checksum */
- if (checksum % 0x100) return mem_start;
-
+ if (checksum % 0x100) return ENODEV;
- for(i = 0; i < 6 ; i++)
- eth_addr[i] = inb(ioaddr +8 +i);
-
/* Some other boards trip the checksum.. but then appear as ether
address 0. Trap these - AC */
- if(memcmp(eth_addr,"\x00\x00\x00\x00\x00\x00",6)==0)
- return mem_start;
+ if(memcmp(eth_addr,"\x00\x00\x49",3)!= 0)
+ return ENODEV;
+
+ snarf_region(ioaddr, APRICOT_TOTAL_SIZE);
- dev = init_etherdev(0, (sizeof (struct i596_private) + 0xf), &mem_start);
+ dev->base_addr = ioaddr;
+ ether_setup(dev);
printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr);
for (i = 0; i < 6; i++)
dev->irq = 10;
printk(" IRQ %d.\n", dev->irq);
- snarf_region(ioaddr, APRICOT_TOTAL_SIZE);
-
- if (i596_debug > 0)
- printk(version);
+ if (i596_debug > 0) printk(version);
/* The APRICOT-specific entries in the device structure. */
dev->open = &i596_open;
dev->set_multicast_list = &set_multicast_list;
#endif
+ dev->mem_start = (int)kmalloc(sizeof(struct i596_private)+ 0x0f, GFP_KERNEL);
/* align for scp */
- dev->priv = (void *)(((int) dev->priv + 0xf) & 0xfffffff0);
+ dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0);
- return mem_start;
+ lp = (struct i596_private *)dev->priv;
+ lp->scb.command = 0;
+ lp->scb.cmd = (struct i596_cmd *) I596_NULL;
+ lp->scb.rfd = (struct i596_rfd *)I596_NULL;
+
+ return 0;
}
static void
struct i596_private *lp;
short ioaddr;
int boguscnt = 200;
- unsigned short status, ack_cmd=0;
+ unsigned short status, ack_cmd = 0;
if (dev == NULL) {
printk ("i596_interrupt(): irq %d for unknown device.\n", irq);
if ((i596_debug > 4) && (status & 0x2000))
printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700);
- while ((lp->cmd_head != (struct i596_cmd *) -1) && (lp->cmd_head->status & STAT_C))
+ while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C))
{
ptr = lp->cmd_head;
}
- ptr->next = (struct i596_cmd * ) -1;
+ ptr->next = (struct i596_cmd * ) I596_NULL;
kfree_s((unsigned char *)tx_cmd, (sizeof (struct tx_cmd) + sizeof (struct i596_tbd)));
break;
}
{
unsigned short count = *((unsigned short *) (ptr + 1));
- ptr->next = (struct i596_cmd * ) -1;
+ ptr->next = (struct i596_cmd * ) I596_NULL;
kfree_s((unsigned char *)ptr, (sizeof (struct i596_cmd) + count + 2));
break;
}
}
}
default:
- ptr->next = (struct i596_cmd * ) -1;
+ ptr->next = (struct i596_cmd * ) I596_NULL;
- lp->last_cmd=jiffies;
+ lp->last_cmd = jiffies;
}
}
ptr = lp->cmd_head;
- while ((ptr != (struct i596_cmd *) -1) && (ptr != lp->cmd_tail))
+ while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail))
{
ptr->command &= 0x1fff;
ptr = ptr->next;
}
- if ((lp->cmd_head != (struct i596_cmd *) -1) && (dev->start)) ack_cmd |= CUC_START;
+ if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd |= CUC_START;
lp->scb.cmd = lp->cmd_head;
}
/* acknowledge the interrupt */
/*
- if ((lp->scb.cmd != (struct i596_cmd *) -1) && (dev->start)) ack_cmd |= CUC_START;
+ if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd | = CUC_START;
*/
boguscnt = 100;
while (lp->scb.status, lp->scb.command)
{
int ioaddr = dev->base_addr;
struct i596_private *lp = (struct i596_private *)dev->priv;
+ int boguscnt = 200;
dev->start = 0;
dev->tbusy = 1;
i596_cleanup_cmd(lp);
+ while (lp->scb.status, lp->scb.command)
+ if (--boguscnt == 0)
+ {
+ printk("%s: close timed timed out with status %4.4x, cmd %4.4x.\n",
+ dev->name, lp->scb.status, lp->scb.command);
+ break;
+ }
free_irq(dev->irq);
irq2dev_map[dev->irq] = 0;
+ remove_rx_bufs(dev);
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+
return 0;
}
i596_add_cmd(dev, cmd);
} else
{
- if (lp->set_conf.next != (struct i596_cmd * ) -1) return;
+ if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL) return;
if (num_addrs == 0)
lp->i596_config[8] &= ~0x01;
else
#ifdef HAVE_DEVLIST
static unsigned int apricot_portlist[] = {0x300, 0};
-struct netdev_entry apricot_drv =
-{"apricot", apricot_init, APRICOT_TOTAL_SIZE, apricot_portlist};
+struct netdev_entry apricot_drv =
+{"apricot", apricot_probe, APRICOT_TOTAL_SIZE, apricot_portlist};
#endif
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+static struct device dev_apricot = {
+ " ", /* device name inservted by /linux/drivers/net/net_init.c */
+ 0, 0, 0, 0,
+ 0x300, 10,
+ 0, 0, 0, NULL, apricot_probe };
+
+int
+init_module(void)
+{
+ if (register_netdev(&dev_apricot) != 0)
+ return -EIO;
+ return 0;
+}
+
+void
+cleanup_module(void)
+{
+ if (MOD_IN_USE)
+ printk("%s: device busy, remove delayed\n", dev_apricot.name);
+ else
+ {
+ unregister_netdev(&dev_apricot);
+ kfree_s((void *)dev_apricot.mem_start, sizeof(struct i596_private) + 0xf);
+ dev_apricot.priv = NULL;
+ }
+}
+#endif /* MODULE */
\f
/*
* Local variables:
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
#ifdef FAKE_SMALL_MAX
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
/* Constant definitions for the DE-620 registers, commands and bits */
#ifdef MODULE
#include <linux/module.h>
-#include "/linux/tools/version.h"
+#include <linux/version.h>
#endif /* MODULE */
#include "depca.h"
#include <linux/skbuff.h>
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
#include <linux/malloc.h>
#ifdef MODULE
#include <linux/module.h>
-#include "/linux/tools/version.h"
+#include <linux/version.h>
#endif /* MODULE */
#include "ewrk3.h"
#endif
#if defined(CONFIG_PI)
mem_start = pi_init(mem_start, mem_end);
-#endif
-#if defined(CONFIG_APRICOT)
- mem_start = apricot_init(mem_start, mem_end);
#endif
return mem_start;
}
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
/* use 0 for production, 1 for verification, >2 for debug */
lp->stats.rx_length_errors++;
} else {
/* Malloc up new buffer. */
- int sksize = sizeof(struct sk_buff) + pkt_len;
struct sk_buff *skb;
- skb = alloc_skb(sksize, GFP_ATOMIC);
+ skb = alloc_skb(pkt_len, GFP_ATOMIC);
if (skb == NULL) {
if (znet_debug)
printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
lp->stats.rx_dropped++;
break;
}
- skb->mem_len = sksize;
- skb->mem_addr = skb;
skb->len = pkt_len;
skb->dev = dev;
};
static struct scsi_generic *scsi_generics=NULL;
+static void sg_free(char *buff,int size);
static int sg_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
{
if (scsi_generics[dev].buff != NULL)
- scsi_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
+ sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
scsi_generics[dev].buff=NULL;
scsi_generics[dev].pending=0;
}
#ifndef CONFIG_BINFMT_ELF
#include <linux/module.h>
-#include "../tools/version.h"
+#include <linux/version.h>
#endif
#include <linux/unistd.h>
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#endif
#ifdef LEAK_CHECK
#ifdef MODULE
#include <linux/module.h>
- #include "../../tools/version.h"
+ #include <linux/version.h>
#endif
#include <asm/segment.h>
#include <linux/string.h>
#include <linux/mman.h>
#include <linux/proc_fs.h>
+#include <linux/ioport.h>
#include <asm/segment.h>
#include <asm/io.h>
case PROC_DMA:
return get_dma_list(page);
+ case PROC_IOPORTS:
+ return get_ioport_list(page);
}
return -EBADF;
}
{ PROC_FILESYSTEMS, 11,"filesystems" },
{ PROC_KSYMS, 5, "ksyms" },
{ PROC_DMA, 3, "dma" },
+ { PROC_IOPORTS, 7, "ioports"},
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#ifdef MODULE
#include <linux/module.h>
- #include "../../tools/version.h"
+ #include <linux/version.h>
#endif
struct inode *pseudo_root=NULL; /* Useful to simulate the pseudo DOS */
#ifdef MODULE
#include <linux/module.h>
-#include "../../tools/version.h"
+#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#ifndef _M68K_SYSTEM_H
#define _M68K_SYSTEM_H
-#include <linux/autoconf.h> /* get configuration makros */
+#include <linux/autoconf.h> /* get configuration macros */
#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
/* block out HSYNC on the atari */
#define FD_BROKEN_DCL 0x20
#define FD_DEBUG 0x02
#define FD_SILENT_DCL_CLEAR 0x4
+#define FD_INVERTED_DCL 0x80
char read_track; /* use readtrack during probing? */
extern int check_region(unsigned int from, unsigned int extent);
extern void snarf_region(unsigned int from, unsigned int extent);
extern void release_region(unsigned int from, unsigned int extent);
+extern int get_ioport_list(char *);
#define HAVE_AUTOIRQ
extern volatile char in_bh;
+extern struct device loopback_dev;
extern struct device *dev_base;
extern struct packet_type *ptype_base;
PROC_INTERRUPTS,
PROC_FILESYSTEMS,
PROC_KSYMS,
- PROC_DMA
+ PROC_DMA,
+ PROC_IOPORTS
};
enum pid_directory_inos {
extern void bmouse_setup(char *str, int *ints);
extern void eth_setup(char *str, int *ints);
extern void xd_setup(char *str, int *ints);
+extern void floppy_setup(char *str, int *ints);
extern void mcd_setup(char *str, int *ints);
extern void st_setup(char *str, int *ints);
extern void st0x_setup(char *str, int *ints);
#ifdef CONFIG_BLK_DEV_XD
{ "xd=", xd_setup },
#endif
+#ifdef CONFIG_BLK_DEV_FD
+ { "floppy=", floppy_setup },
+#endif
#ifdef CONFIG_MCD
{ "mcd=", mcd_setup },
#endif
return 0;
}
+int get_ioport_list(char *buf)
+{ int len=0,num,from;
+ for(num=0;num<IO_BITMAP_SIZE*32;num++)
+ if(check_bitmap(ioport_registrar,num,1)) {
+ from=num;
+ while(check_bitmap(ioport_registrar,num+1,1)
+ && num+1<IO_BITMAP_SIZE*32 )
+ num++;
+ if(from==num)
+ len+=sprintf(buf+len,"%04x\n",num);
+ else
+ len+=sprintf(buf+len,"%04x-%04x\n",from,num);
+ if(len>4000) {
+ len+=sprintf((buf+len),"4k-Limit reached!\n");
+ return len;
+ }
+ }
+ return len;
+}
+
/*
* this changes the io permissions bitmap in the current task.
*/
#ifdef CONFIG_PCI
/* PCI BIOS support */
+ X(pcibios_present),
X(pcibios_find_class),
X(pcibios_find_device),
X(pcibios_read_config_byte),
X(ftape_big_buffer),
X(do_floppy),
#endif
+ X(floppy_track_buffer),
#ifdef CONFIG_INET
/* support for loadable net drivers */
X(register_netdev),
X(kfree_skb),
X(dev_kfree_skb),
X(snarf_region),
+ X(release_region),
X(netif_rx),
X(dev_rint),
X(dev_tint),
return -ENOEXEC;
ops = &file_private_mmap;
if (vma->vm_flags & VM_SHARED) {
- if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE))
+ if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) {
+ static int nr = 0;
ops = &file_shared_mmap;
+ if (nr++ < 5)
+ printk("%s tried to do a shared writeable mapping\n", current->comm);
+ return -EINVAL;
+ }
}
if (!IS_RDONLY(inode)) {
inode->i_atime = CURRENT_TIME;
struct swap_info_struct * p;
struct inode * inode;
unsigned int type;
+ struct file filp;
int i;
if (!suser())
break;
}
}
- iput(inode);
- if (type >= nr_swapfiles)
+
+ if (type >= nr_swapfiles){
+ iput(inode);
return -EINVAL;
+ }
p->flags = SWP_USED;
i = try_to_unuse(type);
if (i) {
+ iput(inode);
p->flags = SWP_WRITEOK;
return i;
}
+
+ if(p->swap_device){
+ memset(&filp, 0, sizeof(filp));
+ filp.f_inode = inode;
+ filp.f_mode = 3; /* read write */
+ /* open it again to get fops */
+ if( !blkdev_open(inode, &filp) &&
+ filp.f_op && filp.f_op->release){
+ filp.f_op->release(inode,&filp);
+ filp.f_op->release(inode,&filp);
+ }
+ }
+ iput(inode);
+
nr_swap_pages -= p->pages;
iput(p->swap_file);
p->swap_file = NULL;
unsigned int type;
int i,j;
int error;
+ struct file filp;
+ memset(&filp, 0, sizeof(filp));
if (!suser())
return -EPERM;
p = swap_info;
p->max = 1;
error = namei(specialfile,&swap_inode);
if (error)
- goto bad_swap;
+ goto bad_swap_2;
p->swap_file = swap_inode;
error = -EBUSY;
if (swap_inode->i_count != 1)
- goto bad_swap;
+ goto bad_swap_2;
error = -EINVAL;
+
if (S_ISBLK(swap_inode->i_mode)) {
p->swap_device = swap_inode->i_rdev;
+
+ filp.f_inode = swap_inode;
+ filp.f_mode = 3; /* read write */
+ error = blkdev_open(swap_inode, &filp);
p->swap_file = NULL;
iput(swap_inode);
+ if(error)
+ goto bad_swap_2;
error = -ENODEV;
if (!p->swap_device)
goto bad_swap;
printk("Adding Swap: %dk swap-space\n",j<<2);
return 0;
bad_swap:
+ if(filp.f_op && filp.f_op->release)
+ filp.f_op->release(filp.f_inode,&filp);
+bad_swap_2:
free_page((long) p->swap_lockmap);
vfree(p->swap_map);
iput(p->swap_file);
-3c509.o de600.o de620.o 3c501.o eexpress.o plip.o 8390.o
+3c509.o de600.o de620.o 3c501.o apricot.o eexpress.o plip.o 8390.o
return;
i->users=1;
i->interface=dev;
+ i->multiaddr=addr;
i->next=dev->ip_mc_list;
igmp_group_added(i);
dev->ip_mc_list=i;
* See if we need to look up the device.
*/
+#ifdef CONFIG_INET_MULTICAST
+ if(MULTICAST(daddr) && *dev==NULL && skb->sk && *skb->sk->ip_mc_name)
+ *dev=dev_get(skb->sk->ip_mc_name);
+#endif
if (*dev == NULL)
{
if(skb->localroute)
iph->saddr = saddr;
iph->protocol = type;
iph->ihl = 5;
+ skb->ip_hdr = iph;
/* Setup the IP options. */
#ifdef Not_Yet_Avail
kfree_skb(skb, FREE_WRITE);
return(0);
}
-
+
+#ifdef CONFIG_IP_MULTICAST
+ if(brd==IS_MULTICAST)
+ {
+ /*
+ * Check it is for one of our groups
+ */
+ struct ip_mc_list *ip_mc=dev->ip_mc_list;
+ do
+ {
+ if(ip_mc==NULL)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ return 0;
+ }
+ if(ip_mc->multiaddr==iph->daddr)
+ break;
+ ip_mc=ip_mc->next;
+ }
+ while(1);
+ }
+#endif
/*
* Account for the packet
*/
return(0);
}
+/*
+ * Loop a packet back to the sender.
+ */
+
+static void ip_loopback(struct device *old_dev, struct sk_buff *skb)
+{
+ struct device *dev=&loopback_dev;
+ int len=skb->len-old_dev->hard_header_len;
+ struct sk_buff *newskb=alloc_skb(len+dev->hard_header_len, GFP_ATOMIC);
+
+ if(newskb==NULL)
+ return;
+
+ newskb->link3=NULL;
+ newskb->sk=NULL;
+ newskb->dev=dev;
+ newskb->saddr=skb->saddr;
+ newskb->daddr=skb->daddr;
+ newskb->raddr=skb->raddr;
+ newskb->free=1;
+ newskb->lock=0;
+ newskb->users=0;
+ newskb->pkt_type=skb->pkt_type;
+ newskb->len=len+dev->hard_header_len;
+
+
+ newskb->ip_hdr=(struct iphdr *)(newskb->data+ip_send(newskb, skb->ip_hdr->daddr, len, dev, skb->ip_hdr->saddr));
+ memcpy(newskb->ip_hdr,skb->ip_hdr,len);
+
+ /* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */
+
+ /*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/
+ ip_queue_xmit(NULL, dev, newskb, 1);
+}
+
/*
* Queues a packet to be sent, and starts the transmitter
/*
* If the indicated interface is up and running, send the packet.
*/
+
ip_statistics.IpOutRequests++;
#ifdef CONFIG_IP_ACCT
ip_acct_cnt(iph,ip_acct_chain,1);
#endif
+
+#ifdef CONFIG_IP_MULTICAST
+ /*
+ * Multicasts are looped back for other local users
+ */
+
+ if (MULTICAST(skb->daddr) && !(dev->flags&IFF_LOOPBACK))
+ {
+ if(sk==NULL || sk->ip_mc_loop)
+ {
+ struct ip_mc_list *imc=dev->ip_mc_list;
+ while(imc!=NULL)
+ {
+ if(imc->multiaddr==skb->daddr)
+ {
+ ip_loopback(dev,skb);
+ break;
+ }
+ imc=imc->next;
+ }
+ }
+
+ /* Multicasts with ttl 0 must not go beyond the host */
+
+ if(skb->ip_hdr->ttl==0)
+ {
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ }
+#endif
+ if((dev->flags&IFF_BROADCAST) && iph->daddr==dev->pa_brdaddr && !(dev->flags&IFF_LOOPBACK))
+ ip_loopback(dev,skb);
+
if (dev->flags & IFF_UP)
{
/*
restore_flags(flags);
}
-#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
-
-#ifdef CONFIG_IP_FIREWALL
-
static int add_to_chain(struct ip_fw **chainptr, struct ip_fw *frwl)
{
struct ip_fw *ftmp;
return(EINVAL);
}
-#endif /* CONFIG_IP_FIREWALL */
+#endif /* CONFIG_IP_ACCT || CONFIG_IP_FIREWALL */
struct ip_fw *check_ipfw_struct(struct ip_fw *frwl, int len)
{
return p;
p=p->next;
}
- while(p!=skb_peek(&s->receive_queue));
+ while(p!=(struct sk_buff *)&s->receive_queue);
return NULL;
}
* This routine builds a generic TCP header.
*/
-extern __inline int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
+int tcp_build_header(struct tcphdr *th, struct sock *sk, int push)
{
/* FIXME: want to get rid of this. */
if (th->rst)
{
- if(sk->state!=TCP_TIME_WAIT) /* RFC 1337 recommendation re RST in time wait */
+ tcp_statistics.TcpEstabResets++;
+ sk->zapped=1;
+ /* This means the thing should really be closed. */
+ sk->err = ECONNRESET;
+ if (sk->state == TCP_CLOSE_WAIT)
{
- tcp_statistics.TcpEstabResets++;
- sk->zapped=1;
- /* This means the thing should really be closed. */
- sk->err = ECONNRESET;
- if (sk->state == TCP_CLOSE_WAIT)
- {
- sk->err = EPIPE;
- }
- tcp_set_state(sk,TCP_CLOSE);
- sk->shutdown = SHUTDOWN_MASK;
- if (!sk->dead)
- {
- sk->state_change(sk);
- }
+ sk->err = EPIPE;
+ }
+ tcp_set_state(sk,TCP_CLOSE);
+ sk->shutdown = SHUTDOWN_MASK;
+ if (!sk->dead)
+ {
+ sk->state_change(sk);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
#include <linux/config.h>
#include <linux/utsname.h>
-
-#include "./version.h"
+#include <linux/version.h>
struct new_utsname system_utsname = {
UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION,