More networking updates.. Ross Biro is still struggling with net-1.
Michael Johnson (now RH kernel release manager) works on line printer
driver.
Locking function cleanups (for inodes, superblocks, buffer heads). We
also now pass in the superblock pointer instead of the device number to
the filesystem routines. That cleans up use and locking of
"get_super()" a lot.
[Original announcement below]
Ok, I already sent out an announcement last night, but due to the time
(6AM over here) I wasn't really in a mood to write a real annoucement.
Here it is.
linux-0.98.3 is available by anonymous ftp at least on nic.funet.fi:
pub/OS/Linux/testing/Linus, both as context diffs against 0.98.2 and the
pre-version of 0.98.3 and as complete source. The complete source
package was done by directly applying the diffs - this means that the
Makefile dependancies are probably not 100% up-to-date as I remove those
from the diffs. It shouldn't be any problem, and you can always do a
"make dep ; make clean" before actually compiling the kernel.
0.98 pl3 fixes several bugs, and should remove all known NULL-pointer
problems that made 0.98.2 unusable for most people. In addition to the
NULL pointer fixes, the following things have changed:
- removed most of the cli-sti pairs in the filesystem code by rewriting
the locking routines to use a different algorithm, possible due to
the rewritten wait-queue code that I did back in 0.96c or so.
Interrupt latency should be better on slow machines, but I don't know
if it's noticeable.
- Minor 387-emulation fixes by Bill Metzenthen - only noticeable under
special conditions.
- Corrected various error-returns in the fs (thanks to Bruce Evans for
running some error diagnostics). Error messages when opening (and
renaming etc) files that had a non-directory in the path were wrong,
and should be ok now (ie giving ENOTDIR instead of EACCESS or ENOENT).
Some other problems reported by Bruce fixed.
- Changed the interface for some fs-related functions due to cleaning
up super-block handling. Most noticeably, iget() and related
functions no longer specify the inode with a device and inode number,
but instead with a super-block pointer and inode number. This is
more logical, and should make unnamed devices (ie internal
filesystems like nfs and /proc) cleaner. Also note that the calling
sequence for sb->s_op->put_inode() also has changed since 0.98. This
is of interest only if you are writing filesystem drivers..
- ASK_SVGA was broken in 0.98.2 - it should be ok now.
Also, various minor fixes as usual. No new features, but I hope 0.98.3
will be a lot less bug-prone due to the changes since 0.98.1. Some
minor tcp/ip corrections (but most of them were in the pre-release), and
I removed a race-condition in the tty-handling code.
Note that people who use math without a co-processor should certainly
upgrade to 0.98.3: the new emulator is much better than my original one
both in speed and accuracy/exception handling. x11perf is very much
bearable now even without a 387, and things like ray-tracing etc
shouldn't be a problem any more. It's slower than hardware fp, of
course, but at least it works.
The new emulator also means there is no reason for a separate soft-float
library, so I'd assume that will be gone in the next gcc release for
linux.
As usual, a new kernel version probably means you'll have to recompile
'ps' and friends. But at least the same 'ps' sources that worked for
0.97.6 should still work.
Linus
# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F
# KEYBOARD = -DKBD_SF -DKBDFLAGS=0
# KEYBOARD = -DKBD_SF_LATIN1 -DKBDFLAGS=0x9F
-# KEYBOARD = -DKDB_NO
+# KEYBOARD = -DKBD_NO -DKBDFLAGS=0
#
# comment this line if you don't want the emulation-code
Version:
@./makever.sh
- @echo \#define UTS_RELEASE \"0.98.pl2-`cat .version`\" > tools/version.h
+ @echo \#define UTS_RELEASE \"0.98.pl3-`cat .version`\" > tools/version.h
@echo \#define UTS_VERSION \"`date +%D`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
$(AS86) -o boot/setup.o boot/setup.s
$(LD86) -s -o boot/setup boot/setup.o
-boot/setup.s: boot/setup.S include/linux/config.h
+boot/setup.s: boot/setup.S include/linux/config.h Makefile
$(CPP) -traditional $(SVGA_MODE) boot/setup.S -o boot/setup.s
-boot/bootsect.s: boot/bootsect.S include/linux/config.h
+boot/bootsect.s: boot/bootsect.S include/linux/config.h
$(CPP) -traditional boot/bootsect.S -o boot/bootsect.s
boot/bootsect: boot/bootsect.s
* the page directory.
*/
.text
-.globl _idt,_gdt,_swapper_pg_dir,_tmp_floppy_area,_floppy_track_buffer
+.globl _idt,_gdt,
+.globl _swapper_pg_dir,_pg0
.globl _empty_bad_page
.globl _empty_bad_page_table
+.globl _tmp_floppy_area,_floppy_track_buffer
/*
* swapper_pg_dir is the main page directory, address 0x00001000
* tables are set up later depending on memory size.
*/
.org 0x2000
-pg0:
+_pg0:
.org 0x3000
_empty_bad_page:
movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
cld;rep;stosl
/* Identity-map the kernel in low 4MB memory for ease of transition */
- movl $pg0+7,_swapper_pg_dir /* set present bit/user r/w */
+ movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
/* But the real place is at 0xC0000000 */
- movl $pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
- movl $pg0+4092,%edi
+ movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
+ movl $_pg0+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill the page backwards - more efficient :-) */
!
-! setup.s Copyright (C) 1991, 1992 Linus Torvalds
+! setup.S Copyright (C) 1991, 1992 Linus Torvalds
!
! setup.s is responsible for getting the system data from the BIOS,
! and putting them into the appropriate places in system memory.
! NOTE! These had better be the same as in bootsect.s!
#include <linux/config.h>
-#define NORMAL_VGA 0xffff
+
+#ifndef SVGA_MODE
+#define SVGA_MODE ASK_VGA
+#endif
INITSEG = DEF_INITSEG ! we move boot here - out of the way
SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536).
pop ds
mov ax,#0xc000
mov es,ax
+ mov ax,modesave
+ cmp ax,#NORMAL_VGA
+ je defvga
+ cmp ax,#EXTENDED_VGA
+ je extvga
+ cmp ax,#ASK_VGA
+ jne svga
lea si,msg1
-#ifndef SVGA_MODE
call prtstr
flush: in al,#0x60 ! Flush the keyboard buffer
cmp al,#0x82
je svga ! yes - svga selection
cmp al,#0xb9 ! space ?
jne nokey ! no - repeat
-#endif
-#if !defined(SVGA_MODE) || SVGA_MODE == NORMAL_VGA
- mov ax,#0x5019
+defvga: mov ax,#0x5019
pop ds
ret
-#endif
+/* extended vga mode: 80x50 */
+extvga:
+ mov ax,#0x1112
+ mov bl,#0
+ int 0x10 ! use 8x8 font set (50 lines on VGA)
+ mov ax,#0x1200
+ mov bl,#0x20
+ int 0x10 ! use alternate print screen
+ mov ax,#0x1201
+ mov bl,#0x34
+ int 0x10 ! turn off cursor emulation
+ mov ah,#0x01
+ mov cx,#0x0607
+ int 0x10 ! turn on cursor (scan lines 6 to 7)
+ pop ds
+ mov ax,#0x5032 ! return 80x50
+ ret
+/* svga modes */
svga: cld
lea si,idati ! Check ATI 'clues'
mov di,#0x31
call prtstr
pop si
add cl,#0x80
-#if defined(SVGA_MODE) && SVGA_MODE != NORMAL_VGA
- mov al,#SVGA_MODE ! Preset SVGA mode
-#else
+ mov ax,modesave
+ cmp ax,#ASK_VGA
+ je nonum
+ cmp ax,#NORMAL_VGA
+ jne gotmode
nonum: call getkey
cmp al,#0x82
jb nonum
zero: sub al,#0x0a
nozero: sub al,#0x80
dec al
-#endif
- xor ah,ah
+gotmode: xor ah,ah
add di,ax
inc di
push ax
pop ds
ret
novid7:
- mov ax,#0x1112
- mov bl,#0
- int 0x10 ! use 8x8 font set (50 lines on VGA)
-
- mov ax,#0x1200
- mov bl,#0x20
- int 0x10 ! use alternate print screen
-
- mov ax,#0x1201
- mov bl,#0x34
- int 0x10 ! turn off cursor emulation
-
- mov ah,#0x01
- mov cx,#0x0607
- int 0x10 ! turn on cursor (scan lines 6 to 7)
-
- pop ds
- mov ax,#0x5032 ! return 80x50
- ret
+ br extvga
! Routine that 'tabs' to next col.
dsctseng: .word 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
dscvideo7: .word 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
dscoakvga: .word 0x2819, 0x5019, 0x843c, 0x8419, 0x842C
+modesave: .word SVGA_MODE
.text
endtext:
/*
* 'buffer.c' implements the buffer-cache functions. Race-conditions have
* been avoided by NEVER letting a interrupt change a buffer (except for the
- * data, of course), but instead letting the caller do it. NOTE! As interrupts
- * can wake up a caller, some cli-sti sequences are needed to check for
- * sleep-on-calls. These should be extremely quick, though (I hope).
+ * data, of course), but instead letting the caller do it.
*/
/*
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/io.h>
int nr_buffers = 0;
int nr_buffer_heads = 0;
-static inline void wait_on_buffer(struct buffer_head * bh)
+/*
+ * Rewrote the wait-routines to use the "new" wait-queue functionality,
+ * and getting rid of the cli-sti pairs. The wait-queue routines still
+ * need cli-sti, but now it's just a couple of 386 instructions or so.
+ *
+ * Note that the real wait_on_buffer() is an inline function that checks
+ * if 'b_wait' is set before calling this, so that the queues aren't set
+ * up unnecessarily.
+ */
+void __wait_on_buffer(struct buffer_head * bh)
{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
+ add_wait_queue(&bh->b_wait,¤t->wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (bh->b_lock) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&bh->b_wait,¤t->wait);
+ current->state = TASK_RUNNING;
}
-static void sync_buffers(int dev)
+static void sync_buffers(dev_t dev)
{
int i;
struct buffer_head * bh;
}
}
-int sys_sync(void)
+void sync_dev(dev_t dev)
{
- int i;
-
- for (i=0 ; i<NR_SUPER ; i++)
- if (super_block[i].s_dev
- && super_block[i].s_op
- && super_block[i].s_op->write_super
- && super_block[i].s_dirt)
- super_block[i].s_op->write_super(&super_block[i]);
- sync_inodes(); /* write out inodes into buffers */
- sync_buffers(0);
- return 0;
+ sync_buffers(dev);
+ sync_supers(dev);
+ sync_inodes(dev);
+ sync_buffers(dev);
}
-int sync_dev(int dev)
+int sys_sync(void)
{
- struct super_block * sb;
-
- if (sb = get_super (dev))
- if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
- sb->s_op->write_super (sb);
- sync_buffers(dev);
- sync_inodes();
- sync_buffers(dev);
+ sync_dev(0);
return 0;
}
-void invalidate_buffers(int dev)
+void invalidate_buffers(dev_t dev)
{
int i;
struct buffer_head * bh;
* and that mount/open needn't know that floppies/whatever are
* special.
*/
-void check_disk_change(int dev)
+void check_disk_change(dev_t dev)
{
int i;
struct buffer_head * bh;
bh->b_next->b_prev = bh;
}
-static struct buffer_head * find_buffer(int dev, int block, int size)
+static struct buffer_head * find_buffer(dev_t dev, int block, int size)
{
struct buffer_head * tmp;
* will force it bad). This shouldn't really happen currently, but
* the code is ready.
*/
-struct buffer_head * get_hash_table(int dev, int block, int size)
+struct buffer_head * get_hash_table(dev_t dev, int block, int size)
{
struct buffer_head * bh;
* when the filesystem starts to get full of dirty blocks (I hope).
*/
#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock)
-struct buffer_head * getblk(int dev, int block, int size)
+struct buffer_head * getblk(dev_t dev, int block, int size)
{
struct buffer_head * bh, * tmp;
int buffers;
* bread() reads a specified block and returns the buffer that contains
* it. It returns NULL if the block was unreadable.
*/
-struct buffer_head * bread(int dev, int block, int size)
+struct buffer_head * bread(dev_t dev, int block, int size)
{
struct buffer_head * bh;
* all at the same time, not waiting for one to be read, and then another
* etc.
*/
-void bread_page(unsigned long address,int dev,int b[4])
+void bread_page(unsigned long address, dev_t dev, int b[4])
{
struct buffer_head * bh[4];
int i;
* blocks for reading as well. End the argument list with a negative
* number.
*/
-struct buffer_head * breada(int dev,int first, ...)
+struct buffer_head * breada(dev_t dev,int first, ...)
{
va_list args;
struct buffer_head * bh, *tmp;
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#define NBUF 16
#include <linux/fs.h>
#include <linux/ext_fs.h>
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
static int ext_file_read(struct inode *, struct file *, char *, int);
static int ext_file_write(struct inode *, struct file *, char *, int);
#include <linux/ext_fs.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <linux/locks.h>
#define clear_block(addr) \
__asm__("cld\n\t" \
"stosl" \
::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
-void ext_free_block(int dev, int block)
+void ext_free_block(struct super_block * sb, int block)
{
- struct super_block * sb;
struct buffer_head * bh;
struct ext_free_block * efb;
- if (!(sb = get_super(dev)))
+ if (!sb)
panic("trying to free block on nonexistent device");
lock_super (sb);
if (block < sb->u.ext_sb.s_firstdatazone ||
printk("trying to free block not in datazone\n");
return;
}
- bh = get_hash_table(dev, block, sb->s_blocksize);
+ bh = get_hash_table(sb->s_dev, block, sb->s_blocksize);
if (bh)
bh->b_dirt=0;
brelse(bh);
#endif
if (sb->u.ext_sb.s_firstfreeblock)
brelse (sb->u.ext_sb.s_firstfreeblock);
- if (!(sb->u.ext_sb.s_firstfreeblock = bread (dev,
+ if (!(sb->u.ext_sb.s_firstfreeblock = bread (sb->s_dev,
block, sb->s_blocksize)))
panic ("ext_free_block: unable to read block to free\n");
efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data;
sb->u.ext_sb.s_freeblockscount ++;
sb->s_dirt = 1;
sb->u.ext_sb.s_firstfreeblock->b_dirt = 1;
- free_super (sb);
+ unlock_super (sb);
return;
}
-int ext_new_block(int dev)
+int ext_new_block(struct super_block * sb)
{
struct buffer_head * bh;
- struct super_block * sb;
struct ext_free_block * efb;
int j;
- if (!(sb = get_super(dev)))
+ if (!sb)
panic("trying to get new block from nonexistant device");
if (!sb->u.ext_sb.s_firstfreeblock)
return 0;
if (!sb->u.ext_sb.s_firstfreeblocknumber) {
sb->u.ext_sb.s_firstfreeblock = NULL;
} else {
- if (!(sb->u.ext_sb.s_firstfreeblock = bread (dev,
+ if (!(sb->u.ext_sb.s_firstfreeblock = bread (sb->s_dev,
sb->u.ext_sb.s_firstfreeblocknumber,
sb->s_blocksize)))
panic ("ext_new_block: unable to read next free block\n");
sb->u.ext_sb.s_freeblockscount --;
sb->s_dirt = 1;
- if (!(bh=getblk(dev, j, sb->s_blocksize)))
+ if (!(bh=getblk(sb->s_dev, j, sb->s_blocksize)))
panic("new_block: cannot get block");
if (bh->b_count != 1)
panic("new block: count is != 1");
#ifdef EXTFS_DEBUG
printk("ext_new_block: allocating block %d\n", j);
#endif
- free_super (sb);
+ unlock_super (sb);
return j;
}
}
printk("ext_count_free_blocks: stored = %d, computed = %d\n",
sb->u.ext_sb.s_freeblockscount, count);
- free_super (sb);
+ unlock_super (sb);
return count;
#else
return sb->u.ext_sb.s_freeblockscount;
lock_super (inode->i_sb);
if (inode->i_ino < 1 || inode->i_ino > inode->i_sb->u.ext_sb.s_ninodes) {
printk("free_inode: inode 0 or nonexistent inode\n");
- free_super (inode->i_sb);
+ unlock_super (inode->i_sb);
return;
}
if (inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
inode->i_sb->u.ext_sb.s_freeinodescount ++;
inode->i_sb->s_dirt = 1;
inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
- free_super (inode->i_sb);
+ unlock_super (inode->i_sb);
memset(inode,0,sizeof(*inode));
}
-struct inode * ext_new_inode(int dev)
+struct inode * ext_new_inode(struct super_block * sb)
{
struct inode * inode;
struct ext_free_inode * efi;
unsigned long block;
int j;
- if (!(inode=get_empty_inode()))
+ if (!sb || !(inode=get_empty_inode()))
return NULL;
- if (!(inode->i_sb = get_super(dev))) {
- printk("new_inode: unknown device\n");
- iput(inode);
- return NULL;
- }
- inode->i_flags = inode->i_sb->s_flags;
- if (!inode->i_sb->u.ext_sb.s_firstfreeinodeblock)
+ inode->i_sb = sb;
+ inode->i_flags = sb->s_flags;
+ if (!sb->u.ext_sb.s_firstfreeinodeblock)
return 0;
- lock_super (inode->i_sb);
- efi = ((struct ext_free_inode *) inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
- (inode->i_sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
+ lock_super (sb);
+ efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) +
+ (sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK;
if (efi->count) {
j = efi->free[--efi->count];
- inode->i_sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
+ sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1;
} else {
#ifdef EXTFS_DEBUG
printk("ext_free_inode: inode empty, skipping to %d\n", efi->next);
#endif
- j = inode->i_sb->u.ext_sb.s_firstfreeinodenumber;
- if (efi->next > inode->i_sb->u.ext_sb.s_ninodes) {
+ j = sb->u.ext_sb.s_firstfreeinodenumber;
+ if (efi->next > sb->u.ext_sb.s_ninodes) {
printk ("efi->next = %d\n", efi->next);
panic ("ext_new_inode: bad inode number in free list\n");
}
- inode->i_sb->u.ext_sb.s_firstfreeinodenumber = efi->next;
+ sb->u.ext_sb.s_firstfreeinodenumber = efi->next;
block = 2 + (((unsigned long) efi->next) - 1) / EXT_INODES_PER_BLOCK;
- brelse (inode->i_sb->u.ext_sb.s_firstfreeinodeblock);
- if (!inode->i_sb->u.ext_sb.s_firstfreeinodenumber) {
- inode->i_sb->u.ext_sb.s_firstfreeinodeblock = NULL;
+ brelse (sb->u.ext_sb.s_firstfreeinodeblock);
+ if (!sb->u.ext_sb.s_firstfreeinodenumber) {
+ sb->u.ext_sb.s_firstfreeinodeblock = NULL;
} else {
- if (!(inode->i_sb->u.ext_sb.s_firstfreeinodeblock = bread (dev, block, inode->i_sb->s_blocksize)))
+ if (!(sb->u.ext_sb.s_firstfreeinodeblock =
+ bread(sb->s_dev, block, sb->s_blocksize)))
panic ("ext_new_inode: unable to read next free inode block\n");
}
}
- inode->i_sb->u.ext_sb.s_freeinodescount --;
- inode->i_sb->s_dirt = 1;
+ sb->u.ext_sb.s_freeinodescount --;
+ sb->s_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
- inode->i_dev = dev;
+ inode->i_dev = sb->s_dev;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_dirt = 1;
#ifdef EXTFS_DEBUG
printk("ext_new_inode : allocating inode %d\n", inode->i_ino);
#endif
- free_super (inode->i_sb);
+ unlock_super (sb);
return inode;
}
}
printk("ext_count_free_inodes: stored = %d, computed = %d\n",
sb->u.ext_sb.s_freeinodescount, count);
- free_super (sb);
+ unlock_super (sb);
return count;
#else
return sb->u.ext_sb.s_freeinodescount;
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
-int sync_dev(int dev);
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
void ext_put_inode(struct inode *inode)
{
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
ext_truncate(inode);
ext_free_inode(inode);
brelse (sb->u.ext_sb.s_firstfreeinodeblock);
if (sb->u.ext_sb.s_firstfreeblock)
brelse (sb->u.ext_sb.s_firstfreeblock);
- free_super(sb);
+ unlock_super(sb);
return;
}
lock_super(s);
if (!(bh = bread(dev, 1, BLOCK_SIZE))) {
s->s_dev=0;
- free_super(s);
+ unlock_super(s);
printk("bread failed\n");
return NULL;
}
brelse(bh);
if (s->s_magic != EXT_SUPER_MAGIC) {
s->s_dev = 0;
- free_super(s);
+ unlock_super(s);
printk("magic match failed\n");
return NULL;
}
s->u.ext_sb.s_firstfreeblocknumber, BLOCK_SIZE))) {
printk ("ext_read_super: unable to read first free block\n");
s->s_dev = 0;
- free_super(s);
+ unlock_super(s);
return NULL;
}
if (!s->u.ext_sb.s_firstfreeinodenumber)
printk ("ext_read_super: unable to read first free inode block\n");
brelse(s->u.ext_sb.s_firstfreeblock);
s->s_dev = 0;
- free_super (s);
+ unlock_super (s);
return NULL;
}
}
- free_super(s);
+ unlock_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &ext_sops;
- if (!(s->s_mounted = iget(dev,EXT_ROOT_INO))) {
+ if (!(s->s_mounted = iget(s,EXT_ROOT_INO))) {
s->s_dev=0;
printk("get root inode failed\n");
return NULL;
}
if (!create)
return NULL;
- tmp = ext_new_block(inode->i_dev);
+ tmp = ext_new_block(inode->i_sb);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
return result;
}
-static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int create)
+static struct buffer_head * block_getblk(struct inode * inode,
+ struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned long * p;
brelse(bh);
return NULL;
}
- tmp = ext_new_block(bh->b_dev);
+ tmp = ext_new_block(inode->i_sb);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
- ext_free_block(bh->b_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
block -= 9;
if (block<256) {
bh = inode_getblk(inode,9,create);
- return block_getblk(bh,block,create);
+ return block_getblk(inode,bh,block,create);
}
block -= 256;
if (block<256*256) {
bh = inode_getblk(inode,10,create);
- bh = block_getblk(bh,block>>8,create);
- return block_getblk(bh,block & 255,create);
+ bh = block_getblk(inode,bh,block>>8,create);
+ return block_getblk(inode,bh,block & 255,create);
}
block -= 256*256;
bh = inode_getblk(inode,11,create);
- bh = block_getblk(bh,block>>16,create);
- bh = block_getblk(bh,(block>>8) & 255,create);
- return block_getblk(bh,block & 255,create);
+ bh = block_getblk(inode,bh,block>>16,create);
+ bh = block_getblk(inode,bh,(block>>8) & 255,create);
+ return block_getblk(inode,bh,block & 255,create);
}
struct buffer_head * ext_bread(struct inode * inode, int block, int create)
}
ino = de->inode;
brelse(bh);
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
*result = NULL;
if (!dir)
return -ENOENT;
- inode = ext_new_inode(dir->i_dev);
+ inode = ext_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
iput(dir);
return -EEXIST;
}
- inode = ext_new_inode(dir->i_dev);
+ inode = ext_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
iput(dir);
return -EEXIST;
}
- inode = ext_new_inode(dir->i_dev);
+ inode = ext_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
static inline void ext_merge_entries (struct ext_dir_entry * de,
struct ext_dir_entry * pde, struct ext_dir_entry * nde)
{
- if (! nde->inode)
+ if (nde && !nde->inode)
de->rec_len += nde->rec_len;
- if (! pde->inode)
+ if (pde && !pde->inode)
pde->rec_len += de->rec_len;
}
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid &&
inode->i_uid != current->euid)
bh = ext_find_entry(dir,name,len,&de,&pde,&nde);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_unlink;
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) && !suser() &&
int i;
char c;
- if (!(inode = ext_new_inode(dir->i_dev))) {
+ if (!(inode = ext_new_inode(dir->i_sb))) {
iput(dir);
return -ENOSPC;
}
iput(dir);
return -EPERM;
}
+ if (oldinode->i_nlink > 32000) {
+ iput(oldinode);
+ iput(dir);
+ return -EMLINK;
+ }
bh = ext_find_entry(dir,name,len,&de,NULL,NULL);
if (bh) {
brelse(bh);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = iget(old_dir->i_dev, old_de->inode);
+ old_inode = iget(old_dir->i_sb, old_de->inode);
if (!old_inode)
goto end_rename;
retval = -EPERM;
goto end_rename;
new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL);
if (new_bh) {
- new_inode = iget(new_dir->i_dev, new_de->inode);
+ new_inode = iget(new_dir->i_sb, new_de->inode);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
*p = 0;
inode->i_dirt = 1;
brelse(bh);
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
return retry;
}
*ind = 0;
ind_bh->b_dirt = 1;
brelse(bh);
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
ind = (unsigned long *) ind_bh->b_data;
for (i = 0; i < 256; i++)
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
brelse(ind_bh);
return retry;
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
return retry;
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- ext_free_block(inode->i_dev,tmp);
+ ext_free_block(inode->i_sb,tmp);
}
brelse(tind_bh);
return retry;
#include <asm/system.h>
-struct inode inode_table[NR_INODE]={{0,},};
+static struct inode inode_table[NR_INODE];
+
+void inode_init(void)
+{
+ memset(inode_table,0,sizeof(inode_table));
+}
+
+int fs_may_mount(dev_t dev)
+{
+ struct inode * inode;
+
+ for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
+ if (inode->i_dev != dev)
+ continue;
+ if (inode->i_count || inode->i_dirt || inode->i_lock)
+ return 0;
+ inode->i_dev = 0;
+ }
+ return 1;
+}
+
+int fs_may_umount(dev_t dev, struct inode * mount_root)
+{
+ struct inode * inode;
+
+ for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
+ if (inode->i_dev==dev && inode->i_count)
+ if (inode == mount_root && inode->i_count == 1)
+ continue;
+ else
+ return 0;
+ return 1;
+}
+
+/*
+ * The "new" scheduling primitives (new as of 0.97 or so) allow this to
+ * be done without disabling interrupts (other than in the actual queue
+ * updating things: only a couple of 386 instructions). This should be
+ * much better for interrupt latency.
+ */
+static void __wait_on_inode(struct inode * inode)
+{
+ add_wait_queue(&inode->i_wait,¤t->wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (inode->i_lock) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&inode->i_wait,¤t->wait);
+ current->state = TASK_RUNNING;
+}
static inline void wait_on_inode(struct inode * inode)
{
- cli();
- while (inode->i_lock)
- sleep_on(&inode->i_wait);
- sti();
+ if (inode->i_lock)
+ __wait_on_inode(inode);
}
static inline void lock_inode(struct inode * inode)
{
- cli();
- while (inode->i_lock)
- sleep_on(&inode->i_wait);
- inode->i_lock=1;
- sti();
+ wait_on_inode(inode);
+ inode->i_lock = 1;
}
static inline void unlock_inode(struct inode * inode)
{
- inode->i_lock=0;
+ inode->i_lock = 0;
wake_up(&inode->i_wait);
}
{
if (!inode->i_dirt)
return;
- inode->i_dirt = 0;
lock_inode(inode);
+ inode->i_dirt = 0;
if (inode->i_dev && inode->i_sb &&
inode->i_sb->s_op && inode->i_sb->s_op->write_inode)
inode->i_sb->s_op->write_inode(inode);
return 0;
}
-void invalidate_inodes(int dev)
+void invalidate_inodes(dev_t dev)
{
int i;
struct inode * inode;
}
}
-void sync_inodes(void)
+void sync_inodes(dev_t dev)
{
int i;
struct inode * inode;
inode->i_count--;
return;
}
- if (!inode->i_nlink) {
- if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
- inode->i_sb->s_op->put_inode(inode);
+ if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) {
+ inode->i_sb->s_op->put_inode(inode);
+ if (!inode->i_nlink)
return;
- }
}
if (inode->i_dirt) {
write_inode(inode); /* we can sleep - so do again */
return inode;
}
-struct inode * iget(int dev,int nr)
+struct inode * iget(struct super_block * sb,int nr)
{
struct inode * inode, * empty;
- if (!dev)
- panic("iget with dev==0");
+ if (!sb)
+ panic("iget with sb==NULL");
empty = get_empty_inode();
inode = inode_table;
while (inode < NR_INODE+inode_table) {
- if (inode->i_dev != dev || inode->i_ino != nr) {
+ if (inode->i_sb != sb || inode->i_ino != nr) {
inode++;
continue;
}
wait_on_inode(inode);
- if (inode->i_dev != dev || inode->i_ino != nr) {
+ if (inode->i_sb != sb || inode->i_ino != nr) {
inode = inode_table;
continue;
}
if (!empty)
return (NULL);
inode = empty;
- if (!(inode->i_sb = get_super(dev))) {
- printk("iget: gouldn't get super-block\n\t");
- iput(inode);
- return NULL;
- }
- inode->i_dev = dev;
+ inode->i_sb = sb;
+ inode->i_dev = sb->s_dev;
inode->i_ino = nr;
- inode->i_flags = inode->i_sb->s_flags;
+ inode->i_flags = sb->s_flags;
read_inode(inode);
return inode;
}
return(sum);
}
-void minix_free_block(int dev, int block)
+void minix_free_block(struct super_block * sb, int block)
{
- struct super_block * sb;
struct buffer_head * bh;
unsigned int bit,zone;
- if (!(sb = get_super(dev))) {
+ if (!sb) {
printk("trying to free block on nonexistent device\n");
return;
}
printk("trying to free block not in datazone\n");
return;
}
- bh = get_hash_table(dev,block,BLOCK_SIZE);
+ bh = get_hash_table(sb->s_dev,block,BLOCK_SIZE);
if (bh)
bh->b_dirt=0;
brelse(bh);
return;
}
if (clear_bit(bit,bh->b_data))
- printk("free_block (%04x:%d): bit already cleared\n",dev,block);
+ printk("free_block (%04x:%d): bit already cleared\n",sb->s_dev,block);
bh->b_dirt = 1;
return;
}
-int minix_new_block(int dev)
+int minix_new_block(struct super_block * sb)
{
struct buffer_head * bh;
- struct super_block * sb;
int i,j;
- if (!(sb = get_super(dev))) {
+ if (!sb) {
printk("trying to get new block from nonexistant device\n");
return 0;
}
j += i*8192 + sb->u.minix_sb.s_firstdatazone-1;
if (j >= sb->u.minix_sb.s_nzones)
return 0;
- if (!(bh=getblk(dev,j,BLOCK_SIZE))) {
+ if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) {
printk("new_block: cannot get block");
return 0;
}
memset(inode,0,sizeof(*inode));
}
-struct inode * minix_new_inode(int dev)
+struct inode * minix_new_inode(struct super_block * sb)
{
struct inode * inode;
struct buffer_head * bh;
int i,j;
- if (!(inode=get_empty_inode()))
+ if (!sb || !(inode = get_empty_inode()))
return NULL;
- if (!(inode->i_sb = get_super(dev))) {
- printk("new_inode: unknown device\n");
- iput(inode);
- return NULL;
- }
+ inode->i_sb = sb;
inode->i_flags = inode->i_sb->s_flags;
j = 8192;
for (i=0 ; i<8 ; i++)
bh->b_dirt = 1;
inode->i_count = 1;
inode->i_nlink = 1;
- inode->i_dev = dev;
+ inode->i_dev = sb->s_dev;
inode->i_uid = current->euid;
inode->i_gid = current->egid;
inode->i_dirt = 1;
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#define NBUF 16
#include <linux/fs.h>
#include <linux/minix_fs.h>
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
static int minix_file_read(struct inode *, struct file *, char *, int);
static int minix_file_write(struct inode *, struct file *, char *, int);
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
-int sync_dev(int dev);
-
-static inline void wait_on_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- sti();
-}
-
void minix_put_inode(struct inode *inode)
{
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
minix_truncate(inode);
minix_free_inode(inode);
brelse(sb->u.minix_sb.s_imap[i]);
for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++)
brelse(sb->u.minix_sb.s_zmap[i]);
- free_super(sb);
+ unlock_super(sb);
return;
}
lock_super(s);
if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev=0;
- free_super(s);
+ unlock_super(s);
printk("bread failed\n");
return NULL;
}
brelse(bh);
if (s->s_magic != MINIX_SUPER_MAGIC) {
s->s_dev = 0;
- free_super(s);
+ unlock_super(s);
printk("magic match failed\n");
return NULL;
}
for(i=0;i<MINIX_Z_MAP_SLOTS;i++)
brelse(s->u.minix_sb.s_zmap[i]);
s->s_dev=0;
- free_super(s);
+ unlock_super(s);
printk("block failed\n");
return NULL;
}
s->u.minix_sb.s_imap[0]->b_data[0] |= 1;
s->u.minix_sb.s_zmap[0]->b_data[0] |= 1;
- free_super(s);
/* set up enough so that it can read an inode */
s->s_dev = dev;
s->s_op = &minix_sops;
- if (!(s->s_mounted = iget(dev,MINIX_ROOT_INO))) {
- s->s_dev=0;
+ s->s_mounted = iget(s,MINIX_ROOT_INO);
+ unlock_super(s);
+ if (!s->s_mounted) {
+ s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
return s;
}
-void minix_statfs (struct super_block *sb, struct statfs *buf)
+void minix_statfs(struct super_block *sb, struct statfs *buf)
{
long tmp;
}
if (!create)
return NULL;
- tmp = minix_new_block(inode->i_dev);
+ tmp = minix_new_block(inode->i_sb);
if (!tmp)
return NULL;
result = getblk(inode->i_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
return result;
}
-static struct buffer_head * block_getblk(struct buffer_head * bh, int nr, int create)
+static struct buffer_head * block_getblk(struct inode * inode,
+ struct buffer_head * bh, int nr, int create)
{
int tmp;
unsigned short *p;
brelse(bh);
return NULL;
}
- tmp = minix_new_block(bh->b_dev);
+ tmp = minix_new_block(inode->i_sb);
if (!tmp) {
brelse(bh);
return NULL;
}
result = getblk(bh->b_dev, tmp, BLOCK_SIZE);
if (*p) {
- minix_free_block(bh->b_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
brelse(result);
goto repeat;
}
block -= 7;
if (block < 512) {
bh = inode_getblk(inode,7,create);
- return block_getblk(bh,block,create);
+ return block_getblk(inode, bh, block, create);
}
block -= 512;
bh = inode_getblk(inode,8,create);
- bh = block_getblk(bh,block>>9,create);
- return block_getblk(bh,block & 511,create);
+ bh = block_getblk(inode, bh, block>>9, create);
+ return block_getblk(inode, bh, block & 511, create);
}
struct buffer_head * minix_bread(struct inode * inode, int block, int create)
}
ino = de->inode;
brelse(bh);
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
*result = NULL;
if (!dir)
return -ENOENT;
- inode = minix_new_inode(dir->i_dev);
+ inode = minix_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
iput(dir);
return -EEXIST;
}
- inode = minix_new_inode(dir->i_dev);
+ inode = minix_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
iput(dir);
return -EEXIST;
}
- inode = minix_new_inode(dir->i_dev);
+ inode = minix_new_inode(dir->i_sb);
if (!inode) {
iput(dir);
return -ENOSPC;
if (!bh)
goto end_rmdir;
retval = -EPERM;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_rmdir;
if ((dir->i_mode & S_ISVTX) && current->euid &&
inode->i_uid != current->euid)
bh = minix_find_entry(dir,name,len,&de);
if (!bh)
goto end_unlink;
- if (!(inode = iget(dir->i_dev, de->inode)))
+ if (!(inode = iget(dir->i_sb, de->inode)))
goto end_unlink;
retval = -EPERM;
if ((dir->i_mode & S_ISVTX) && !suser() &&
int i;
char c;
- if (!(inode = minix_new_inode(dir->i_dev))) {
+ if (!(inode = minix_new_inode(dir->i_sb))) {
iput(dir);
return -ENOSPC;
}
iput(dir);
return -EPERM;
}
+ if (oldinode->i_nlink > 126) {
+ iput(oldinode);
+ iput(dir);
+ return -EMLINK;
+ }
bh = minix_find_entry(dir,name,len,&de);
if (bh) {
brelse(bh);
retval = -ENOENT;
if (!old_bh)
goto end_rename;
- old_inode = iget(old_dir->i_dev, old_de->inode);
+ old_inode = iget(old_dir->i_sb, old_de->inode);
if (!old_inode)
goto end_rename;
retval = -EPERM;
goto end_rename;
new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de);
if (new_bh) {
- new_inode = iget(new_dir->i_dev, new_de->inode);
+ new_inode = iget(new_dir->i_sb, new_de->inode);
if (!new_inode) {
brelse(new_bh);
new_bh = NULL;
*p = 0;
inode->i_dirt = 1;
brelse(bh);
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
return retry;
}
*ind = 0;
ind_bh->b_dirt = 1;
brelse(bh);
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
ind = (unsigned short *) ind_bh->b_data;
for (i = 0; i < 512; i++)
else {
tmp = *p;
*p = 0;
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
brelse(ind_bh);
return retry;
tmp = *p;
*p = 0;
inode->i_dirt = 1;
- minix_free_block(inode->i_dev,tmp);
+ minix_free_block(inode->i_sb,tmp);
}
brelse(dind_bh);
return retry;
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/segment.h>
{
struct inode *depend;
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
msdos_truncate(inode);
depend = MSDOS_I(inode)->i_depend;
cache_inval_dev(sb->s_dev);
lock_super(sb);
sb->s_dev = 0;
- free_super(sb);
+ unlock_super(sb);
return;
}
};
-static unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
-{
- unsigned long result = 0,value;
-
- if (!base) {
- base = 10;
- if (*cp == '0') {
- base = 8;
- cp++;
- if ((*cp == 'x') && isxdigit(cp[1])) {
- cp++;
- base = 16;
- }
- }
- }
- while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
- ? toupper(*cp) : *cp)-'A'+10) < base) {
- result = result*base + value;
- cp++;
- }
- if (endp)
- *endp = (char *)cp;
- return result;
-}
-
-
static int parse_options(char *options,char *check,char *conversion,uid_t *uid, gid_t *gid, int *umask)
{
char *this,*value;
cache_init();
lock_super(s);
bh = bread(s->s_dev, 0, BLOCK_SIZE);
- free_super(s);
+ unlock_super(s);
if (bh == NULL) {
s->s_dev = 0;
printk("MSDOS bread failed\n");
MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
MSDOS_SB(s)->fat_wait = NULL;
MSDOS_SB(s)->fat_lock = 0;
- if (!(s->s_mounted = iget(s->s_dev,MSDOS_ROOT_INO))) {
+ if (!(s->s_mounted = iget(s,MSDOS_ROOT_INO))) {
s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
DELETED_FLAG) {
- if (!(inode = iget(dir->i_dev,*ino))) break;
+ if (!(inode = iget(dir->i_sb,*ino))) break;
if (!MSDOS_I(inode)->i_busy) {
iput(inode);
break;
ino = msdos_parent_ino(dir,0);
iput(dir);
if (ino < 0) return ino;
- if (!(*result = iget(dir->i_dev,ino))) return -EACCES;
+ if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
return 0;
}
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
}
if (bh) brelse(bh);
/* printk("lookup: ino=%d\r\n",ino); */
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -EACCES;
}
while (MSDOS_I(*result)->i_old) {
next = MSDOS_I(*result)->i_old;
iput(*result);
- if (!(*result = iget(next->i_dev,next->i_ino)))
+ if (!(*result = iget(next->i_sb,next->i_ino)))
panic("msdos_lookup: Can't happen");
}
iput(dir);
date_unix2dos(CURRENT_TIME,&de->time,&de->date);
de->size = 0;
bh->b_dirt = 1;
- if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result);
+ if (*result = iget(dir->i_sb,ino)) msdos_read_inode(*result);
brelse(bh);
if (!*result) return -EIO;
(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
get_fs_byte(name+1) == '.'))) goto rmdir_done;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done;
res = -ENOENT;
- if (!(inode = iget(dir->i_dev,ino))) goto rmdir_done;
+ if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done;
res = -ENOTDIR;
if (!S_ISDIR(inode->i_mode)) goto rmdir_done;
res = -EBUSY;
inode = NULL;
if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0)
goto unlink_done;
- if (!(inode = iget(dir->i_dev,ino))) {
+ if (!(inode = iget(dir->i_sb,ino))) {
res = -ENOENT;
goto unlink_done;
}
return -ENOENT;
}
if (exists) {
- if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
+ if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
brelse(new_bh);
return -EIO;
}
memcpy(old_de->name,new_name,MSDOS_NAME);
old_bh->b_dirt = 1;
if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */
- if (old_inode = iget(old_dir->i_dev,old_ino)) {
+ if (old_inode = iget(old_dir->i_sb,old_ino)) {
msdos_read_inode(old_inode);
iput(old_inode);
}
if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
if (old_ino == new_dir->i_ino) return -EINVAL;
- if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO;
+ if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO;
while (walk->i_ino != MSDOS_ROOT_INO) {
ino = msdos_parent_ino(walk,1);
iput(walk);
if (ino < 0) return ino;
if (ino == old_ino) return -EINVAL;
- if (!(walk = iget(new_dir->i_dev,ino))) return -EIO;
+ if (!(walk = iget(new_dir->i_sb,ino))) return -EIO;
}
iput(walk);
if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0)
return error;
exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)
>= 0;
- if (!(old_inode = iget(old_dir->i_dev,old_ino))) {
+ if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
brelse(free_bh);
if (exists) brelse(new_bh);
return -EIO;
}
new_inode = NULL; /* to make GCC happy */
if (exists) {
- if (!(new_inode = iget(new_dir->i_dev,new_ino))) {
+ if (!(new_inode = iget(new_dir->i_sb,new_ino))) {
iput(old_inode);
brelse(new_bh);
return -EIO;
}
memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
memcpy(free_de->name,new_name,MSDOS_NAME);
- if (!(free_inode = iget(new_dir->i_dev,free_ino))) {
+ if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
free_de->name[0] = DELETED_FLAG;
/* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */
brelse(free_bh);
if (S_ISDIR(old_inode->i_mode)) {
if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
&dotdot_de,&dotdot_ino)) < 0) goto rename_done;
- if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) {
+ if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
brelse(dotdot_bh);
error = -EIO;
goto rename_done;
}
if (!dir)
return -ENOENT;
+ if (!dir->i_op || !dir->i_op->lookup) {
+ iput(dir);
+ return -ENOTDIR;
+ }
if (!permission(dir,MAY_EXEC)) {
iput(dir);
return -EACCES;
*result = dir;
return 0;
}
- if (!dir->i_op || !dir->i_op->lookup) {
- iput(dir);
- return -ENOENT;
- }
return dir->i_op->lookup(dir,name,len,result);
}
return 0;
}
-int do_mknod(const char * filename, int mode, int dev)
+int do_mknod(const char * filename, int mode, dev_t dev)
{
const char * basename;
int namelen, error;
return dir->i_op->mknod(dir,basename,namelen,mode,dev);
}
-int sys_mknod(const char * filename, int mode, int dev)
+int sys_mknod(const char * filename, int mode, dev_t dev)
{
if (S_ISFIFO(mode) || suser())
return do_mknod(filename,mode,dev);
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE)) {
+ if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
iput(dir);
return -EACCES;
}
iput(dir);
return -EROFS;
}
- if (!permission(dir,MAY_WRITE)) {
+ if (!permission(dir,MAY_WRITE | MAY_EXEC)) {
iput(dir);
return -EACCES;
}
return (close_fp (filp));
}
+/*
+ * This routine is used by vhangup. It send's sigkill to everything
+ * waiting on a particular wait_queue. It assumes root privledges.
+ * We don't want to destroy the wait queue here, because the caller
+ * should call wake_up immediately after calling kill_wait.
+ */
+static void kill_wait(struct wait_queue **q, int sig)
+{
+ struct wait_queue *next;
+ struct wait_queue *tmp;
+ struct task_struct *p;
+
+ if (!q || !(next = *q))
+ return;
+ do {
+ tmp = next;
+ next = tmp->next;
+ if (p = tmp->task)
+ send_sig (sig, p , 1);
+ } while (next && next != *q);
+}
+
/*
* This routine looks through all the process's and closes any
* references to the current processes tty. To avoid problems with
*/
int sys_vhangup(void)
{
- int i,j;
+ int j;
+ struct task_struct ** process;
struct file *filep;
+ struct inode *inode;
struct tty_struct *tty;
- extern void kill_wait (struct wait_queue **q, int signal);
extern int kill_pg (int pgrp, int sig, int priv);
if (!suser())
if (current->tty < 0)
return 0;
- for (i = 0; i < NR_TASKS; i++) {
- if (task[i] == NULL)
- continue;
+ for (process = task + 0; process < task + NR_TASKS; process++) {
for (j = 0; j < NR_OPEN; j++) {
- filep = task[i]->filp[j];
- if (!filep)
+ if (!*process)
+ break;
+ if (!(filep = (*process)->filp[j]))
continue;
- if (!S_ISCHR(filep->f_inode->i_mode))
+ if (!(inode = filep->f_inode))
continue;
- if ((MAJOR(filep->f_inode->i_rdev) == 5 ||
- MAJOR(filep->f_inode->i_rdev) == 4 ) &&
+ if (!S_ISCHR(inode->i_mode))
+ continue;
+ if ((MAJOR(inode->i_rdev) == 5 ||
+ MAJOR(inode->i_rdev) == 4 ) &&
(MAJOR(filep->f_rdev) == 4 &&
MINOR(filep->f_rdev) == MINOR (current->tty))) {
/* so now we have found something to close. We
need to kill every process waiting on the
inode. */
- task[i]->filp[j] = NULL;
- kill_wait (&filep->f_inode->i_wait, SIGKILL);
+ (*process)->filp[j] = NULL;
+ kill_wait (&inode->i_wait, SIGKILL);
/* now make sure they are awake before we close the
file. */
- wake_up (&filep->f_inode->i_wait);
+ wake_up (&inode->i_wait);
/* finally close the file. */
- current->close_on_exec &= ~(1<<j);
+ (*process)->close_on_exec &= ~(1<<j);
close_fp (filep);
}
}
But we can't touch current->tty until after the
loop is complete. */
- if (task[i]->tty == current->tty && task[i] != current) {
- task[i]->tty = -1;
+ if (*process && (*process)->tty == current->tty && *process != current) {
+ (*process)->tty = -1;
}
}
/* need to do tty->session = 0 */
tty = TTY_TABLE(MINOR(current->tty));
- tty->session = 0;
- tty->pgrp = -1;
- current->tty = -1;
+ if (tty) {
+ tty->session = 0;
+ tty->pgrp = -1;
+ current->tty = -1;
+ }
return 0;
}
iput(dir);
return -ENOENT;
}
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -ENOENT;
}
{
unsigned int ino, pid, fd, c;
struct task_struct * p;
- int i, dev;
+ struct super_block * sb;
+ int i;
*result = NULL;
ino = dir->i_ino;
ino -= 7;
if (!dir)
return -ENOENT;
+ sb = dir->i_sb;
if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) {
iput(dir);
return -ENOENT;
*result = dir;
return 0;
}
- if (!(*result = iget(dir->i_dev,(pid << 16)+2))) {
+ if (!(*result = iget(sb,(pid << 16)+2))) {
iput(dir);
return -ENOENT;
}
iput(dir);
return 0;
}
- dev = dir->i_dev;
iput(dir);
fd = 0;
while (len-- > 0) {
return -ENOENT;
ino = (pid << 16) + 0x200 + fd;
}
- if (!(*result = iget(dev,ino)))
+ if (!(*result = iget(sb,ino)))
return -ENOENT;
return 0;
}
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
void proc_put_inode(struct inode *inode)
{
+ if (inode->i_nlink)
+ return;
inode->i_size = 0;
}
{
lock_super(sb);
sb->s_dev = 0;
- free_super(sb);
+ unlock_super(sb);
}
static struct super_operations proc_sops = {
struct super_block *proc_read_super(struct super_block *s,void *data)
{
- int dev=s->s_dev;
-
lock_super(s);
s->s_blocksize = 1024;
s->s_magic = PROC_SUPER_MAGIC;
- s->s_dev = dev;
s->s_op = &proc_sops;
- free_super(s);
- if (!(s->s_mounted = iget(dev,PROC_ROOT_INO))) {
- s->s_dev=0;
+ unlock_super(s);
+ if (!(s->s_mounted = iget(s,PROC_ROOT_INO))) {
+ s->s_dev = 0;
printk("get root inode failed\n");
return NULL;
}
return -ENOENT;
}
ino = (pid << 16) + 2;
- if (!(*result = iget(dir->i_dev,ino))) {
+ if (!(*result = iget(dir->i_sb,ino))) {
iput(dir);
return -ENOENT;
}
#include <linux/kernel.h>
#include <linux/stat.h>
#include <linux/errno.h>
+#include <linux/locks.h>
#include <asm/system.h>
#include <asm/segment.h>
-int sync_dev(int dev);
void wait_for_keypress(void);
void fcntl_init_locks(void);
struct super_block super_block[NR_SUPER];
/* this is initialized in init/main.c */
-int ROOT_DEV = 0;
+dev_t ROOT_DEV = 0;
/* Move into include file later */
return(NULL);
}
-void lock_super(struct super_block * sb)
+void __wait_on_super(struct super_block * sb)
{
- cli();
- while (sb->s_lock)
- sleep_on(&(sb->s_wait));
- sb->s_lock = 1;
- sti();
+ add_wait_queue(&sb->s_wait,¤t->wait);
+repeat:
+ current->state = TASK_UNINTERRUPTIBLE;
+ if (sb->s_lock) {
+ schedule();
+ goto repeat;
+ }
+ remove_wait_queue(&sb->s_wait,¤t->wait);
+ current->state = TASK_RUNNING;
}
-void free_super(struct super_block * sb)
+void sync_supers(dev_t dev)
{
- sb->s_lock = 0;
- wake_up(&(sb->s_wait));
-}
+ struct super_block * sb;
-void wait_on_super(struct super_block * sb)
-{
- cli();
- while (sb->s_lock)
- sleep_on(&(sb->s_wait));
- sti();
+ for (sb = super_block + 0 ; sb < super_block + NR_SUPER ; sb++) {
+ if (!sb->s_dev)
+ continue;
+ wait_on_super(sb);
+ if (!sb->s_dev || !sb->s_dirt)
+ continue;
+ if (dev && (dev != sb->s_dev))
+ continue;
+ if (sb->s_op && sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+ }
}
-struct super_block * get_super(int dev)
+static struct super_block * get_super(dev_t dev)
{
struct super_block * s;
return NULL;
}
-void put_super(int dev)
+void put_super(dev_t dev)
{
struct super_block * sb;
sb->s_op->put_super(sb);
}
-static struct super_block * read_super(int dev,char *name,int flags,void *data)
+static struct super_block * read_super(dev_t dev,char *name,int flags,void *data)
{
struct super_block * s;
struct file_system_type *type;
return s;
}
-static int do_umount(int dev)
+static int do_umount(dev_t dev)
{
struct super_block * sb;
- struct inode * inode;
if (dev==ROOT_DEV)
return -EBUSY;
return -ENOENT;
if (!sb->s_covered->i_mount)
printk("Mounted inode has i_mount=0\n");
- for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++)
- if (inode->i_dev==dev && inode->i_count)
- if (inode == sb->s_mounted && inode->i_count == 1)
- continue;
- else
- return -EBUSY;
+ if (!fs_may_umount(dev, sb->s_mounted))
+ return -EBUSY;
sb->s_covered->i_mount=0;
iput(sb->s_covered);
sb->s_covered = NULL;
sb->s_mounted = NULL;
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super (sb);
- put_super(dev);
+ put_super(dev);
return 0;
}
iput(inode);
return -ENOTBLK;
}
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (MAJOR(dev) >= MAX_BLKDEV) {
+ iput(inode);
+ return -ENODEV;
+ }
retval = do_umount(dev);
- if (!retval && MAJOR(dev) < MAX_BLKDEV &&
- blkdev_fops[MAJOR(dev)]->release)
+ if (!retval && blkdev_fops[MAJOR(dev)] && blkdev_fops[MAJOR(dev)]->release)
blkdev_fops[MAJOR(dev)]->release(inode,NULL);
iput(inode);
- if (retval) return retval;
- sync_dev(dev);
+ if (retval)
+ return retval;
+ sync_dev(dev);
return 0;
}
* We also have to flush all inode-data for this device, as the new mount
* might need new info.
*/
-static int do_mount(int dev, const char * dir, char * type, int flags, void * data)
+static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
{
- struct inode * inode, * dir_i;
+ struct inode * dir_i;
struct super_block * sb;
int error;
iput(dir_i);
return -EPERM;
}
- for (inode = inode_table+0 ; inode < inode_table+NR_INODE ; inode++) {
- if (inode->i_dev != dev)
- continue;
- if (inode->i_count || inode->i_dirt || inode->i_lock) {
- iput(dir_i);
- return -EBUSY;
- }
- inode->i_dev = 0;
+ if (!fs_may_mount(dev)) {
+ iput(dir_i);
+ return -EBUSY;
}
sb = read_super(dev,type,flags,data);
if (!sb || sb->s_covered) {
unsigned long new_flags, void *data)
{
struct inode * inode;
+ struct file_operations * fops;
int dev;
int retval;
char tmp[100],*t;
if (!suser())
return -EPERM;
- retval = namei(dev_name,&inode);
- if (retval)
+ if (retval = namei(dev_name,&inode))
return retval;
dev = inode->i_rdev;
- if (!S_ISBLK(inode->i_mode))
- retval = -EPERM;
- else if (IS_NODEV(inode))
- retval = -EACCES;
- if (!retval && blkdev_fops[MAJOR(dev)]->open)
- retval = blkdev_fops[MAJOR(dev)]->open(inode,NULL);
- if (retval) {
+ if (!S_ISBLK(inode->i_mode)) {
iput(inode);
- return retval;
+ return -ENOTBLK;
+ }
+ if (IS_NODEV(inode)) {
+ iput(inode);
+ return -EACCES;
+ }
+ if (MAJOR(dev) >= MAX_BLKDEV) {
+ iput(inode);
+ return -ENODEV;
+ }
+ fops = blkdev_fops[MAJOR(dev)];
+ if (fops && fops->open) {
+ if (retval = fops->open(inode,NULL)) {
+ iput(inode);
+ return retval;
+ }
}
if ((new_flags & 0xffff0000) == 0xC0ED0000) {
flags = new_flags & 0xffff;
t = "minix";
retval = do_mount(dev,dir_name,t,flags,(void *) page);
free_page(page);
- if (retval && blkdev_fops[MAJOR(dev)]->release)
- blkdev_fops[MAJOR(dev)]->release(inode,NULL);
+ if (retval && fops && fops->release)
+ fops->release(inode,NULL);
iput(inode);
return retval;
}
--- /dev/null
+/* $Header: /sys/linux-0.97/include/asm/RCS/dma.h,v 1.4 1992/09/21 03:15:46 root Exp root $
+ * linux/include/asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <asm/io.h> /* need byte IO */
+#include <linux/kernel.h> /* need panic() [FIXME] */
+
+
+#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER
+#define outb outb_p
+#endif
+
+/* FIXME: better fix this code for dma channels>3!!!!!!! */
+
+/*
+ * The routines below should in most cases (with optimizing on) result
+ * in equal or better code than similar code using macros.
+ *
+ * NOTE about DMA transfers: The DMA controller cannot handle transfers
+ * that cross a 64k boundary. When the address reaches 0xNffff, it will wrap
+ * around to 0xN0000, rather than increment to 0x(N+1)0000 !
+ * Make sure you align your buffers properly! Runtime check recommended.
+ *
+ * NOTE2: DMA1..3 can only use the lower 1MB of physical memory. DMA4..7
+ * can access the lower 16MB. There are people with >16MB, so beware!
+ */
+
+
+#define MAX_DMA_CHANNELS 8
+
+/* SOMEBODY should check the following:
+ * Channels 0..3 are on the first DMA controller, channels 4..7 are
+ * on the second. Channel 0 is for refresh, 4 is for cascading.
+ * The first DMA controller uses bytes, the second words.
+ *
+ * Where are the page regs for the second DMA controller?????
+ */
+
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG 0x08 /* DMA command register */
+#define DMA1_STAT_REG 0x08 /* DMA status register */
+#define DMA1_MASK_REG 0x0A /* mask individual channels */
+#define DMA1_MODE_REG 0x0B /* set modes for individual channels */
+#define DMA1_CLEAR_FF_REG 0x0C /* Write 0 for LSB, 1 for MSB */
+#define DMA1_RESET_REG 0x0D /* Write here to reset DMA controller */
+/* don't have much info on the second DMA controller... */
+#define DMA2_MASK_REG 0xD4
+#define DMA2_MODE_REG 0xD6
+/* #define DMA2_CLEAR_FF_REG 0xD8 -- pure guessing.... */
+
+/************* #error This needs more work!!!!!!!*************/
+
+#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0 /* cascade mode (for DMA2 controller only) */
+
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+ if (dmanr<=3)
+ outb(dmanr, DMA1_MASK_REG);
+ else
+ outb(dmanr & 3, DMA2_MASK_REG);
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+ if (dmanr<=3)
+ outb(dmanr | 4, DMA1_MASK_REG);
+ else
+ outb((dmanr & 3) | 4, DMA2_MASK_REG);
+}
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a know state.
+ * After that, keep track of it. :-) In order to do that,
+ * dma_set_addr() and dma_set_count() should only be used wile
+ * interrupts are disbled.
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+ if (dmanr<=3)
+ outb(0, DMA1_CLEAR_FF_REG);
+ else
+#ifdef DMA2_CLEAR_FF_REG
+ outb(0, DMA2_CLEAR_FF_REG);
+#else
+ panic("dma.h: Don't have CLEAR_FF for high dma channels!\n");
+#endif
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+ if (dmanr<=3)
+ outb(mode | dmanr, DMA1_MODE_REG);
+ else
+ outb(DMA_MODE_CASCADE | mode | (dmanr&3), DMA2_MODE_REG);
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+ switch(dmanr) {
+ case 0:
+ outb(pagenr, 0x80);
+ break;
+ case 1:
+ outb(pagenr, 0x83);
+ break;
+ case 2:
+ outb(pagenr, 0x81);
+ break;
+ case 3:
+ outb(pagenr, 0x82);
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ panic("dma.h: don't know how to set DMA page regs for channels>3");
+ break;
+ }
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+ unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
+
+ set_dma_page(dmanr, a>>16);
+ outb(a & 0xff, ((dmanr&3)<<1) + io_base);
+ outb((a>>8) & 0xff, ((dmanr&3)<<1) + io_base);
+}
+
+
+/* Set transfer size (max 64k) for a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+ unsigned int dc = count - 1;
+ unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
+
+ outb(dc & 0xff, ((dmanr&3)<<1) + 1 + io_base);
+ outb((dc>>8) & 0xff, ((dmanr&3)<<1) + 1 + io_base);
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of bytes left to transfer,
+ * minus 1, modulo 64k.
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ short int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int io_base = (dmanr<=3)? IO_DMA1_BASE : IO_DMA2_BASE;
+
+ return 1 + inb( ((dmanr&3)<<1) + 1 + io_base ) +
+ ( inb( ((dmanr&3)<<1) + 1 + io_base ) << 8 );
+}
+
+/* These are in kernel/dma.c: */
+extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */
+extern void free_dma(unsigned int dmanr); /* release it again */
+
+
+#endif /* _ASM_DMA_H */
__asm__ ("movl %0,%%fs:%1"::"r" (val),"m" (*addr));
}
-extern inline void memcpy_tofs(void * to, void * from, unsigned long n)
+extern inline void memcpy_tofs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"push %%es\n\t"
:"cx","di","si");
}
-extern inline void memcpy_fromfs(void * to, void * from, unsigned long n)
+extern inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
{
__asm__("cld\n\t"
"testb $1,%%cl\n\t"
#define DEF_SETUPSEG 0x9020
#define DEF_SYSSIZE 0x7000
+/* internal svga startup constants */
+#define NORMAL_VGA 0xffff /* 80x25 mode */
+#define EXTENDED_VGA 0xfffe /* 80x50 mode */
+#define ASK_VGA 0xfffd /* ask for it at bootup */
+
/*
* The root-device is no longer hard-coded. You can change the default
* root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s
extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len);
-extern struct inode * ext_new_inode(int dev);
+extern struct inode * ext_new_inode(struct super_block * sb);
extern void ext_free_inode(struct inode * inode);
extern unsigned long ext_count_free_inodes(struct super_block *sb);
-extern int ext_new_block(int dev);
-extern void ext_free_block(int dev, int block);
+extern int ext_new_block(struct super_block * sb);
+extern void ext_free_block(struct super_block * sb, int block);
extern unsigned long ext_count_free_blocks(struct super_block *sb);
extern int ext_bmap(struct inode *,int);
#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */
extern void buffer_init(void);
+extern void inode_init(void);
#define MAJOR(a) (((unsigned)(a))>>8)
#define MINOR(a) ((a)&0xff)
char * b_data; /* pointer to data block (1024 bytes) */
unsigned long b_size; /* block size */
unsigned long b_blocknr; /* block number */
- unsigned short b_dev; /* device (0 = free) */
+ dev_t b_dev; /* device (0 = free) */
unsigned short b_count; /* users using this block */
unsigned char b_uptodate;
unsigned char b_dirt; /* 0-clean,1-dirty */
};
struct file {
- unsigned short f_mode;
+ mode_t f_mode;
+ dev_t f_rdev; /* needed for /dev/tty */
+ off_t f_pos;
unsigned short f_flags;
unsigned short f_count;
unsigned short f_reada;
- unsigned short f_rdev; /* needed for /dev/tty */
struct inode * f_inode;
struct file_operations * f_op;
- off_t f_pos;
};
struct file_lock {
#include <linux/msdos_fs_sb.h>
struct super_block {
- unsigned short s_dev;
+ dev_t s_dev;
unsigned long s_blocksize;
unsigned char s_lock;
unsigned char s_rd_only;
extern struct file_system_type *get_fs_type(char *name);
-extern struct inode inode_table[NR_INODE];
+extern int fs_may_mount(dev_t dev);
+extern int fs_may_umount(dev_t dev, struct inode * mount_root);
+
extern struct file file_table[NR_FILE];
extern struct super_block super_block[NR_SUPER];
extern int nr_buffers;
extern int nr_buffer_heads;
-extern void check_disk_change(int dev);
-extern void invalidate_inodes(int dev);
-extern void invalidate_buffers(int dev);
+extern void check_disk_change(dev_t dev);
+extern void invalidate_inodes(dev_t dev);
+extern void invalidate_buffers(dev_t dev);
extern int floppy_change(struct buffer_head * first_block);
extern int ticks_to_floppy_on(unsigned int dev);
extern void floppy_on(unsigned int dev);
extern void floppy_off(unsigned int dev);
-extern void sync_inodes(void);
-extern void wait_on(struct inode * inode);
+extern void sync_inodes(dev_t dev);
+extern void sync_dev(dev_t dev);
+extern void sync_supers(dev_t dev);
extern int bmap(struct inode * inode,int block);
extern int namei(const char * pathname, struct inode ** res_inode);
extern int lnamei(const char * pathname, struct inode ** res_inode);
extern int permission(struct inode * inode,int mask);
extern int open_namei(const char * pathname, int flag, int mode,
struct inode ** res_inode, struct inode * base);
-extern int do_mknod(const char * filename, int mode, int dev);
+extern int do_mknod(const char * filename, int mode, dev_t dev);
extern void iput(struct inode * inode);
-extern struct inode * iget(int dev,int nr);
+extern struct inode * iget(struct super_block * sb,int nr);
extern struct inode * get_empty_inode(void);
extern struct inode * get_pipe_inode(void);
extern struct file * get_empty_filp(void);
-extern struct buffer_head * get_hash_table(int dev, int block, int size);
-extern struct buffer_head * getblk(int dev, int block, int size);
+extern struct buffer_head * get_hash_table(dev_t dev, int block, int size);
+extern struct buffer_head * getblk(dev_t dev, int block, int size);
extern void ll_rw_block(int rw, struct buffer_head * bh);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern void brelse(struct buffer_head * buf);
-extern struct buffer_head * bread(int dev, int block, int size);
-extern void bread_page(unsigned long addr,int dev,int b[4]);
-extern struct buffer_head * breada(int dev,int block,...);
-extern int sync_dev(int dev);
-extern struct super_block * get_super(int dev);
-extern void put_super(int dev);
-extern int ROOT_DEV;
+extern struct buffer_head * bread(dev_t dev, int block, int size);
+extern void bread_page(unsigned long addr,dev_t dev,int b[4]);
+extern struct buffer_head * breada(dev_t dev,int block,...);
+extern void put_super(dev_t dev);
+extern dev_t ROOT_DEV;
extern void mount_root(void);
-extern void lock_super(struct super_block * sb);
-extern void free_super(struct super_block * sb);
extern int char_read(struct inode *, struct file *, char *, int);
extern int block_read(struct inode *, struct file *, char *, int);
void verify_area(void * addr,int count);
volatile void panic(const char * str);
volatile void do_exit(long error_code);
+unsigned long simple_strtoul(const char *,char **,unsigned int);
int printk(const char * fmt, ...);
void * malloc(unsigned int size);
void free_s(void * obj, int size);
--- /dev/null
+#ifndef _LINUX_LOCKS_H
+#define _LINUX_LOCKS_H
+
+/*
+ * Buffer cache locking - note that interrupts may only unlock, not
+ * lock buffers.
+ */
+extern void __wait_on_buffer(struct buffer_head *);
+
+extern inline void wait_on_buffer(struct buffer_head * bh)
+{
+ if (bh->b_lock)
+ __wait_on_buffer(bh);
+}
+
+extern inline void lock_buffer(struct buffer_head * bh)
+{
+ if (bh->b_lock)
+ __wait_on_buffer(bh);
+ bh->b_lock = 1;
+}
+
+extern inline void unlock_buffer(struct buffer_head * bh)
+{
+ bh->b_lock = 0;
+ wake_up(&bh->b_wait);
+}
+
+/*
+ * super-block locking. Again, interrupts may only unlock
+ * a super-block (although even this isn't done right now.
+ * nfs may need it).
+ */
+extern void __wait_on_super(struct super_block *);
+
+extern inline void wait_on_super(struct super_block * sb)
+{
+ if (sb->s_lock)
+ __wait_on_super(sb);
+}
+
+extern inline void lock_super(struct super_block * sb)
+{
+ if (sb->s_lock)
+ __wait_on_super(sb);
+ sb->s_lock = 1;
+}
+
+extern inline void unlock_super(struct super_block * sb)
+{
+ sb->s_lock = 0;
+ wake_up(&sb->s_wait);
+}
+
+#endif /* _LINUX_LOCKS_H */
+
#ifndef _LINUX_LP_H
#define _LINUX_LP_H
-/*
-$Header: /usr/src/linux/include/linux/lp.h,v 1.2 1992/01/21 23:59:24 james_r_wiegand Exp james_r_wiegand $
-*/
-
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/sched.h>
/*
* usr/include/linux/lp.h c.1991-1992 James Wiegand
+ * many modifications copyright (C) 1992 Michael K. Johnson
*/
/*
* caveat: my machine only has 1 printer @ lpt2 so lpt1 & lpt3 are
* implemented but UNTESTED
+ *
+ * My machine (Michael K. Johnson) has only lpt1... dupla caveat...
*/
/*
* Per POSIX guidelines, this module reserves the LP and lp prefixes
+ * These are the lp_table[minor].flags flags...
*/
#define LP_EXIST 0x0001
#define LP_SELEC 0x0002
#define LP_NOPA 0x0010
#define LP_ERR 0x0020
-#define LP_TIMEOUT 200000
-
-#define LP_B(minor) lp_table[(minor)].base
-#define LP_F(minor) lp_table[(minor)].flags
-#define LP_S(minor) inb(LP_B((minor)) + 1)
+/* timeout for each character (This is a good case 50 Mhz computer
+ at a poor case 10 KBS xfer rate to the printer, as best as I can
+ tell.) This is in instruction cycles, kinda -- it is the count
+ in a busy loop. THIS IS THE VALUE TO CHANGE if you have extremely
+ slow printing, or if the machine seems to slow down a lot when you
+ print. If you have slow printing, increase this number and recompile,
+ and if your system gets bogged down, decrease this number.*/
+#define LP_TIME_CHAR 5000
+
+/* timeout for printk'ing a timeout, in jiffies (100ths of a second).
+ If your printer isn't printing at least one character every five seconds,
+ you have worse problems than a slow printer driver and lp_timeout printed
+ every five seconds while trying to print. */
+#define LP_TIMEOUT 5000
+
+#define LP_B(minor) lp_table[(minor)].base /* IO address */
+#define LP_F(minor) lp_table[(minor)].flags /* flags for busy, etc. */
+#define LP_S(minor) inb(LP_B((minor)) + 1) /* status port */
+#define LP_C(minor) (lp_table[(minor)].base + 2) /* control port */
+#define LP_COUNT(minor) lp_table[(minor)].count /* last count */
+#define LP_TIME(minor) lp_table[(minor)].time /* last time */
/*
since we are dealing with a horribly slow device
struct lp_struct {
int base;
int flags;
+ int count;
+ int time;
};
-/*
- * the BIOS manuals say there can be up to 4 lpt devices
+/* This is the starting value for the heuristic algorithm. If you
+ * want to tune this and have a fast printer (i.e. HPIIIP), decrease
+ * this number, and if you have a slow printer, increase this number.
+ * This is not stricly necessary, as the algorithm should be able to
+ * adapt to your printer relatively quickly.
+ * this is in hundredths of a second, the default 50 being .5 seconds.
+ */
+
+#define LP_INIT_TIME 50
+
+/* This is our first guess at the size of the buffer on the printer,
+ * in characters. I am assuming a 4K buffer because most newer printers
+ * have larger ones, which will be adapted to. At this time, it really
+ * doesn't matter, as this value isn't used.
+ */
+
+#define LP_INIT_COUNT 4096
+
+/* the BIOS manuals say there can be up to 4 lpt devices
* but I have not seen a board where the 4th address is listed
* if you have different hardware change the table below
* please let me know if you have different equipment
* if you have more than 3 printers, remember to increase LP_NO
*/
struct lp_struct lp_table[] = {
- { 0x3bc, 0, },
- { 0x378, 0, },
- { 0x278, 0, }
+ { 0x3bc, 0, LP_INIT_COUNT, LP_INIT_TIME, },
+ { 0x378, 0, LP_INIT_COUNT, LP_INIT_TIME, },
+ { 0x278, 0, LP_INIT_COUNT, LP_INIT_TIME, }
};
-
#define LP_NO 3
/*
* bit defines for 8255 status port
* base + 1
+ * accessed with LP_S(minor), which gets the byte...
*/
#define LP_PBUSY 0x80 /* active low */
#define LP_PACK 0x40 /* active low */
#define LP_POUTPA 0x20
#define LP_PSELECD 0x10
-#define LP_PERRORP 0x08 /*Ã¥ active low*/
-#define LP_PIRQ 0x04 /* active low */
+#define LP_PERRORP 0x08 /* active low*/
/*
* defines for 8255 control port
* base + 2
+ * accessed with LP_C(minor)
*/
-#define LP_PIRQEN 0x10
#define LP_PSELECP 0x08
#define LP_PINITP 0x04 /* active low */
#define LP_PAUTOLF 0x02
#define LP_DUMMY 0x00
/*
- * this is the port delay time. your mileage may vary
+ * This is the port delay time. Your mileage may vary.
+ * It is used only in the lp_init() routine.
*/
#define LP_DELAY 150000
extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
struct inode * new_dir, const char * new_name, int new_len);
-extern struct inode * minix_new_inode(int dev);
+extern struct inode * minix_new_inode(struct super_block * sb);
extern void minix_free_inode(struct inode * inode);
extern unsigned long minix_count_free_inodes(struct super_block *sb);
-extern int minix_new_block(int dev);
-extern void minix_free_block(int dev, int block);
+extern int minix_new_block(struct super_block * sb);
+extern void minix_free_block(struct super_block * sb, int block);
extern unsigned long minix_count_free_blocks(struct super_block *sb);
extern int minix_bmap(struct inode *,int);
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
+/*
+ * The wait-queues are circular lists, and you have to be *very* sure
+ * to keep them correct. Use only these two functions to add/remove
+ * entries in the queues.
+ */
extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
{
unsigned long flags;
- struct wait_queue * tmp;
+#ifdef DEBUG
+ if (wait->next) {
+ unsigned long pc;
+ __asm__ __volatile__("call 1f\n"
+ "1:\tpopl %0":"=r" (pc));
+ printk("add_wait_queue (%08x): wait->next = %08x\n",pc,wait->next);
+ }
+#endif
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- wait->next = *p;
- tmp = wait;
- while (tmp->next)
- if ((tmp = tmp->next)->next == *p)
- break;
- *p = tmp->next = wait;
+ if (!*p) {
+ wait->next = wait;
+ *p = wait;
+ } else {
+ wait->next = (*p)->next;
+ (*p)->next = wait;
+ }
__asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
struct wait_queue * tmp;
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- if (*p == wait)
- if ((*p = wait->next) == wait)
- *p = NULL;
- tmp = wait;
- while (tmp && tmp->next != wait)
- tmp = tmp->next;
- if (tmp)
+ if ((*p == wait) && ((*p = wait->next) == wait)) {
+ *p = NULL;
+ } else {
+ tmp = wait;
+ while (tmp->next != wait)
+ tmp = tmp->next;
tmp->next = wait->next;
+ }
wait->next = NULL;
__asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
}
return;
entry->wait_address = wait_address;
entry->wait.task = current;
+ entry->wait.next = NULL;
add_wait_queue(wait_address,&entry->wait);
p->nr++;
}
#ifndef _LINUX_STRING_H_
#define _LINUX_STRING_H_
+#include <linux/types.h> /* for size_t */
+
#ifndef NULL
#define NULL ((void *) 0)
#endif
return __res;
}
-extern inline void * memcpy(void * dest,const void * src, size_t n)
+extern inline void * memcpy(void * to, const void * from, size_t n)
{
__asm__("cld\n\t"
- "rep\n\t"
- "movsb"
- ::"c" (n),"S" (src),"D" (dest)
- :"cx","si","di");
-return dest;
+ "movl %%edx, %%ecx\n\t"
+ "shrl $2,%%ecx\n\t"
+ "rep ; movsl\n\t"
+ "testb $1,%%dl\n\t"
+ "je 1f\n\t"
+ "movsb\n"
+ "1:\ttestb $2,%%dl\n\t"
+ "je 2f\n\t"
+ "movsw\n"
+ "2:\n"
+ ::"d" (n),"D" ((long) to),"S" ((long) from)
+ : "cx","di","si");
+return (to);
}
extern inline void * memmove(void * dest,const void * src, size_t n)
#include <linux/tty.h>
#include <linux/head.h>
#include <linux/unistd.h>
+#include <linux/string.h>
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
extern long kernel_mktime(struct mktime * time);
+extern unsigned long simple_strtoul(const char *cp,char **endp,unsigned int
+ base);
#ifdef CONFIG_SCSI
-extern void scsi_dev_init(void);
+extern unsigned long scsi_dev_init(unsigned long, unsigned long);
#endif
-static int sprintf(char * str, const char *fmt, ...)
-{
- va_list args;
- int i;
-
- va_start(args, fmt);
- i = vsprintf(str, fmt, args);
- va_end(args);
- return i;
-}
-
/*
* This is set up by the setup-routine at boot-time
*/
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF)
+/*
+ * Boot command-line arguments
+ */
+#define MAX_INIT_ARGS 8
+#define MAX_INIT_ENVS 8
+#define CL_MAGIC_ADDR (*(unsigned short *) 0x90020)
+#define CL_MAGIC 0xa33f
+#define CL_BASE_ADDR ((char *) 0x90000)
+#define CL_OFFSET (*(unsigned short *) 0x90022)
+
/*
* Yeah, yeah, it's ugly, but I cannot find how to do this correctly
* and this seems to work. I anybody has more info on the real-time
static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0;
-static char term[32];
-
-static char * argv_init[] = { "/bin/init", NULL };
-static char * envp_init[] = { "HOME=/", NULL, NULL };
+static char * argv_init[MAX_INIT_ARGS+2] = { "/bin/init", NULL, };
+static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, };
static char * argv_rc[] = { "/bin/sh", NULL };
-static char * envp_rc[] = { "HOME=/", NULL ,NULL };
+static char * envp_rc[] = { "HOME=/", "TERM=console", NULL };
static char * argv[] = { "-/bin/sh",NULL };
-static char * envp[] = { "HOME=/usr/root", NULL, NULL };
+static char * envp[] = { "HOME=/usr/root", "TERM=console", NULL };
struct drive_info { char dummy[32]; } drive_info;
struct screen_info screen_info;
unsigned char aux_device_present;
+static char command_line[80] = { 0, };
+
+/*
+ * This is a simple kernel command line parsing function: it parses
+ * the command line, and fills in the arguments/environment to init
+ * as appropriate. Any cmd-line option is taken to be an environment
+ * variable if it contains the character '='.
+ *
+ *
+ * This routine also checks for options meant for the kernel - currently
+ * only the "root=XXXX" option is recognized. These options are not given
+ * to init - they are for internal kernel use only.
+ */
+static void parse_options(char *line)
+{
+ char *next;
+ int args, envs;
+
+ if (!*line)
+ return;
+ args = 0;
+ envs = 1; /* TERM is set to 'console' by default */
+ next = line;
+ while (line = next) {
+ if (next = strchr(line,' '))
+ *next++ = 0;
+ /*
+ * check for kernel options first..
+ */
+ if (!strncmp(line,"root=",5)) {
+ ROOT_DEV = simple_strtoul(line+5,NULL,16);
+ continue;
+ }
+ /*
+ * Then check if it's an environment variable or
+ * an option.
+ */
+ if (strchr(line,'=')) {
+ if (envs >= MAX_INIT_ENVS)
+ break;
+ envp_init[++envs] = line;
+ } else {
+ if (args >= MAX_INIT_ARGS)
+ break;
+ argv_init[++args] = line;
+ }
+ }
+ argv_init[args+1] = NULL;
+ envp_init[envs+1] = NULL;
+}
+
void start_kernel(void)
{
/*
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
aux_device_present = AUX_DEVICE_INFO;
- sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
- envp[1] = term;
- envp_rc[1] = term;
- envp_init[1] = term;
memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= 0xfffff000;
#ifdef MAX_16M
low_memory_start += 0xfff;
low_memory_start &= 0xfffff000;
memory_start = paging_init(memory_start,memory_end);
+ if (CL_MAGIC_ADDR == CL_MAGIC)
+ strcpy(command_line,CL_BASE_ADDR+CL_OFFSET);
trap_init();
init_IRQ();
sched_init();
+ parse_options(command_line);
#ifdef PROFILE_SHIFT
prof_buffer = (unsigned long *) memory_start;
prof_len = (unsigned long) &end;
#endif
memory_start = chr_dev_init(memory_start,memory_end);
memory_start = blk_dev_init(memory_start,memory_end);
+#ifdef CONFIG_SCSI
+ memory_start = scsi_dev_init(memory_start,memory_end);
+#endif
mem_init(low_memory_start,memory_start,memory_end);
buffer_init();
+ inode_init();
time_init();
floppy_init();
sock_init();
sti();
-#ifdef CONFIG_SCSI
- scsi_dev_init();
-#endif
- sti();
move_to_user_mode();
if (!fork()) /* we count on this going ok */
init();
proto:
cproto -e -DMAKING_PROTO *.c >fpu_proto.h
-tar:
- echo "List of source files for wm-FPU-emu" > MANIFEST
- echo "---- -- ------ ----- --- ----------" >> MANIFEST
- ls -l Makefile *.c *.S *.h >> MANIFEST
- ( cd ../../..; \
- pwd; \
- tar cvf wm-FPU-emu.t \
- linux/kernel/wm-FPU-emu/*.c \
- linux/kernel/wm-FPU-emu/*.S \
- linux/kernel/wm-FPU-emu/*.h \
- linux/kernel/wm-FPU-emu/Makefile \
- linux/kernel/wm-FPU-emu/MANIFEST \
- linux/kernel/wm-FPU-emu/README \
- linux/kernel/wm-FPU-emu/Checklist \
- linux/kernel/wm-FPU-emu/Limitations \
- linux/kernel/wm-FPU-emu/Internals \
- linux/kernel/wm-FPU-emu/Performance \
- linux/kernel/wm-FPU-emu/COPYING \
- linux/include/linux/sched.h \
- linux/include/linux/user.h \
- ; \
- compress wm-FPU-emu.t \
- )
-
dummy:
### Dependencies:
}
-/********
-int EmptyError(void)
-{
- EXCEPTION(EX_StackUnder);
- return 0;
-}
- **********/
-
-
-/****
-int FullError(void)
-{
- EXCEPTION(EX_StackOver);
- reg_move(&CONST_QNaN, st0_ptr);
- return 0;
-}
- ****/
-
-
-
-
/* Real operation attempted on two operands, one a NaN */
void real_2op_NaN(REG *a, REG *b, REG *dest)
{
REG tmp;
EXCEPTION(EX_Denormal); /* De-normal */
reg_move(st0_ptr, &tmp);
- tmp.exp += EXTENDED_Emin + 64; /* largest exp to be 62 */
+ tmp.exp += -EXTENDED_Emin + 64; /* largest exp to be 63 */
round_to_int(&tmp);
e = 0;
put_fs_long(tmp.sigl, (unsigned long *) d);
REG tmp;
EXCEPTION(EX_Denormal);
reg_move(st0_ptr, &tmp);
- tmp.exp += DOUBLE_Emin + 52; /* largest exp to be 51 */
+ tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
round_to_int(&tmp);
l[0] = tmp.sigl;
l[1] = tmp.sigh;
REG tmp;
EXCEPTION(EX_Denormal);
reg_move(st0_ptr, &tmp);
- tmp.exp += SINGLE_Emin + 53; /* largest exp to be 52 */
+ tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
round_to_int(&tmp);
templ = tmp.sigl;
}
{
/* Make a de-normal */
reg_move(rp, &tmp);
- tmp.exp += EXTENDED_Emin + 64; /* largest exp to be 62 */
+ tmp.exp += -EXTENDED_Emin + 64; /* largest exp to be 63 */
round_to_int(&tmp);
e = 0;
put_fs_long(tmp.sigl, (unsigned long *) (d+i*10+2));
reg_u_mul(a, b, dest);
dest->exp += - EXP_BIAS + 1;
dest->sign = (a->sign ^ b->sign);
+ dest->tag = TW_Valid;
if ( dest->exp <= EXP_UNDER )
{ arith_underflow(st0_ptr); }
else if ( dest->exp >= EXP_OVER )
{ arith_overflow(st0_ptr); }
- else
- dest->tag = TW_Valid;
return;
}
else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero))
cmpl $0x80000000,%edx
jc L_no_round_up
-/* Check the rounding algorithm *********/
jne L_do_round_up
+ /* Now test for round-to-even */
testb $1,%ebx
jz L_no_round_up
L_do_round_up:
addl $1,%ebx
adcl $0,%eax
- jnc L_no_round_up
+ jnc L_no_round_up /* Rounding done, no overflow */
/* Overflow, adjust the result */
rcrl $1,%eax
rcrl $1,%ebx
+ incl EXP(%edi)
L_no_round_up:
/* store the result */
L_round_up:
addl $1,%ebx
adcl $0,%eax
-
-#ifdef PARANOID
- /* We can show that an overflow here is not possible */
- jc L_bugged_4
-#endif PARANOID
+ jnc L_store
+
+ /* We just rounded up to (1) 00 00 */
+ /* This *is* possible, if the subtraction is of the
+ form (1. + x) - (x + y) where x is small and y is
+ very small. */
+ incl EXP(%edi)
+ movl $0x80000000,%eax
L_store:
/*------------------------------+
| |
+---------------------------------------------------------------------------*/
-#define FPU_VERSION "wm-FPU-emu version ALPHA 0.5"
+#define FPU_VERSION "wm-FPU-emu version ALPHA 0.61"
SUBDIRS = chr_drv blk_drv FPU-emu
-OBJS = sched.o sys_call.o traps.o irq.o fork.o \
+OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o ptrace.o ioport.o itimer.o
unsigned long nr_sectors;
unsigned long current_nr_sectors;
char * buffer;
- struct wait_queue * waiting;
+ struct task_struct * waiting;
struct buffer_head * bh;
struct buffer_head * bhtail;
struct request * next;
{
struct request * req;
struct buffer_head * bh;
+ struct task_struct * p;
req = CURRENT;
req->errors = 0;
}
DEVICE_OFF(req->dev);
CURRENT = req->next;
- wake_up(&req->waiting);
+ if (p = req->waiting) {
+ req->waiting = NULL;
+ p->state = TASK_RUNNING;
+ if (p->counter > current->counter)
+ need_resched = 1;
+ }
req->dev = -1;
wake_up(&wait_for_request);
}
* 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed
* FDC data overrun bug, added some preliminary stuff for vertical
* recording support.
+ *
+ * 1992/9/17: Added DMA allocation & DMA functions. -- hhb.
+ *
* TODO: Errors are still not counted properly.
*/
#define REALLY_SLOW_IO
#define FLOPPY_IRQ 6
+#define FLOPPY_DMA 2
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/fdreg.h>
#include <linux/fd.h>
#include <linux/errno.h>
-#ifdef HHB_SYSMACROS
-#include <linux/system.h>
-#endif
+#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
static unsigned int changed_floppies = 0, fake_change = 0;
+static int initial_reset_flag = 0;
+static int need_configure = 1; /* for 82077 */
static int recalibrate = 0;
static int reset = 0;
static int recover = 0; /* recalibrate immediately after resetting */
/*
* Announce successful media type detection and media information loss after
* disk changes.
+ * Also used to enable/disable printing of overrun warnings.
*/
static ftd_msg[4] = { 0,0,0,0 };
(CURRENT->errors))
/*
- * Treshold for reporting FDC errors to the console.
+ * Threshold for reporting FDC errors to the console.
* Setting this to zero may flood your screen when using
* ultra cheap floppies ;-)
*/
void request_done(int uptodate)
{
timer_active &= ~(1 << FLOPPY_TIMER);
- if (format_status != FORMAT_BUSY) end_request(uptodate);
+ if (format_status != FORMAT_BUSY)
+ end_request(uptodate);
else {
format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR;
wake_up(&format_done);
copy_buffer(CURRENT->buffer,tmp_floppy_area);
}
cli();
-#ifndef HHB_SYSMACROS
-/* mask DMA 2 */
- outb_p(4|2,10);
-/* output command byte. I don't know why, but everyone (minix, */
-/* sanches & canton) output this twice, first to 12 then to 11 */
- outb_p(dma_code,12);
- outb_p(dma_code,11);
-/* 8 low bits of addr */
- outb_p(addr,4);
- addr >>= 8;
-/* bits 8-15 of addr */
- outb_p(addr,4);
- addr >>= 8;
-/* bits 16-19 of addr */
- outb_p(addr,0x81);
-/* low 8 bits of count-1 */
- count--;
- outb_p(count,5);
- count >>= 8;
-/* high 8 bits of count-1 */
- outb_p(count,5);
-/* activate DMA 2 */
- outb_p(0|2,10);
-#else /* just to show off my macros -- hhb */
- DISABLE_DMA(DMA2);
- CLEAR_DMA_FF(DMA2);
- SET_DMA_MODE(DMA2, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
- SET_DMA_ADDR(DMA2, addr);
- SET_DMA_COUNT(DMA2, count);
- ENABLE_DMA(DMA2);
-#endif
+ disable_dma(FLOPPY_DMA);
+ clear_dma_ff(FLOPPY_DMA);
+ set_dma_mode(FLOPPY_DMA, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE);
+ set_dma_addr(FLOPPY_DMA, addr);
+ set_dma_count(FLOPPY_DMA, count);
+ enable_dma(FLOPPY_DMA);
sti();
}
static void bad_flp_intr(void)
{
+ int errors;
+
current_track = NO_TRACK;
- CURRENT_ERRORS++;
- if (CURRENT_ERRORS > MAX_ERRORS) {
+ if (format_status == FORMAT_BUSY)
+ errors = ++format_errors;
+ else if (!CURRENT) {
+ printk(DEVICE_NAME ": no current request\n");
+ reset = recalibrate = 1;
+ return;
+ } else
+ errors = ++CURRENT->errors;
+ if (errors > MAX_ERRORS) {
floppy_deselect(current_drive);
request_done(0);
}
- if (CURRENT_ERRORS > MAX_ERRORS/2)
+ if (errors > MAX_ERRORS/2)
reset = 1;
else
recalibrate = 1;
}
+
+/* Set perpendicular mode as required, based on data rate, if supported.
+ * 82077 Untested! 1Mbps data rate only possible with 82077-1.
+ * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
+ */
+static void inline perpendicular_mode(unsigned char rate)
+{
+ if (fdc_version == FDC_TYPE_82077) {
+ output_byte(FD_PERPENDICULAR);
+ if (rate & 0x40) {
+ unsigned char r = rate & 0x03;
+ if (r == 0)
+ output_byte(2); /* perpendicular, 500 kbps */
+ else if (r == 3)
+ output_byte(3); /* perpendicular, 1Mbps */
+ else {
+ printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
+ reset = 1;
+ }
+ } else
+ output_byte(0); /* conventional mode */
+ } else {
+ if (rate & 0x40) {
+ printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n");
+ reset = 1;
+ }
+ }
+} /* perpendicular_mode */
+
+
/*
* This has only been tested for the case fdc_version == FDC_TYPE_STD.
* In case you have a 82077 and want to test it, you'll have to compile
*/
static void configure_fdc_mode(void)
{
- if (fdc_version == FDC_TYPE_82077) {
+ if (need_configure && (fdc_version == FDC_TYPE_82077)) {
/* Enhanced version with FIFO & vertical recording. */
output_byte(FD_CONFIGURE);
output_byte(0);
- output_byte(0x1A); /* FIFO on, polling off, 10 byte treshold */
+ output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */
output_byte(0); /* precompensation from track 0 upwards */
+ need_configure = 0;
printk(DEVICE_NAME ": FIFO enabled\n");
}
+ if (cur_spec1 != floppy->spec1) {
+ cur_spec1 = floppy->spec1;
+ output_byte(FD_SPECIFY);
+ output_byte(cur_spec1); /* hut etc */
+ output_byte(6); /* Head load time =6ms, DMA */
+ }
+ if (cur_rate != floppy->rate) {
+ /* use bit 6 of floppy->rate to indicate perpendicular mode */
+ perpendicular_mode(floppy->rate);
+ outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR);
+ }
} /* configure_fdc_mode */
request_done(0);
bad = 0;
} else if (ST1 & ST1_OR) {
- printk(DEVICE_NAME ": Over/Underrun - retrying\n");
+ if (ftd_msg[ST0 & ST0_DS])
+ printk(DEVICE_NAME ": Over/Underrun - retrying\n");
/* could continue from where we stopped, but ... */
bad = 0;
} else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) {
setup_rw_floppy();
}
-/* Set perpendicular mode as required, based on data rate, if supported.
- * 80277: 1Mbps data rate only possible with 82077-1.
- * Untested!! TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries.
- */
-static void inline perpendicular_mode(unsigned char rate)
-{
- if (fdc_version == FDC_TYPE_82077) {
- output_byte(FD_PERPENDICULAR);
- if (rate & 0x40) {
- unsigned char r = rate & 0x03;
- if (r == 0)
- output_byte(2); /* perpendicular, 500 kbps */
- else if (r == 3)
- output_byte(3); /* perpendicular, 1Mbps */
- else {
- printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n");
- reset = 1;
- }
- } else
- output_byte(0); /* conventional mode */
- } else {
- if (rate & 0x40) {
- printk(DEVICE_NAME ": perpendicular mode not supported by FDC.\n");
- reset = 1;
- }
- }
-} /* perpendicular_mode */
/*
* This routine is called when everything should be correctly set up
{
read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) &&
(floppy->sect <= MAX_BUFFER_SECTORS);
- if (cur_spec1 != floppy->spec1) {
- cur_spec1 = floppy->spec1;
- output_byte(FD_SPECIFY);
- output_byte(cur_spec1); /* hut etc */
- output_byte(6); /* Head load time =6ms, DMA */
- }
- if (cur_rate != floppy->rate) {
- /* use bit 6 of floppy->rate to indicate perpendicular mode */
- perpendicular_mode(floppy->rate);
- outb_p(cur_rate = ((floppy->rate)) & ~0x40, FD_DCR);
- }
+
+ configure_fdc_mode();
+
if (reset) {
redo_fd_request();
return;
setup_rw_floppy();
return;
}
+
do_floppy = seek_interrupt;
output_byte(FD_SEEK);
if (read_track)
if (result()!=2 || (ST0 & 0xE0) == 0x60)
reset = 1;
/* Recalibrate until track 0 is reached. Might help on some errors. */
- if ((ST0 & 0x10) == 0x10) recalibrate_floppy();
- else redo_fd_request();
+ if ((ST0 & 0x10) == 0x10)
+ recalibrate_floppy(); /* FIXME: should limit nr of recalibrates */
+ else
+ redo_fd_request();
}
static void unexpected_floppy_interrupt(void)
output_byte(FD_SPECIFY);
output_byte(cur_spec1); /* hut etc */
output_byte(6); /* Head load time =6ms, DMA */
- configure_fdc_mode(); /* reprogram if smart fdc */
- if (!recover) redo_fd_request();
+ configure_fdc_mode(); /* reprogram fdc */
+ if (initial_reset_flag) {
+ initial_reset_flag = 0;
+ recalibrate = 1;
+ reset = 0;
+ return;
+ }
+ if (!recover)
+ redo_fd_request();
else {
recalibrate_floppy();
recover = 0;
cur_spec1 = -1;
cur_rate = -1;
recalibrate = 1;
- printk("Reset-floppy called\n");
+ need_configure = 1;
+ if (!initial_reset_flag)
+ printk("Reset-floppy called\n");
cli();
- outb_p(current_DOR & ~0x04,FD_DOR);
+ outb_p(current_DOR & ~0x04, FD_DOR);
for (i=0 ; i<1000 ; i++)
__asm__("nop");
- outb(current_DOR,FD_DOR);
+ outb(current_DOR, FD_DOR);
sti();
}
static void shake_done(void)
{
current_track = NO_TRACK;
- if (inb(FD_DIR) & 0x80) request_done(0);
+ if (inb(FD_DIR) & 0x80)
+ request_done(0);
redo_fd_request();
}
keep_data[current_drive]--;
}
else {
- if (ftd_msg[current_drive] && current_type[
- current_drive] != NULL)
+ if (ftd_msg[current_drive] && current_type[current_drive] != NULL)
printk("Disk type is undefined after disk "
"change in fd%d\n",current_drive);
current_type[current_drive] = NULL;
if (format_status != FORMAT_BUSY) {
if (!CURRENT) {
if (!fdc_busy)
- printk("FDC access conflict");
+ printk("FDC access conflict!");
fdc_busy = 0;
wake_up(&fdc_wait);
CLEAR_INTR;
* my FDC does, except when booting in SVGA screen mode.
* When it does generate an interrupt, it doesn't return any status bytes.
* It appears to have something to do with the version command...
+ *
+ * This should never be called, because of the reset after the version check.
*/
static void ignore_interrupt(void)
{
- if (result() != 0) {
- printk(DEVICE_NAME ": weird interrupt ignored\n");
- reset = 1;
- }
+ printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result());
+ reset = 1;
CLEAR_INTR; /* ignore only once */
}
timer_active &= ~(1 << FLOPPY_TIMER);
config_types();
if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
- printk("Unable to grab IRQ%d for the floppy driver\n",FLOPPY_IRQ);
-
+ printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
+ if (request_dma(FLOPPY_DMA))
+ printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA);
/* Try to determine the floppy controller type */
DEVICE_INTR = ignore_interrupt; /* don't ask ... */
output_byte(FD_VERSION); /* get FDC version code */
#ifndef FDC_FIFO_UNTESTED
fdc_version = FDC_TYPE_STD; /* force std fdc type; can't test other. */
#endif
- configure_fdc_mode();
+
+ /* Not all FDCs seem to be able to handle the version command
+ * properly, so force a reset for the standard FDC clones,
+ * to avoid interrupt garbage.
+ */
+
+ if (fdc_version == FDC_TYPE_STD) {
+ initial_reset_flag = 1;
+ reset_floppy();
+ }
}
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/config.h>
+#include <linux/locks.h>
#include <asm/system.h>
*/
int * blk_size[NR_BLK_DEV] = { NULL, NULL, };
-static inline void lock_buffer(struct buffer_head * bh)
-{
- cli();
- while (bh->b_lock)
- sleep_on(&bh->b_wait);
- bh->b_lock=1;
- sti();
-}
-
-static inline void unlock_buffer(struct buffer_head * bh)
-{
- if (!bh->b_lock)
- printk("ll_rw_block.c: buffer not locked\n\r");
- bh->b_lock = 0;
- wake_up(&bh->b_wait);
-}
-
/* RO fail safe mechanism */
static long ro_bits[NR_BLK_DEV][8];
req->nr_sectors = 8;
req->current_nr_sectors = 8;
req->buffer = buffer;
- req->waiting = ¤t->wait;
+ req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
make_request(major,rw,bh);
}
-long blk_dev_init(long mem_start, long mem_end)
-{
- int i;
-
- for (i=0 ; i<NR_REQUEST ; i++) {
- request[i].dev = -1;
- request[i].next = NULL;
- }
- memset(ro_bits,0,sizeof(ro_bits));
-#ifdef CONFIG_BLK_DEV_HD
- mem_start = hd_init(mem_start,mem_end);
-#endif
-#ifdef RAMDISK
- mem_start += rd_init(mem_start, RAMDISK*1024);
-#endif
- return mem_start;
-}
-
void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
{
int i;
req->nr_sectors = 2;
req->current_nr_sectors = 2;
req->buffer = buf;
- req->waiting = ¤t->wait;
+ req->waiting = current;
req->bh = NULL;
req->next = NULL;
current->state = TASK_UNINTERRUPTIBLE;
schedule();
}
}
+
+long blk_dev_init(long mem_start, long mem_end)
+{
+ int i;
+
+ for (i=0 ; i<NR_REQUEST ; i++) {
+ request[i].dev = -1;
+ request[i].next = NULL;
+ }
+ memset(ro_bits,0,sizeof(ro_bits));
+#ifdef CONFIG_BLK_DEV_HD
+ mem_start = hd_init(mem_start,mem_end);
+#endif
+#ifdef RAMDISK
+ mem_start += rd_init(mem_start, RAMDISK*1024);
+#endif
+ return mem_start;
+}
#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
-#include <asm/memory.h>
#define MAJOR_NR 1
#include "blk.h"
wd7000fasst_queuecommand, \
wd7000fasst_abort, \
wd7000fasst_reset, \
- 1, 7, 0}
+ 1, 7, 0, 1}
#endif
return 0;
}
-#ifndef MAX_16M
- printk("Adaptec 1542 disabled for kernels without memory limiting to 16MB.\n");
- return 0;
-#endif
-
/* Set the Bus on/off-times as not to ruin floppy performens */
{
static unchar oncmd[] = {CMD_BUSON_TIME, 5};
aha1542_queuecommand, \
aha1542_abort, \
aha1542_reset, \
- 1, 7, 0}
+ 1, 7, 0, 1}
#endif
NULL, \
fdomain_16x0_abort, \
fdomain_16x0_reset, \
- 0, 6, 0 }
+ 0, 6, 0 ,0}
#endif
#endif
*/
unsigned present:1;
+ /*
+ true if this host adapter uses unchecked DMA onto an ISA bus.
+ */
+ unsigned unchecked_isa_dma:1;
+
} Scsi_Host;
/*
*/
static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
-void scsi_dev_init (void)
+unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end)
{
int i;
#ifdef FOO_ON_YOU
scan_scsis(); /* scan for scsi devices */
#ifdef CONFIG_BLK_DEV_SD
- sd_init(); /* init scsi disks */
+ memory_start = sd_init(memory_start, memory_end); /* init scsi disks */
#endif
#ifdef CONFIG_BLK_DEV_ST
- st_init(); /* init scsi tapes */
+ memory_start = st_init(memory_start, memory_end); /* init scsi tapes */
#endif
#ifdef CONFIG_BLK_DEV_SR
- sr_init();
+ memory_start = sr_init(memory_start, memory_end);
#endif
+ return memory_start;
}
#endif
Initializes all SCSI devices. This scans all scsi busses.
*/
-extern void scsi_dev_init (void);
+extern unsigned long scsi_dev_init (unsigned long, unsigned long);
/*
You guesed it. This sends a command to the selected SCSI host
the_result[host] = result;
}
+/* This function will operate certain scsi functions which require no
+ data transfer */
static int ioctl_internal_command(Scsi_Device *dev, char ** command)
{
- char * buf;
char * cmd;
int temp, host;
+ char sense_buffer[256];
host = dev->host_no;
cmd = command[0];
- buf = command[1];
do {
cli();
}
} while (1);
- scsi_do_cmd(host, dev->id, cmd, buf, 255,
+ scsi_do_cmd(host, dev->id, cmd, NULL, 0,
scsi_ioctl_done, MAX_TIMEOUT,
- buf, MAX_RETRIES);
+ sense_buffer, MAX_RETRIES);
while (the_result[host] == -1)
/* nothing */;
temp = the_result[host];
if(driver_byte(the_result[host]) != 0)
- switch(buf[2] & 0xf) {
+ switch(sense_buffer[2] & 0xf) {
case ILLEGAL_REQUEST:
printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
break;
dev->lun,
the_result);
printk("\tSense class %x, sense error %x, extended sense %x\n",
- sense_class(buf[0]),
- sense_error(buf[0]),
- buf[2] & 0xf);
+ sense_class(sense_buffer[0]),
+ sense_error(sense_buffer[0]),
+ sense_buffer[2] & 0xf);
};
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
command[0] = scsi_cmd;
- command[1] = (char *) arg;
return ioctl_internal_command((Scsi_Device *) dev, command);
break;
case SCSI_IOCTL_DOORUNLOCK:
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
command[0] = scsi_cmd;
- command[1] = (char *) arg;
return ioctl_internal_command((Scsi_Device *) dev, command);
case SCSI_IOCTL_TEST_UNIT_READY:
scsi_cmd[0] = TEST_UNIT_READY;
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 0;
command[0] = scsi_cmd;
- command[1] = (char *) arg;
return ioctl_internal_command((Scsi_Device *) dev, command);
break;
default :
#include <asm/system.h>
#include "scsi.h"
+#include "hosts.h"
#include "sd.h"
#include "scsi_ioctl.h"
#define SD_TIMEOUT 200
+#define ISA_DMA_THRESHOLD (0x00ffffff)
struct hd_struct sd[MAX_SD << 4];
+/* For a > 16 Mb system, we may need an intermediate buffer for data */
+
+struct block_buffer
+ {
+ unsigned long int use;
+ unsigned char buffer[4096];
+ };
+
+static struct block_buffer * bb = NULL;
+
int NR_SD=0;
Scsi_Disk rscsi_disks[MAX_SD];
static int sd_sizes[MAX_SD << 4] = {0, };
int target;
target = DEVICE_NR(MINOR(inode->i_rdev));
+ if(target >= NR_SD || !rscsi_disks[target].device)
+ return -EACCES; /* No such device */
+
/* Make sure that only one process can do a check_change_disk at one time.
This is also used to lock out further access when the partition table is being re-read. */
while (rscsi_disks[target].device->busy);
if(rscsi_disks[target].device->removable) {
- if (filp->f_mode)
- check_disk_change(inode->i_rdev);
+ check_disk_change(inode->i_rdev);
if(!rscsi_disks[target].device->access_count)
sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
*/
if (!result) {
+ if (bb && bb[DEVICE_NR(CURRENT->dev)].use && CURRENT->cmd == READ)
+ {
+ memcpy((char *)CURRENT->buffer,
+ bb[DEVICE_NR(CURRENT->dev)].buffer,
+ this_count << 9);
+#ifdef DEBUG
+ printk("R");
+#endif
+ };
+ if(bb) bb[DEVICE_NR(CURRENT->dev)].use = 0;
+
CURRENT->nr_sectors -= this_count;
if (slow_scsi_io == host) {
total_count -= this_count;
else
end_request(1);
do_sd_request();
- }
+ }
/*
* Of course, the error handling code is a little Fubar down in scsi.c.
*/
else if (driver_byte(result) & DRIVER_SENSE) {
+ if (bb) bb[DEVICE_NR(CURRENT->dev)].use = 0;
if (sugestion(result) == SUGGEST_REMAP) {
#ifdef REMAP
/*
Not yet implemented. A read will fail after being remapped,
a write will call the strategy routine again.
*/
+ if rscsi_disks[DEVICE_NR(CURRENT->dev)].remap
+ {
+ result = 0;
+ }
+ else
+
+#endif
+ }
+
+/* A unit attention comes up if there is a media change on a removable
+ disk drive */
+
else if ((sense_buffer[0] & 0x7f) == 0x70) {
if ((sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
/* detected disc change. set a bit and quietly refuse */
do_sd_request();
return;
}
- }
-
- if rscsi_disks[DEVICE_NR(CURRENT->dev)].remap
- {
- result = 0;
- }
- else
+ }
-#endif
- }
/*
If we had an ILLEGAL REQUEST returned, then we may have performed
an unsupported command. The only thing this should be would be a ten
system where READ CAPACITY failed, we mave have read past the end of the
disk.
*/
-
else if (sense_buffer[7] == ILLEGAL_REQUEST) {
if (rscsi_disks[DEVICE_NR(CURRENT->dev)].ten) {
rscsi_disks[DEVICE_NR(CURRENT->dev)].ten = 0;
}
}
if (result) {
+ if (bb) bb[DEVICE_NR(CURRENT->dev)].use = 0;
printk("SCSI disk error : host %d id %d lun %d return code = %x\n",
rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no,
rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id,
{
int dev, block;
unsigned char cmd[10];
+ char * buff;
repeat:
INIT_REQUEST;
cmd[1] = (LUN << 5) & 0xe0;
+ buff = CURRENT->buffer;
+
+/* Curses, curses. If this is a DMA transfer, we could be screwed. */
+ if (((int) buff) + (this_count << 9) > ISA_DMA_THRESHOLD &&
+ (scsi_hosts[HOST].unchecked_isa_dma)) {
+ if (bb[DEVICE_NR(CURRENT->dev)].use) panic ("block buffer already in use");
+ bb[DEVICE_NR(CURRENT->dev)].use = 1;
+ if(this_count > 8) this_count = 8;
+ if (CURRENT->cmd == WRITE) {
+ memcpy(bb[DEVICE_NR(CURRENT->dev)].buffer,
+ (char *)CURRENT->buffer, this_count << 9);
+#ifdef DEBUG
+ printk("W");
+#endif
+ };
+ buff = bb[DEVICE_NR(CURRENT->dev)].buffer;
+ };
+
if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
{
if (this_count > 0xffff)
cmd[5] = 0;
}
- scsi_do_cmd (HOST, ID, (void *) cmd, CURRENT->buffer, this_count << 9,
+ scsi_do_cmd (HOST, ID, (void *) cmd, buff, this_count << 9,
rw_intr, SD_TIMEOUT, sense_buffer, MAX_RETRIES);
}
their size, and reads partition table entries for them.
*/
-void sd_init(void)
+unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
sd_gendisk.next = gendisk_head;
gendisk_head = &sd_gendisk;
boot_init_done++;
+/* Allocate DMA block buffer */
+ if(memory_end > ISA_DMA_THRESHOLD) {
+ bb = (struct block_buffer *) memory_start;
+ memory_start += NR_SD * sizeof(struct block_buffer);
+ for (i=0; i < NR_SD; ++i) bb[i].use = 0;
+ };
+ return memory_start;
}
#define DEVICE_BUSY rscsi_disks[target].device->busy
sti();
if (DEVICE_BUSY || USAGE > maxusage) {
cli();
+ printk("Device busy for revalidation (usage=%d)\n", USAGE);
return -EBUSY;
};
DEVICE_BUSY = 1;
extern Scsi_Disk rscsi_disks[MAX_SD];
-void sd_init(void);
+unsigned long sd_init(unsigned long, unsigned long);
#define HOST (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->host_no)
#define ID (rscsi_disks[DEVICE_NR(CURRENT->dev)].device->id)
#define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \
seagate_st0x_info, seagate_st0x_command, \
seagate_st0x_queue_command, seagate_st0x_abort, \
- seagate_st0x_reset, 1, 7, 0}
+ seagate_st0x_reset, 1, 7, 0, 0}
#endif
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
+#include <linux/errno.h>
#include "scsi.h"
#include "sr.h"
unsigned char buffer[2048];
};
-static struct block_buffer bb[MAX_SR];
+static struct block_buffer * bb;
static int sr_open(struct inode *, struct file *);
static int sr_open(struct inode * inode, struct file * filp)
{
- if (filp->f_mode)
- check_disk_change(inode->i_rdev);
+ if(MINOR(inode->i_rdev) >= NR_SR ||
+ !scsi_CDs[MINOR(inode->i_rdev)].device) return -EACCES; /* No such device */
+
+ check_disk_change(inode->i_rdev);
if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
rw_intr, SR_TIMEOUT, sense_buffer, MAX_RETRIES);
}
-void sr_init(void)
+unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
{
int i;
+ bb = (struct block_buffer *) memory_start;
+ memory_start += NR_SR * sizeof(struct block_buffer);
+
for (i = 0; i < NR_SR; ++i)
{
scsi_CDs[i].capacity = 0x1fffff;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blk_size[MAJOR_NR] = sr_sizes;
blkdev_fops[MAJOR_NR] = &sr_fops;
+ return memory_start;
}
#endif
extern Scsi_CD scsi_CDs[MAX_SR];
-void sr_init(void);
+unsigned long sr_init(unsigned long, unsigned long);
#define SR_HOST (scsi_CDs[DEVICE_NR(CURRENT->dev)].device->host_no)
#define SR_ID (scsi_CDs[DEVICE_NR(CURRENT->dev)].device->id)
panic("There is no st driver.\n\r");
}
-void st_init(void)
+unsigned long st_init(unsigned long memory_start, unsigned long memory_end)
{
blk_dev[MAJOR_NR].request_fn = do_st_request;
blk_size[MAJOR_NR] = st_sizes;
+ return memory_start;
}
#endif
+
extern int NR_ST;
extern Scsi_Tape scsi_tapes[MAX_ST];
-void st_init(void);
+unsigned long st_init(unsigned long, unsigned long);
#endif
#define ULTRASTOR_14F \
{ "UltraStor 14F", ultrastor_14f_detect, ultrastor_14f_info, \
ultrastor_14f_command, 0, ultrastor_14f_abort, ultrastor_14f_reset, \
- 0, 0, 0 }
+ 0, 0, 0, 1 }
#endif
#define UD_ABORT 0x0001
rep = scancode;
repke0 = ke0;
}
- } else if (ke0 == repke0 && (scancode & 0x7f) == rep)
+ } else if (ke0 == repke0 && (scancode & 0x7f) == rep) {
if (scancode & 0x80)
rep = 0xff;
- else if (!(krepeat && tty && (L_ECHO(tty) ||
- (EMPTY(&tty->secondary) &&
- EMPTY(&tty->read_q))))) {
+ else if (!(krepeat && tty &&
+ (L_ECHO(tty) ||
+ (EMPTY(&tty->secondary) &&
+ EMPTY(&tty->read_q))))) {
ke0 = 0;
return;
}
+ }
key_table[scancode](scancode);
do_keyboard_interrupt();
ke0 = 0;
void hard_reset_now(void)
{
int i;
- unsigned long * pg_dir;
+ extern unsigned long pg0[1024];
sti();
/* rebooting needs to touch the page at absolute addr 0 */
- pg_dir = (unsigned long *) current->tss.cr3;
- pg_dir[768] = 7; /* 0xC0000000 */
+ pg0[0] = 7;
for (;;) {
for (i=0; i<100; i++) {
kb_wait();
/*
- $Header: /usr/src/linux/kernel/chr_drv/lp.c,v 1.9 1992/01/06 16:11:19
- james_r_wiegand Exp james_r_wiegand $
-*/
-
-/*
- * Edited by Linus - cleaner interface etc. Still not using interrupts, so
- * it eats more resources than necessary, but it was easy to code this way...
+ * Copyright (C) 1992 by Jim Weigand, Linus Torvalds, and Michael K. Johnson
*/
-#include <linux/sched.h>
#include <linux/lp.h>
+/* sched.h is included from lp.h */
static int lp_reset(int minor)
{
int testvalue;
/* reset value */
- outb(0, LP_B(minor)+2);
+ outb(0, LP_C(minor));
for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++)
;
- outb(LP_PSELECP | LP_PINITP, LP_B(minor)+2);
+ outb(LP_PSELECP | LP_PINITP, LP_C(minor));
return LP_S(minor);
}
outb(lpchar, LP_B(minor));
do {
retval = LP_S(minor);
- schedule();
count ++;
- } while(!(retval & LP_PBUSY) && count < LP_TIMEOUT);
- if (count == LP_TIMEOUT) {
- printk("lp%d timeout\n\r", minor);
+ if (need_resched)
+ schedule();
+ } while(!(retval & LP_PBUSY) && count < LP_TIME_CHAR);
+
+ if (count == LP_TIME_CHAR) {
return 0;
+ /* we timed out, and the character was /not/ printed */
}
- /* control port pr_table[0]+2 take strobe high */
- outb(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_B( minor ) + 2 ));
- /* take strobe low */
- outb(( LP_PSELECP | LP_PINITP ), ( LP_B( minor ) + 2 ));
- /* get something meaningful for return value */
+ /* control port takes strobe high */
+ outb(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
+ /* take strobe low */
+ outb(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
+ /* get something meaningful for return value */
return LP_S(minor);
}
{
int retval;
unsigned int minor = MINOR(inode->i_rdev);
+ unsigned int each_cnt = 0, old_cnt = 0;
char c, *temp = buf;
temp = buf;
while (count > 0) {
- c = get_fs_byte(temp++);
+ c = get_fs_byte(temp);
retval = lp_char(c, minor);
- count--;
- if (retval & LP_POUTPA) {
- LP_F(minor) |= LP_NOPA;
- return temp-buf?temp-buf:-ENOSPC;
- } else
- LP_F(minor) &= ~LP_NOPA;
-
- if (!(retval & LP_PSELECD)) {
- LP_F(minor) &= ~LP_SELEC;
- return temp-buf?temp-buf:-EFAULT;
- } else
- LP_F(minor) &= ~LP_SELEC;
-
- /* not offline or out of paper. on fire? */
- if (!(retval & LP_PERRORP)) {
- LP_F(minor) |= LP_ERR;
- return temp-buf?temp-buf:-EIO;
- } else
- LP_F(minor) &= ~LP_SELEC;
+ /* only update counting vars if character was printed */
+ if (retval) {
+ count--;
+ temp++;
+ }
+
+ if (!retval) { /* if printer timed out */
+ each_cnt = count - old_cnt;
+ old_cnt = count;
+
+ /* here we do calculations based on old count
+ and change the time that we will sleep.
+ For now this will be hard coded... */
+
+ /* check for signals before going to sleep */
+ if (current->signal & ~current->blocked) {
+ return temp-buf?temp-buf:-ERESTARTSYS;
+ }
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + LP_TIME(minor);
+ schedule();
+ LP_COUNT(minor) = each_cnt;
+
+ /* the following is ugly, but should alert me if
+ something dreadful is going on. It will disappear
+ in the final versions of the driver. */
+ if (!(LP_S(minor) & LP_BUSY)) {
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + LP_TIMEOUT;
+ schedule();
+ if (!(LP_S(minor) & LP_BUSY))
+ printk("lp%d timeout\n\r", minor);
+ }
+ } else {
+ if (retval & LP_POUTPA) {
+ LP_F(minor) |= LP_NOPA;
+ printk("lp%d out of paper\n\r", minor);
+ return temp-buf?temp-buf:-ENOSPC;
+ } else
+ LP_F(minor) &= ~LP_NOPA;
+
+ if (!(retval & LP_PSELECD)) {
+ LP_F(minor) |= LP_SELEC;
+ printk("lp%d off-line\n\r", minor);
+ return temp-buf?temp-buf:-EFAULT;
+ } else
+ LP_F(minor) &= ~LP_SELEC;
+
+ /* not offline or out of paper. on fire? */
+ if (!(retval & LP_PERRORP)) {
+ LP_F(minor) |= LP_ERR;
+ printk("lp%d on fire\n\r", minor);
+ return temp-buf?temp-buf:-EIO;
+ } else
+ LP_F(minor) &= ~LP_SELEC;
+ }
}
return temp-buf;
}
}
static struct file_operations lp_fops = {
- lp_lseek,
- lp_read,
+ lp_lseek, /* why not null? */
+ lp_read, /* why not null? */
lp_write,
NULL, /* lp_readdir */
NULL, /* lp_select */
NULL, /* lp_ioctl */
- NULL, /* lp_mmap */
+ NULL, /* mmap */
lp_open,
lp_release
};
#include <linux/tty.h>
#include <linux/mouse.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/string.h>
+
#include <asm/segment.h>
#include <asm/io.h>
return -EIO;
}
+static int read_core(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long p = file->f_pos;
+ int read;
+ int count1;
+ char * pnt;
+ struct user dump;
+
+ memset(&dump, 0, sizeof(struct user));
+ dump.magic = CMAGIC;
+ dump.u_dsize = high_memory >> 12;
+
+ if (count < 0)
+ return -EINVAL;
+ if (p >= high_memory)
+ return 0;
+ if (count > high_memory - p)
+ count = high_memory - p;
+ read = 0;
+
+ if (p < sizeof(struct user) && count > 0) {
+ count1 = count;
+ if (p + count1 > sizeof(struct user))
+ count1 = sizeof(struct user)-p;
+ pnt = (char *) &dump + p;
+ memcpy_tofs(buf,(void *) pnt, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+
+ while (p < (4096 + 4096) && count > 0) {
+ put_fs_byte(0,buf);
+ buf++;
+ p++;
+ count--;
+ read++;
+ }
+ memcpy_tofs(buf,(void *) (p - 4096),count);
+ read += count;
+ file->f_pos += read;
+ return read;
+}
+
static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
NULL /* no special release code */
};
+static struct file_operations core_fops = {
+ memory_lseek,
+ read_core,
+ NULL,
+ NULL, /* zero_readdir */
+ NULL, /* zero_select */
+ NULL, /* zero_ioctl */
+ NULL, /* zero_mmap */
+ NULL, /* no special open code */
+ NULL /* no special release code */
+};
+
static int memory_open(struct inode * inode, struct file * filp)
{
switch (MINOR(inode->i_rdev)) {
case 5:
filp->f_op = &zero_fops;
break;
+ case 6:
+ filp->f_op = &core_fops;
+ break;
default:
return -ENODEV;
}
info->timer = jiffies + info->timeout;
if (info->timer < timer_table[RS_TIMER].expires)
timer_table[RS_TIMER].expires = info->timer;
+#ifdef i386
rs_write_active |= 1 << line;
+#else
+ set_bit(line, &rs_write_active);
+#endif
timer_active |= 1 << RS_TIMER;
}
no_xmit:
if ((mask > rs_event) &&
(mask > rs_write_active))
break;
+ if (!info->tty) { /* check that we haven't closed it.. */
+ rs_event &= ~mask;
+ rs_write_active &= ~mask;
+ continue;
+ }
if (mask & rs_event) {
if (!clear_bit(RS_EVENT_READ_PROCESS, &info->event)) {
TTY_READ_FLUSH(info->tty);
}
if (mask & rs_write_active) {
if (info->timer <= jiffies) {
+#ifdef i386
rs_write_active &= ~mask;
+#else
+ clear_bit(info->line, &rs_write_active);
+#endif
rs_write(info->tty);
}
if ((mask & rs_write_active) &&
struct async_struct *info;
unsigned char mcr;
+#ifdef notdef
printk("throttle tty%d: %d (%d, %d)....\n", DEV_TO_SL(tty->line),
status, LEFT(&tty->read_q), LEFT(&tty->secondary));
+#endif
switch (status) {
case TTY_THROTTLE_RQ_FULL:
info = rs_table + DEV_TO_SL(tty->line);
if (!info->port)
return;
shutdown(info);
+#ifdef i386
+ rs_write_active &= ~(1 << line);
+ rs_event &= ~(1 << line);
+#else
+ clear_bit(line, &rs_write_active);
+ clear_bit(line, &rs_event);
+#endif
+ info->event = 0;
info->tty = 0;
ISR = info->ISR;
irq = ISR->irq;
struct async_struct * info;
unsigned short port;
int quot = 0;
- unsigned cflag,cval;
+ unsigned cflag,cval,mcr;
int i;
if (line >= NR_PORTS)
quot = 0;
info->timeout = 0;
}
- if (!quot) {
- shutdown(info);
+ mcr = inb(UART_MCR + port);
+ if (quot)
+ outb(mcr | UART_MCR_DTR, UART_MCR + port);
+ else {
+ outb(mcr & ~UART_MCR_DTR, UART_MCR + port);
return;
}
/* byte size and parity */
IRQ_ISR[irq] = ISR;
}
startup(info);
+ change_speed(info->line);
return 0;
}
}
} else
info->type = PORT_8250;
- startup(info);
- change_speed(info->line);
shutdown(info);
}
*/
int fg_console = 0;
struct tty_struct * redirect = NULL;
-struct wait_queue * keypress_wait;
+struct wait_queue * keypress_wait = NULL;
int initialize_tty_struct(struct tty_struct *tty, int line);
if (dev < 0)
return -ENODEV;
filp->f_rdev = 0x0400 | dev;
- tty = TTY_TABLE(dev);
- if (!tty) {
- tty = TTY_TABLE(dev) = (struct tty_struct *)
- get_free_page(GFP_KERNEL);
- if (!tty)
- return -ENOMEM;
- retval = initialize_tty_struct(tty, TTY_TABLE_IDX(dev));
- if (retval) {
- free_page((unsigned long)tty);
- return retval;
- }
- if (IS_A_PTY(dev) && !tty_table[PTY_OTHER(dev)]) {
- o_tty = (struct tty_struct *) get_free_page(GFP_USER);
- /*
- * Check for race condition, since get_free_page may sleep.
- */
- if (tty_table[PTY_OTHER(dev)]) {
- free_page((unsigned long) o_tty);
- goto other_done;
- }
- tty_table[PTY_OTHER(dev)] = o_tty;
- if (!o_tty) {
- free_page((unsigned long)tty);
- return -ENOMEM;
- }
- retval = initialize_tty_struct(o_tty, PTY_OTHER(dev));
+/*
+ * There be race-conditions here... Lots of them. Careful now.
+ */
+ tty = o_tty = NULL;
+ if (!TTY_TABLE(dev)) {
+ tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+ if (tty) {
+ retval = initialize_tty_struct(tty, TTY_TABLE_IDX(dev));
if (retval) {
- free_page((unsigned long) tty);
- free_page((unsigned long) o_tty);
+ free_page((unsigned long)tty);
return retval;
}
- tty->link = o_tty;
- o_tty->link = tty;
}
- other_done:
+ }
+ if (IS_A_PTY(dev)) {
+ if (!tty_table[PTY_OTHER(dev)]) {
+ o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+ if (o_tty) {
+ retval = initialize_tty_struct(o_tty, PTY_OTHER(dev));
+ if (retval) {
+ free_page((unsigned long) tty);
+ free_page((unsigned long) o_tty);
+ return retval;
+ }
+ }
+ }
+ if (!o_tty && !tty_table[PTY_OTHER(dev)]) {
+ free_page((unsigned long) tty);
+ return -ENOMEM;
+ }
+ }
+ if (TTY_TABLE(dev)) {
+ free_page((unsigned long) tty);
+ tty = TTY_TABLE(dev);
+ } else if (tty)
+ TTY_TABLE(dev) = tty;
+ else {
+ free_page((unsigned long) o_tty);
+ return -ENOMEM;
+ }
+ if (IS_A_PTY(dev)) {
+ if (tty_table[PTY_OTHER(dev)]) {
+ free_page((unsigned long) o_tty);
+ o_tty = tty_table[PTY_OTHER(dev)];
+ } else
+ tty_table[PTY_OTHER(dev)] = o_tty;
+ tty->link = o_tty;
+ o_tty->link = tty;
}
if (IS_A_PTY_MASTER(dev)) {
if (tty->count)
tp->c_oflag = OPOST | ONLCR;
tp->c_cflag = B38400 | CS8 | CREAD;
tp->c_lflag = ISIG | ICANON | ECHO | ECHOCTL | ECHOKE;
- } else if IS_A_SERIAL(line) {
+ } else if (IS_A_SERIAL(line)) {
tp->c_cflag = B2400 | CS8 | CREAD | HUPCL;
- } else if IS_A_PTY_MASTER(line) {
+ } else if (IS_A_PTY_MASTER(line)) {
tp->c_cflag = B9600 | CS8 | CREAD;
- } else if IS_A_PTY_SLAVE(line) {
+ } else if (IS_A_PTY_SLAVE(line)) {
tp->c_cflag = B9600 | CS8 | CREAD;
tp->c_lflag = ISIG | ICANON;
}
chrdev_fops[4] = &tty_fops;
chrdev_fops[5] = &tty_fops;
- keypress_wait = 0;
for (i=0 ; i<256 ; i++) {
tty_table[i] = 0;
tty_termios[i] = 0;
redirect = tty;
return 0;
case FIONBIO:
+ arg = get_fs_long((unsigned long *) arg);
if (arg)
file->f_flags |= O_NONBLOCK;
else
--- /dev/null
+/* $Header: /sys/linux-0.97/kernel/RCS/dma.c,v 1.4 1992/09/18 02:54:14 root Exp $
+ * linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.
+ * Written by Hennus Bergman, 1992.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <asm/dma.h>
+
+
+/* A note on resource allocation:
+ *
+ * All drivers needing DMA channels, should allocate and release them
+ * through the public routines `request_dma()' and `free_dma()'.
+ *
+ * In order to avoid problems, all processes should allocate resources in
+ * the same sequence and release them in the reverse order.
+ *
+ * So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA.
+ * When releasing them, first release the DMA, then release the IRQ.
+ * If you don't, you may cause allocation requests to fail unnecessarily.
+ * This doesn't really matter now, but it will once we get real semaphores
+ * in the kernel.
+ */
+
+
+
+/* Channel n is busy iff dma_chan_busy[n] != 0.
+ * DMA0 is reserved for DRAM refresh, I think.
+ * DMA4 is reserved for cascading (?).
+ */
+static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = {
+ 1, 0, 0, 0, 1, 0, 0, 0
+};
+
+
+
+/* Atomically swap memory location [32 bits] with `newval'.
+ * This avoid the cli()/sti() junk and related problems.
+ * [And it's faster too :-)]
+ * Maybe this should be in include/asm/mutex.h and be used for
+ * implementing kernel-semaphores as well.
+ */
+static unsigned int __inline__ mutex_atomic_swap(volatile unsigned int * p, unsigned int newval)
+{
+ unsigned int semval = newval;
+
+ /* If one of the operands for the XCHG instructions is a memory ref,
+ * it makes the swap an uninterruptible RMW cycle.
+ *
+ * One operand must be in memory, the other in a register, otherwise
+ * the swap may not be atomic.
+ */
+
+ asm __volatile__ ("xchgl %2, %0\n"
+ : /* outputs: semval */ "=r" (semval)
+ : /* inputs: newval, p */ "0" (semval), "m" (*p)
+ ); /* p is a var, containing an address */
+ return semval;
+} /* mutex_atomic_swap */
+
+
+
+int request_dma(unsigned int dmanr)
+{
+ if (dmanr >= MAX_DMA_CHANNELS)
+ return -EINVAL;
+
+ if (mutex_atomic_swap(&dma_chan_busy[dmanr], 1) != 0)
+ return -EBUSY;
+ else
+ /* old flag was 0, now contains 1 to indicate busy */
+ return 0;
+} /* request_dma */
+
+
+void free_dma(unsigned int dmanr)
+{
+ if (dmanr >= MAX_DMA_CHANNELS) {
+ printk("Trying to free DMA%d\n", dmanr);
+ return;
+ }
+
+ if (mutex_atomic_swap(&dma_chan_busy[dmanr], 0) == 0)
+ printk("Trying to free free DMA%d\n", dmanr);
+} /* free_dma */
+
return(found ? 0 : retval);
}
-/* This routine is used by vhangup. It send's sigkill to everything
- waiting on a particular wait_queue. It assumes root privledges.
- We don't want to destroy the wait queue here, because the caller
- should call wake_up immediately after calling kill_wait. */
-
-void
-kill_wait (struct wait_queue **q, int sig)
-{
- struct wait_queue *next;
- struct wait_queue *tmp;
- struct task_struct *p;
-
- if (!q || !(next = *q))
- return;
- do {
- tmp = next;
- next = tmp->next;
- if (p = tmp->task)
- {
- send_sig (sig, p , 1);
- }
- } while (next && next != *q);
-}
-
int kill_proc(int pid, int sig, int priv)
{
struct task_struct **p;
/*
* wake_up doesn't wake up stopped processes - they have to be awakened
* with signals or similar.
+ *
+ * Note that this doesn't need cli-sti pairs: interrupts may not change
+ * the wait-queue structures directly, but only call wake_up() to wake
+ * a process. The process itself must remove the queue once it has woken.
*/
void wake_up(struct wait_queue **q)
{
- struct wait_queue *tmp, *next;
+ struct wait_queue *tmp;
struct task_struct * p;
- unsigned long flags;
- if (!q || !(next = *q))
+ if (!q || !(tmp = *q))
return;
- save_flags(flags);
- cli();
do {
- tmp = next;
- next = tmp->next;
if (p = tmp->task) {
if (p->state == TASK_ZOMBIE)
printk("wake_up: TASK_ZOMBIE\n");
need_resched = 1;
}
}
- tmp->next = NULL;
- } while (next && next != *q);
- restore_flags(flags);
+#ifdef DEBUG
+ if (!tmp->next) {
+ printk("wait_queue is bad\n");
+ printk(" q = %08x\n",q);
+ printk(" *q = %08x\n",*q);
+ printk(" tmp = %08x\n",tmp);
+ break;
+ }
+#endif
+ tmp = tmp->next;
+ } while (tmp != *q);
}
static inline void __sleep_on(struct wait_queue **p, int state)
return;
if (current == task[0])
panic("task[0] trying to sleep");
- if (current->wait.next)
- printk("__sleep_on: wait->next exists\n");
- save_flags(flags);
- cli();
current->state = state;
add_wait_queue(p,¤t->wait);
+ save_flags(flags);
sti();
schedule();
remove_wait_queue(p,¤t->wait);
return -ERESTARTNOINTR; /* handle the signal, and come back */
}
-static inline void save_old(char * from,char * to)
-{
- int i;
-
- verify_area(to, sizeof(struct sigaction));
- for (i=0 ; i< sizeof(struct sigaction) ; i++) {
- put_fs_byte(*from,to);
- from++;
- to++;
- }
-}
-
-static inline void get_new(char * from,char * to)
-{
- int i;
-
- for (i=0 ; i< sizeof(struct sigaction) ; i++)
- *(to++) = get_fs_byte(from++);
-}
-
int sys_signal(int signum, long handler, long restorer)
{
struct sigaction tmp;
int sys_sigaction(int signum, const struct sigaction * action,
struct sigaction * oldaction)
{
- struct sigaction tmp;
+ struct sigaction new, *p;
if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
return -EINVAL;
- tmp = current->sigaction[signum-1];
- get_new((char *) action,
- (char *) (signum-1+current->sigaction));
- if (oldaction)
- save_old((char *) &tmp,(char *) oldaction);
- if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
- current->sigaction[signum-1].sa_mask = 0;
- else
- current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
+ p = signum - 1 + current->sigaction;
+ if (action) {
+ memcpy_fromfs(&new, action, sizeof(struct sigaction));
+ if (new.sa_flags & SA_NOMASK)
+ new.sa_mask = 0;
+ else
+ new.sa_mask |= (1<<(signum-1));
+ }
+ if (oldaction) {
+ verify_area(oldaction, sizeof(struct sigaction));
+ memcpy_tofs(oldaction, p, sizeof(struct sigaction));
+ }
+ if (action)
+ *p = new;
return 0;
}
return 0;
}
-int sys_getrlimit(int resource, struct rlimit *rlim)
+int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
{
if (resource >= RLIM_NLIMITS)
return -EINVAL;
return 0;
}
-int sys_setrlimit(int resource, struct rlimit *rlim)
+int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
{
struct rlimit new, *old;
#include <stdarg.h>
#include <linux/types.h>
#include <linux/string.h>
+#include <linux/ctype.h>
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (!base) {
+ base = 10;
+ if (*cp == '0') {
+ base = 8;
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1])) {
+ cp++;
+ base = 16;
+ }
+ }
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
/* we use this so that we can do without the ctype library */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/string.h>
+
#include <asm/system.h>
struct bucket_desc { /* 16 bytes */
printk("malloc called with impossibly large argument (%d)\n", len);
return NULL;
}
+ len = bdir->size;
/*
* Now we search for a bucket descriptor which has free space
*/
bdesc = free_bucket_desc;
free_bucket_desc = bdesc->next;
bdesc->refcnt = 0;
- bdesc->bucket_size = bdir->size;
+ bdesc->bucket_size = len;
bdesc->page = bdesc->freeptr =
(void *) cp = get_free_page(GFP_ATOMIC);
if (!cp) {
return NULL;
}
/* Set up the chain of free objects */
- for (i=PAGE_SIZE/bdir->size; i > 1; i--) {
- *((char **) cp) = cp + bdir->size;
- cp += bdir->size;
+ for (i=PAGE_SIZE/len; i > 1; i--) {
+ *((char **) cp) = cp + len;
+ cp += len;
}
*((char **) cp) = 0;
bdesc->next = bdir->chain; /* OK, link it in! */
bdesc->freeptr = *((void **) retval);
bdesc->refcnt++;
sti(); /* OK, we're safe again */
+ memset(retval, 0, len);
return retval;
}
nr[i] = bmap(inode,block);
bread_page(page,inode->i_dev,nr);
}
+ if (share_page(tsk,inode,address)) {
+ free_page(page);
+ return;
+ }
i = address + PAGE_SIZE - tsk->end_data;
if (i > PAGE_SIZE-1)
i = 0;
apt->hlen =hlen;
memcpy (apt->hard, addr, hlen);
apt->last_used=timer_seq;
- sti();
- apt->next = arp_table[hash];
- arp_table[hash]=apt;
cli();
+ apt->next = arp_table[hash];
+ arp_table[hash] = apt;
+ sti();
return (apt);
}
return (1);
}
-
void
arp_add (unsigned long addr, unsigned char *haddr, struct device *dev)
{
arp_add (addr, dev->broadcast , dev);
}
-
void
arp_queue(struct sk_buff *skb)
{
skb->prev = skb;
}
else
- {
- skb->next = arp_q;
- skb->prev = arp_q->prev;
- skb->next->prev = skb;
- skb->prev->next = skb;
- }
- sti();
-
+ {
+ skb->next = arp_q;
+ skb->prev = arp_q->prev;
+ skb->next->prev = skb;
+ skb->prev->next = skb;
+ }
+ sti();
}
-
#include <linux/mm.h>
#include <linux/socket.h>
#include <netinet/in.h>
-#include <asm/memory.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include <linux/mm.h>
#include <linux/socket.h>
#include <netinet/in.h>
-#include <asm/memory.h>
#include "dev.h"
#include "eth.h"
#include "timer.h"
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
+#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
-#include <asm/memory.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
+#include <linux/string.h>
#include <linux/sock_ioctl.h>
-#include <asm/memory.h>
#include "../kern_sock.h"
#include "timer.h"
#include "ip.h"
void
print_sk (volatile struct sock *sk)
{
+ if (!sk) {
+ PRINTK (" print_sk(NULL)\n");
+ return;
+ }
PRINTK (" wmem_alloc = %d\n", sk->wmem_alloc);
PRINTK (" rmem_alloc = %d\n", sk->rmem_alloc);
PRINTK (" send_head = %X\n", sk->send_head);
void
print_skb(struct sk_buff *skb)
{
+ if (!skb) {
+ PRINTK (" print_skb(NULL)\n");
+ return;
+ }
PRINTK (" prev = %X, next = %X\n", skb->prev, skb->next);
PRINTK (" sk = %X link3 = %X\n", skb->sk, skb->link3);
PRINTK (" mem_addr = %X, mem_len = %d\n", skb->mem_addr, skb->mem_len);
volatile struct sock *sk2;
PRINTK ("remove_sock(sk1=%X)\n",sk1);
+ if (!sk1)
+ {
+ printk ("sock.c: remove_sock: sk1 == NULL\n");
+ return;
+ }
+
+ if (!sk1->prot)
+ {
+ printk ("sock.c: remove_sock: sk1->prot == NULL\n");
+ return;
+ }
+
/* we can't have this changing out from under us. */
cli();
- sk2=sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)];
+ sk2 = sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)];
if (sk2 == sk1)
{
sk1->prot->sock_array[sk1->num & (SOCK_ARRAY_SIZE -1)] = sk1->next;
sti();
return;
}
- while (sk2->next != sk1)
+
+ while (sk2 && sk2->next != sk1)
+ sk2 = sk2->next;
+
+ if (sk2)
{
- if (sk2 == NULL)
- {
- sti();
- PRINTK ("remove_sock: sock not found.\n");
- return;
- }
- sk2=sk2->next;
+ sk2->next = sk1->next;
+ sti();
+ return;
}
- sk2->next = sk1->next;
sti();
+
+ if (sk1->num != 0)
+ PRINTK ("remove_sock: sock not found.\n");
}
void
void release_sock (volatile struct sock *sk)
{
+ if (!sk)
+ {
+ printk ("sock.c: release_sock sk == NULL\n");
+ return;
+ }
+
+ if (!sk->prot)
+ {
+ printk ("sock.c: release_sock sk->prot == NULL\n");
+ return;
+ }
+
if (sk->blog) return;
/* see if we have any packets built up. */
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <asm/memory.h>
+#include <linux/string.h>
#include <linux/socket.h>
#include <netinet/in.h>
#include <linux/fcntl.h>
struct tcp_header *th;
volatile struct sock *sk;
+ if (!skb)
+ {
+ printk ("tcp.c: tcp_rcv skb = NULL\n");
+ return (0);
+ }
+#if 0 /* it's ok for protocol to be NULL */
+ if (!protocol)
+ {
+ printk ("tcp.c: tcp_rcv protocol = NULL\n");
+ return (0);
+ }
+
+ if (!opt) /* it's ok for opt to be NULL */
+ {
+ printk ("tcp.c: tcp_rcv opt = NULL\n");
+ }
+#endif
+ if (!dev)
+ {
+ printk ("tcp.c: tcp_rcv dev = NULL\n");
+ return (0);
+ }
+
th = skb->h.th;
+
/* find the socket. */
sk=get_sock(&tcp_prot, net16(th->dest), saddr, th->source, daddr);
PRINTK("<<\n");
}
sk->inuse = 1;
sti();
+ }
+ else
+ {
+ if (!sk)
+ {
+ printk ("tcp.c: tcp_rcv bug sk=NULL redo = 1\n");
+ return (0);
+ }
+ }
+
+ if (!sk->prot)
+ {
+ printk ("tcp.c: tcp_rcv sk->prot = NULL \n");
+ return (0);
}
/* charge the memory to the socket. */
release_sock(sk);
return (0);
}
+
if (th->rst)
{
sk->err = ECONNRESET;
release_sock(sk);
return (0);
}
-
- if (opt->security != 0 || opt->compartment != 0 || th->syn)
+ if (opt && (opt->security != 0 || opt->compartment != 0 || th->syn))
{
sk->err = ECONNRESET;
sk->state = TCP_CLOSE;
sk = get_sock (prot, net16(uh->dest), saddr, uh->source, daddr);
/* if we don't know about the socket, forget about it. */
- if (sk == NULL &&
- (daddr & 0xff000000 != 0) && (daddr & 0xff000000 != 0xff000000))
+ if (sk == NULL)
{
- icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
- skb->sk = NULL;
- free_skb (skb, 0);
- return (0);
+ if ((daddr & 0xff000000 != 0) && (daddr & 0xff000000 != 0xff000000))
+ {
+ icmp_reply (skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
+ }
+ skb->sk = NULL;
+ free_skb (skb, 0);
+ return (0);
}
#include <linux/tty.h>
#include <linux/types.h>
#include <linux/ptrace.h>
+#include <linux/string.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <asm/io.h>
-#include <asm/memory.h>
#include <errno.h>
#include <linux/fcntl.h>
#include <netinet/in.h>