aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1993-03-22 21:03:45 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:14 -0400
commit3ccb23223d9cbee8e7946aa23f44a84ceff88d3c (patch)
tree35552324421d578052a6bc9267cae9a49aed3008
parenteeb7df9e7d9a3a48dc39743a13e0ed1cc0d5cb41 (diff)
downloadarchive-3ccb23223d9cbee8e7946aa23f44a84ceff88d3c.tar.gz
ALPHA-diffs for 0.99 patchlevel 7
I don't generally announce ALPHA-diffs to quite this large an audience, but I'll be partying^H^H^H^H^H^H^H^Hunavailable for the rest of the week, and it's unlikely that I will be able to check mails or the newsgroups until the start of April. As a result, I'm putting up my latest kernel version for ftp as it fixes some things in 0.99.7. The ALPHA-diffs can be found on nic.funet.fi: in the directory pub/OS/Linux/PEOPLE/Linus. If you dislike patching, you can get the full sources in "linux-0.99.7A.tar.z", or just get the diff file "ALPHA-diff.z". Changes in this release: - the new kernel now detects the lock-up condition at startup if you have a faulty 386/387 coupling, and will use software floating point in that case. - the Xia filesystem is updated to the latest version - the DOS filesystem is updated to the latest version - the XT disk driver is included: I haven't been able to test it, but at least it won't bother anybody if you don't configure it in.. - the latest serial diffs are in - minor ultrastor fixes - some changes to the keyboard and line printer drivers: I hope the keyboard lockups that some people have reported would be gone with this release. - some fixes to arp.c I'll be interested in success/failure reports, although I won't be able to answer them for some time (and I might miss some of the posts on c.o.l). Linus
-rw-r--r--Makefile24
-rw-r--r--config.in2
-rw-r--r--fs/buffer.c8
-rw-r--r--fs/exec.c2
-rw-r--r--fs/ext/symlink.c1
-rw-r--r--fs/minix/namei.c1
-rw-r--r--fs/msdos/dir.c8
-rw-r--r--fs/msdos/fat.c31
-rw-r--r--fs/msdos/file.c2
-rw-r--r--fs/msdos/inode.c184
-rw-r--r--fs/msdos/misc.c295
-rw-r--r--fs/msdos/namei.c80
-rw-r--r--fs/xiafs/bitmap.c3
-rw-r--r--fs/xiafs/dir.c14
-rw-r--r--fs/xiafs/file.c9
-rw-r--r--fs/xiafs/inode.c47
-rw-r--r--fs/xiafs/namei.c13
-rw-r--r--fs/xiafs/symlink.c12
-rw-r--r--fs/xiafs/truncate.c6
-rw-r--r--fs/xiafs/xiafs_mac.h12
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/msdos_fs.h37
-rw-r--r--include/linux/msdos_fs_i.h3
-rw-r--r--include/linux/msdos_fs_sb.h5
-rw-r--r--include/linux/sched.h18
-rw-r--r--include/linux/sys.h4
-rw-r--r--include/linux/timer.h3
-rw-r--r--include/linux/tty.h1
-rw-r--r--include/linux/xd.h143
-rw-r--r--init/main.c22
-rw-r--r--kernel/blk_drv/Makefile5
-rw-r--r--kernel/blk_drv/blk.h10
-rw-r--r--kernel/blk_drv/ll_rw_blk.c3
-rw-r--r--kernel/blk_drv/scsi/ultrastor.c4
-rw-r--r--kernel/blk_drv/xd.c619
-rw-r--r--kernel/chr_drv/console.c3
-rw-r--r--kernel/chr_drv/keyboard.c39
-rw-r--r--kernel/chr_drv/lp.c37
-rw-r--r--kernel/chr_drv/serial.c204
-rw-r--r--kernel/chr_drv/tty_io.c10
-rw-r--r--kernel/exit.c4
-rw-r--r--kernel/fork.c23
-rw-r--r--kernel/irq.c5
-rw-r--r--kernel/printk.c129
-rw-r--r--kernel/sched.c6
-rw-r--r--kernel/signal.c159
-rw-r--r--kernel/sys.c7
-rw-r--r--kernel/sys_call.S86
-rw-r--r--mm/memory.c24
-rw-r--r--mm/swap.c2
-rw-r--r--net/tcp/arp.c42
-rw-r--r--net/tcp/ip.c10
-rw-r--r--net/tcp/ip.h6
-rw-r--r--tools/build.c9
-rw-r--r--tools/version.h5
55 files changed, 1815 insertions, 627 deletions
diff --git a/Makefile b/Makefile
index f985dc4..cbcb8f7 100644
--- a/Makefile
+++ b/Makefile
@@ -24,11 +24,11 @@ endif
#
# ROOT_DEV specifies the default root-device when making the image.
-# This can be either FLOPPY, /dev/xxxx or empty, in which case the
-# default of FLOPPY is used by 'build'.
+# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case
+# the default of FLOPPY is used by 'build'.
#
-ROOT_DEV = /dev/hdb1
+ROOT_DEV = CURRENT
#
# uncomment the correct keyboard:
@@ -45,20 +45,20 @@ ROOT_DEV = /dev/hdb1
# 0x10 - dieresis (umlaut)
KEYBOARD = -DKBD_FINNISH -DKBDFLAGS=0
-# KEYBOARD = -DKBD_FINNISH_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_FINNISH_LATIN1 -DKBDFLAGS=0x1F
# KEYBOARD = -DKBD_US -DKBDFLAGS=0
# KEYBOARD = -DKBD_GR -DKBDFLAGS=0
-# KEYBOARD = -DKBD_GR_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_GR_LATIN1 -DKBDFLAGS=0x1F
# KEYBOARD = -DKBD_FR -DKBDFLAGS=0
-# KEYBOARD = -DKBD_FR_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_FR_LATIN1 -DKBDFLAGS=0x1F
# KEYBOARD = -DKBD_UK -DKBDFLAGS=0
# KEYBOARD = -DKBD_DK -DKBDFLAGS=0
-# KEYBOARD = -DKBD_DK_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_DK_LATIN1 -DKBDFLAGS=0x1F
# KEYBOARD = -DKBD_DVORAK -DKBDFLAGS=0
# KEYBOARD = -DKBD_SG -DKBDFLAGS=0
-# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_SG_LATIN1 -DKBDFLAGS=0x1F
# KEYBOARD = -DKBD_SF -DKBDFLAGS=0
-# KEYBOARD = -DKBD_SF_LATIN1 -DKBDFLAGS=0x9F
+# KEYBOARD = -DKBD_SF_LATIN1 -DKBDFLAGS=0x1F
# KEYBOARD = -DKBD_NO -DKBDFLAGS=0
#
@@ -139,7 +139,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile
@./makever.sh
- @echo \#define UTS_RELEASE \"0.99.pl7-`cat .version`\" > tools/version.h
+ @echo \#define UTS_RELEASE \"0.99.pl7A-`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
@@ -232,9 +232,9 @@ clean:
mrproper: clean
rm -f include/linux/autoconf.h tools/version.h
rm -f .version .config*
- rm -f `find . -name .depend -print`
+ rm -f .depend `find . -name .depend -print`
-backup: clean
+backup: mrproper
cd .. && tar cf - linux | gzip -9 > backup.z
sync
diff --git a/config.in b/config.in
index 1ea8c9d..5c6ffb3 100644
--- a/config.in
+++ b/config.in
@@ -4,6 +4,8 @@ Kernel math emulation
CONFIG_MATH_EMULATION y/n n
Normal harddisk support
CONFIG_BLK_DEV_HD y/n y
+XT harddisk support
+CONFIG_BLK_DEV_XD y/n n
TCP/IP
CONFIG_TCPIP y/n y
Kernel profiling support
diff --git a/fs/buffer.c b/fs/buffer.c
index fac233b..fce0733 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/locks.h>
+#include <linux/errno.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -102,6 +103,11 @@ int sys_sync(void)
return 0;
}
+int sys_fsync(int fd)
+{
+ return -ENOSYS;
+}
+
void invalidate_buffers(dev_t dev)
{
int i;
@@ -358,7 +364,7 @@ repeat:
if (bh->b_count || bh->b_size != size)
goto repeat;
if (bh->b_dirt) {
- sync_buffers(bh->b_dev);
+ sync_buffers(0);
goto repeat;
}
/* NOTE!! While we slept waiting for this block, somebody else might */
diff --git a/fs/exec.c b/fs/exec.c
index 15a3e11..44ec13b 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -460,7 +460,7 @@ restart_interp:
}
i = inode->i_mode;
if (IS_NOSUID(inode) && (((i & S_ISUID) && inode->i_uid != current->
- euid) || ((i & S_ISGID) && inode->i_gid != current->egid)) &&
+ euid) || ((i & S_ISGID) && !in_group_p(inode->i_gid))) &&
!suser()) {
retval = -EPERM;
goto exec_error2;
diff --git a/fs/ext/symlink.c b/fs/ext/symlink.c
index 8d46ce1..94d148e 100644
--- a/fs/ext/symlink.c
+++ b/fs/ext/symlink.c
@@ -48,7 +48,6 @@ static int ext_follow_link(struct inode * dir, struct inode * inode,
int flag, int mode, struct inode ** res_inode)
{
int error;
- unsigned short fs;
struct buffer_head * bh;
*res_inode = NULL;
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index a902655..e7e9702 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -376,6 +376,7 @@ static int empty_dir(struct inode * inode)
return 1;
info = &inode->i_sb->u.minix_sb;
block = 0;
+ bh = NULL;
offset = 2*info->s_dirsize;
if (inode->i_size & (info->s_dirsize-1))
goto bad_dir;
diff --git a/fs/msdos/dir.c b/fs/msdos/dir.c
index 12a5a45..90415ce 100644
--- a/fs/msdos/dir.c
+++ b/fs/msdos/dir.c
@@ -1,19 +1,19 @@
/*
* linux/fs/msdos/dir.c
*
- * Written 1992 by Werner Almesberger
+ * Written 1992,1993 by Werner Almesberger
*
* MS-DOS directory handling functions
*/
#include <asm/segment.h>
-#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/msdos_fs.h>
#include <linux/errno.h>
#include <linux/stat.h>
+
static int msdos_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
{
return -EISDIR;
@@ -22,6 +22,7 @@ static int msdos_dir_read(struct inode * inode,struct file * filp, char * buf,in
static int msdos_readdir(struct inode *inode,struct file *filp,
struct dirent *dirent,int count);
+
static struct file_operations msdos_dir_operations = {
NULL, /* lseek - default */
msdos_dir_read, /* read */
@@ -78,8 +79,7 @@ static int msdos_readdir(struct inode *inode,struct file *filp,
if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT;
bh = NULL;
while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) {
- if (de->name[0] && ((unsigned char *) (de->name))[0] !=
- DELETED_FLAG && !(de->attr & ATTR_VOLUME)) {
+ if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
for (i = last = 0; i < 8; i++) {
if (!(c = de->name[i])) break;
if (c >= 'A' && c <= 'Z') c += 32;
diff --git a/fs/msdos/fat.c b/fs/msdos/fat.c
index 8e766c1..a1c0fa7 100644
--- a/fs/msdos/fat.c
+++ b/fs/msdos/fat.c
@@ -1,7 +1,7 @@
/*
* linux/fs/msdos/fat.c
*
- * Written 1992 by Werner Almesberger
+ * Written 1992,1993 by Werner Almesberger
*/
#include <linux/msdos_fs.h>
@@ -22,6 +22,7 @@ int fat_access(struct super_block *sb,int this,int new_value)
void *data,*data2,*c_data,*c_data2;
int first,last,next,copy;
+ if ((unsigned) (this-2) >= MSDOS_SB(sb)->clusters) return 0;
if (MSDOS_SB(sb)->fat_bits == 16) first = last = this*2;
else {
first = this*3/2;
@@ -46,9 +47,9 @@ int fat_access(struct super_block *sb,int this,int new_value)
}
if (MSDOS_SB(sb)->fat_bits == 16) {
p_first = p_last = NULL; /* GCC needs that stuff */
- next = ((unsigned short *) data)[(first & (SECTOR_SIZE-1))
- >> 1];
- if (next >= 0xfff8) next = -1;
+ next = CF_LE_W(((unsigned short *) data)[(first &
+ (SECTOR_SIZE-1)) >> 1]);
+ if (next >= 0xfff7) next = -1;
}
else {
p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)];
@@ -56,12 +57,12 @@ int fat_access(struct super_block *sb,int this,int new_value)
(SECTOR_SIZE-1)];
if (this & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
else next = (*p_first+(*p_last << 8)) & 0xfff;
- if (next >= 0xff8) next = -1;
+ if (next >= 0xff7) next = -1;
}
if (new_value != -1) {
if (MSDOS_SB(sb)->fat_bits == 16)
((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >>
- 1] = new_value;
+ 1] = CT_LE_W(new_value);
else {
if (this & 1) {
*p_first = (*p_first & 0xf) | (new_value << 4);
@@ -167,8 +168,11 @@ printk("cache add: <%d,%d> %d (%d)\n",inode->i_dev,inode->i_ino,f_clu,d_clu);
for (walk = fat_cache; walk->next; walk = (last = walk)->next)
if (inode->i_dev == walk->device && walk->ino == inode->i_ino &&
walk->file_cluster == f_clu) {
- if (walk->disk_cluster != d_clu)
- panic("FAT cache corruption");
+ if (walk->disk_cluster != d_clu) {
+ printk("FAT cache corruption");
+ cache_inval_inode(inode);
+ return;
+ }
/* update LRU */
if (last == NULL) return;
last->next = walk->next;
@@ -226,10 +230,7 @@ int get_cluster(struct inode *inode,int cluster)
if ((this = fat_access(inode->i_sb,this,-1)) == -1) return 0;
if (!this) return 0;
}
- if (!(MSDOS_I(inode)->i_busy && inode->i_nlink))
- cache_add(inode,cluster,this);
- /* don't add clusters of moved files, because we can't invalidate them
- when this inode is returned. */
+ cache_add(inode,cluster,this);
return this;
}
@@ -278,8 +279,10 @@ int fat_free(struct inode *inode,int skip)
}
lock_fat(inode->i_sb);
while (this != -1) {
- if (!(this = fat_access(inode->i_sb,this,0)))
- panic("fat_free: deleting beyond EOF");
+ if (!(this = fat_access(inode->i_sb,this,0))) {
+ fs_panic(inode->i_sb,"fat_free: deleting beyond EOF");
+ break;
+ }
if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
MSDOS_SB(inode->i_sb)->free_clusters++;
inode->i_blocks -= MSDOS_SB(inode->i_sb)->cluster_size;
diff --git a/fs/msdos/file.c b/fs/msdos/file.c
index ec446fb..afddf81 100644
--- a/fs/msdos/file.c
+++ b/fs/msdos/file.c
@@ -1,7 +1,7 @@
/*
* linux/fs/msdos/file.c
*
- * Written 1992 by Werner Almesberger
+ * Written 1992,1993 by Werner Almesberger
*
* MS-DOS regular file handling primitives
*/
diff --git a/fs/msdos/inode.c b/fs/msdos/inode.c
index bd5b7d8..c19df60 100644
--- a/fs/msdos/inode.c
+++ b/fs/msdos/inode.c
@@ -1,7 +1,7 @@
/*
* linux/fs/msdos/inode.c
*
- * Written 1992 by Werner Almesberger
+ * Written 1992,1993 by Werner Almesberger
*/
#include <linux/msdos_fs.h>
@@ -15,22 +15,28 @@
#include <asm/segment.h>
+
void msdos_put_inode(struct inode *inode)
{
struct inode *depend;
+ struct super_block *sb;
- if (inode->i_nlink)
+ if (inode->i_nlink) {
+ if (MSDOS_I(inode)->i_busy) cache_inval_inode(inode);
return;
+ }
inode->i_size = 0;
msdos_truncate(inode);
depend = MSDOS_I(inode)->i_depend;
+ sb = inode->i_sb;
clear_inode(inode);
if (depend) {
if (MSDOS_I(depend)->i_old != inode) {
- printk("Invalid link (0x%X): expected 0x%X, got "
- "0x%X\n",(int) depend,(int) inode,(int)
- MSDOS_I(depend)->i_old);
- panic("That's fatal");
+ printk("Invalid link (0x%X): expected 0x%X, got 0x%X\n",
+ (int) depend,(int) inode,(int) MSDOS_I(depend)->
+ i_old);
+ fs_panic(sb,"...");
+ return;
}
MSDOS_I(depend)->i_old = NULL;
iput(depend);
@@ -50,7 +56,7 @@ void msdos_put_super(struct super_block *sb)
static struct super_operations msdos_sops = {
msdos_read_inode,
- NULL,
+ msdos_notify_change,
msdos_write_inode,
msdos_put_inode,
msdos_put_super,
@@ -59,7 +65,8 @@ static struct super_operations msdos_sops = {
};
-static int parse_options(char *options,char *check,char *conversion,uid_t *uid, gid_t *gid, int *umask)
+static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
+ gid_t *gid,int *umask,int *debug,int *fat)
{
char *this,*value;
@@ -68,6 +75,7 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
*uid = current->uid;
*gid = current->gid;
*umask = current->umask;
+ *debug = *fat = 0;
if (!options) return 1;
for (this = strtok(options,","); this; this = strtok(NULL,",")) {
if ((value = strchr(this,'=')) != NULL)
@@ -109,6 +117,17 @@ static int parse_options(char *options,char *check,char *conversion,uid_t *uid,
if (*value)
return 0;
}
+ else if (!strcmp(this,"debug")) {
+ if (value) return 0;
+ *debug = 1;
+ }
+ else if (!strcmp(this,"fat")) {
+ if (!value || !*value)
+ return 0;
+ *fat = simple_strtoul(value,&value,0);
+ if (*value || (*fat != 12 && *fat != 16))
+ return 0;
+ }
else return 0;
}
return 1;
@@ -121,13 +140,15 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
{
struct buffer_head *bh;
struct msdos_boot_sector *b;
- int data_sectors;
+ int data_sectors,logical_sector_size,sector_mult;
+ int debug,error,fat;
char check,conversion;
uid_t uid;
gid_t gid;
int umask;
- if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask)) {
+ if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask,
+ &debug,&fat)) {
s->s_dev = 0;
return NULL;
}
@@ -142,29 +163,64 @@ struct super_block *msdos_read_super(struct super_block *s,void *data)
}
b = (struct msdos_boot_sector *) bh->b_data;
s->s_blocksize = 1024; /* we cannot handle anything else yet */
- MSDOS_SB(s)->cluster_size = b->cluster_size;
+
+/*
+ * The DOS3 partition size limit is *not* 32M as many people think.
+ * Instead, it is 64K sectors (with the usual sector size being
+ * 512 bytes, leading to a 32M limit).
+ *
+ * DOS 3 partition managers got around this problem by faking a
+ * larger sector size, ie treating multiple physical sectors as
+ * a single logical sector.
+ *
+ * We can accommodate this scheme by adjusting our cluster size,
+ * fat_start, and data_start by an appropriate value.
+ *
+ * (by Drew Eckhardt)
+ */
+
+#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0)
+ /* don't divide by zero */
+
+ logical_sector_size = CF_LE_W(*(unsigned short *) &b->sector_size);
+ sector_mult = logical_sector_size >> SECTOR_BITS;
+ MSDOS_SB(s)->cluster_size = b->cluster_size*sector_mult;
MSDOS_SB(s)->fats = b->fats;
- MSDOS_SB(s)->fat_start = b->reserved;
- MSDOS_SB(s)->fat_length = b->fat_length;
- MSDOS_SB(s)->dir_start = b->reserved+b->fats*b->fat_length;
- MSDOS_SB(s)->dir_entries = *((unsigned short *) &b->dir_entries);
- MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+((MSDOS_SB(s)->
- dir_entries << 5) >> 9);
- data_sectors = (*((unsigned short *) &b->sectors) ? *((unsigned short *)
- &b->sectors) : b->total_sect)-MSDOS_SB(s)->data_start;
- MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/b->cluster_size :
- 0;
- MSDOS_SB(s)->fat_bits = MSDOS_SB(s)->clusters > MSDOS_FAT12 ? 16 : 12;
- brelse(bh);
-printk("[MS-DOS FS Rel. alpha.8, FAT %d, check=%c, conv=%c, uid=%d, gid=%d, umask=%03o]\n",
- MSDOS_SB(s)->fat_bits,check,conversion,uid,gid,umask);
-printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\n",
- b->media,MSDOS_SB(s)->cluster_size,MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,
- MSDOS_SB(s)->fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
- MSDOS_SB(s)->data_start,*(unsigned short *) &b->sectors,b->total_sect);
- if (!MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries & (MSDOS_DPS-1))
+ MSDOS_SB(s)->fat_start = CF_LE_W(b->reserved)*sector_mult;
+ MSDOS_SB(s)->fat_length = CF_LE_W(b->fat_length)*sector_mult;
+ MSDOS_SB(s)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W(
+ b->fat_length))*sector_mult;
+ MSDOS_SB(s)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries
+ ));
+ MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+ROUND_TO_MULTIPLE((
+ MSDOS_SB(s)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS,
+ sector_mult);
+ data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ?
+ CF_LE_W(*((unsigned short *) &b->sectors)) :
+ CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(s)->data_start;
+ MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/b->cluster_size/
+ sector_mult : 0;
+ MSDOS_SB(s)->fat_bits = fat ? fat : MSDOS_SB(s)->clusters > MSDOS_FAT12
+ ? 16 : 12;
+ error = !MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries & (MSDOS_DPS-1))
|| !b->cluster_size || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)->
- fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits) {
+ fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits || !sector_mult ||
+ (logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track ||
+ !b->heads;
+ brelse(bh);
+ if (error || debug) {
+ printk("[MS-DOS FS Rel. alpha.10,FAT %d,check=%c,conv=%c,"
+ "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(s)->fat_bits,check,
+ conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(s)) ? ",
+ bmap" : "");
+ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
+ "se=%d,ts=%d,ls=%d]\n",b->media,MSDOS_SB(s)->cluster_size,
+ MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,MSDOS_SB(s)->
+ fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries,
+ MSDOS_SB(s)->data_start,CF_LE_W(*(unsigned short *) &b->
+ sectors),b->total_sect,logical_sector_size);
+ }
+ if (error) {
s->s_dev = 0;
printk("Unsupported FS parameters\n");
return NULL;
@@ -180,6 +236,7 @@ printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,se=%d,ts=%d]\n",
MSDOS_SB(s)->free_clusters = -1; /* don't know yet */
MSDOS_SB(s)->fat_wait = NULL;
MSDOS_SB(s)->fat_lock = 0;
+ MSDOS_SB(s)->prev_free = 0;
if (!(s->s_mounted = iget(s,MSDOS_ROOT_INO))) {
s->s_dev = 0;
printk("get root inode failed\n");
@@ -260,16 +317,18 @@ void msdos_read_inode(struct inode *inode)
inode->i_mtime = inode->i_atime = inode->i_ctime = 0;
return;
}
- if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS, BLOCK_SIZE)))
- panic("unable to read i-node block");
+ if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS,
+ BLOCK_SIZE))) {
+ printk("dev = 0x%04X, ino = %d\n",inode->i_dev,inode->i_ino);
+ panic("msdos_read_inode: unable to read i-node block");
+ }
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
[inode->i_ino & (MSDOS_DPB-1)];
- if ((raw_entry->attr & ATTR_DIR) && *raw_entry->name && *(unsigned char *)
- raw_entry->name != DELETED_FLAG) {
+ if ((raw_entry->attr & ATTR_DIR) && !IS_FREE(raw_entry->name)) {
inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0777 &
~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR;
inode->i_op = &msdos_dir_inode_operations;
- MSDOS_I(inode)->i_start = raw_entry->start;
+ MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
inode->i_nlink = msdos_subdirs(inode);
/* includes .., compensating for "self" */
#ifdef DEBUG
@@ -279,7 +338,7 @@ void msdos_read_inode(struct inode *inode)
}
#endif
inode->i_size = 0;
- if ((this = raw_entry->start) != 0)
+ if ((this = CF_LE_W(raw_entry->start)) != 0)
while (this != -1) {
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->
i_sb)->cluster_size;
@@ -289,14 +348,15 @@ void msdos_read_inode(struct inode *inode)
}
}
else {
- inode->i_mode = MSDOS_MKMODE(raw_entry->attr,0666 &
- ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFREG;
+ inode->i_mode = MSDOS_MKMODE(raw_entry->attr,(IS_NOEXEC(inode)
+ ? 0666 : 0777) & ~MSDOS_SB(inode->i_sb)->fs_umask) |
+ S_IFREG;
inode->i_op = MSDOS_CAN_BMAP(MSDOS_SB(inode->i_sb)) ?
&msdos_file_inode_operations :
&msdos_file_inode_operations_no_bmap;
- MSDOS_I(inode)->i_start = raw_entry->start;
+ MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start);
inode->i_nlink = 1;
- inode->i_size = raw_entry->size;
+ inode->i_size = CF_LE_L(raw_entry->size);
}
MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->conversion,
raw_entry->ext);
@@ -306,7 +366,7 @@ void msdos_read_inode(struct inode *inode)
inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
inode->i_blksize*MSDOS_SB(inode->i_sb)->cluster_size;
inode->i_mtime = inode->i_atime = inode->i_ctime =
- date_dos2unix(raw_entry->time,raw_entry->date);
+ date_dos2unix(CF_LE_W(raw_entry->time),CF_LE_W(raw_entry->date));
brelse(bh);
}
@@ -318,8 +378,11 @@ void msdos_write_inode(struct inode *inode)
inode->i_dirt = 0;
if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return;
- if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS, BLOCK_SIZE)))
- panic("unable to read i-node block");
+ if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS,
+ BLOCK_SIZE))) {
+ printk("dev = 0x%04X, ino = %d\n",inode->i_dev,inode->i_ino);
+ panic("msdos_write_inode: unable to read i-node block");
+ }
raw_entry = &((struct msdos_dir_entry *) (bh->b_data))
[inode->i_ino & (MSDOS_DPB-1)];
if (S_ISDIR(inode->i_mode)) {
@@ -328,12 +391,41 @@ void msdos_write_inode(struct inode *inode)
}
else {
raw_entry->attr = ATTR_NONE;
- raw_entry->size = inode->i_size;
+ raw_entry->size = CT_LE_L(inode->i_size);
}
raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) |
MSDOS_I(inode)->i_attrs;
- raw_entry->start = MSDOS_I(inode)->i_start;
+ raw_entry->start = CT_LE_L(MSDOS_I(inode)->i_start);
date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date);
+ raw_entry->time = CT_LE_W(raw_entry->time);
+ raw_entry->date = CT_LE_W(raw_entry->date);
bh->b_dirt = 1;
brelse(bh);
}
+
+
+int msdos_notify_change(int flags,struct inode *inode)
+{
+ int error;
+
+ error = 0;
+ if ((flags & NOTIFY_UIDGID) && (inode->i_uid != MSDOS_SB(inode->i_sb)->
+ fs_uid || inode->i_gid != MSDOS_SB(inode->i_sb)->fs_gid)) {
+ inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid;
+ inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid;
+ error = -EPERM;
+ }
+ if (!(flags & NOTIFY_MODE))
+ return error;
+ if (inode->i_mode & ~MSDOS_VALID_MODE) {
+ inode->i_mode &= MSDOS_VALID_MODE;
+ error = -EPERM;
+ }
+ if (IS_NOEXEC(inode) && !S_ISDIR(inode->i_mode))
+ inode->i_mode &= S_IFMT | 0666;
+ else inode->i_mode |= 0111;
+ inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU
+ & ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IRUSR) >> 6)*0111)) &
+ ~MSDOS_SB(inode->i_sb)->fs_umask;
+ return error;
+}
diff --git a/fs/msdos/misc.c b/fs/msdos/misc.c
index e75f0f5..6f1aef5 100644
--- a/fs/msdos/misc.c
+++ b/fs/msdos/misc.c
@@ -1,9 +1,10 @@
/*
* linux/fs/msdos/misc.c
*
- * Written 1992 by Werner Almesberger
+ * Written 1992,1993 by Werner Almesberger
*/
+#include <linux/fs.h>
#include <linux/msdos_fs.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -11,14 +12,38 @@
#include <linux/string.h>
#include <linux/stat.h>
+/* Well-known binary file extensions */
+
static char bin_extensions[] =
- "EXECOMAPPSYSOVLOBJLIB" /* program code */
- "ARCZIPLHALZHZOOTARZ ARJTZ " /* common archivers */
- "GIFBMPTIFGL JPGPCX" /* graphics */
- "TFMVF GF PK PXLDVI"; /* TeX */
+ "EXECOMAPPSYSOVLOBJLIB" /* program code */
+ "ARCZIPLHALZHZOOTARZ ARJ" /* common archivers */
+ "TZ TAZTZPTPZ" /* abbreviations of tar.Z and tar.zip */
+ "GIFBMPTIFGL JPGPCX" /* graphics */
+ "TFMVF GF PK PXLDVI"; /* TeX */
-/* Select binary/text conversion */
+/*
+ * fs_panic reports a severe file system problem and sets the file system
+ * read-only. The file system can be made writable again by remounting it.
+ */
+
+void fs_panic(struct super_block *s,char *msg)
+{
+ int not_ro;
+
+ not_ro = !(s->s_flags & MS_RDONLY);
+ if (not_ro) s->s_flags |= MS_RDONLY;
+ printk("Filesystem panic (dev 0x%04X, mounted on 0x%04X:%d)\n %s\n",
+ s->s_dev,s->s_covered->i_dev,s->s_covered->i_ino,msg);
+ if (not_ro)
+ printk(" File system has been set read-only\n");
+}
+
+
+/*
+ * is_binary selects optional text conversion based on the conversion mode and
+ * the extension part of the file name.
+ */
int is_binary(char conversion,char *extension)
{
@@ -76,35 +101,34 @@ void unlock_fat(struct super_block *sb)
}
+/*
+ * msdos_add_cluster tries to allocate a new cluster and adds it to the file
+ * represented by inode. The cluster is zero-initialized.
+ */
+
int msdos_add_cluster(struct inode *inode)
{
- static struct wait_queue *wait = NULL;
- static int lock = 0;
- static int previous = 0; /* works best if one FS is being used */
int count,this,limit,last,current,sector;
void *data;
struct buffer_head *bh;
if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC;
- while (lock) sleep_on(&wait);
- lock = 1;
lock_fat(inode->i_sb);
limit = MSDOS_SB(inode->i_sb)->clusters;
this = limit; /* to keep GCC happy */
for (count = 0; count < limit; count++) {
- this = ((count+previous) % limit)+2;
+ this = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2;
if (fat_access(inode->i_sb,this,-1) == 0) break;
}
#ifdef DEBUG
printk("free cluster: %d\n",this);
#endif
- previous = (count+previous+1) % limit;
+ MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)->
+ prev_free+1) % limit;
if (count >= limit) {
MSDOS_SB(inode->i_sb)->free_clusters = 0;
unlock_fat(inode->i_sb);
- lock = 0;
- wake_up(&wait);
return -ENOSPC;
}
fat_access(inode->i_sb,this,MSDOS_SB(inode->i_sb)->fat_bits == 12 ?
@@ -112,8 +136,6 @@ printk("free cluster: %d\n",this);
if (MSDOS_SB(inode->i_sb)->free_clusters != -1)
MSDOS_SB(inode->i_sb)->free_clusters--;
unlock_fat(inode->i_sb);
- lock = 0;
- wake_up(&wait);
#ifdef DEBUG
printk("set to %x\n",fat_access(inode->i_sb,this,-1));
#endif
@@ -122,8 +144,10 @@ printk("set to %x\n",fat_access(inode->i_sb,this,-1));
cache_lookup(inode,0x7fffffff,&last,&current);
while (current && current != -1)
if (!(current = fat_access(inode->i_sb,
- last = current,-1)))
- panic("File without EOF");
+ last = current,-1))) {
+ fs_panic(inode->i_sb,"File without EOF");
+ return -ENOSPC;
+ }
}
#ifdef DEBUG
printk("last = %d\n",last);
@@ -145,7 +169,8 @@ printk("zeroing sector %d\n",sector);
#endif
if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 &&
!(sector & 1)) {
- if (!(bh = getblk(inode->i_dev,sector >> 1, BLOCK_SIZE)))
+ if (!(bh = getblk(inode->i_dev,sector >> 1,
+ BLOCK_SIZE)))
printk("getblk failed\n");
else {
memset(bh->b_data,0,BLOCK_SIZE);
@@ -154,7 +179,8 @@ printk("zeroing sector %d\n",sector);
current++;
}
else {
- if (!(bh = msdos_sread(inode->i_dev,sector,&data)))
+ if (!(bh = msdos_sread(inode->i_dev,sector,
+ &data)))
printk("msdos_sread failed\n");
else memset(data,0,SECTOR_SIZE);
}
@@ -165,8 +191,11 @@ printk("zeroing sector %d\n",sector);
}
inode->i_blocks += MSDOS_SB(inode->i_sb)->cluster_size;
if (S_ISDIR(inode->i_mode)) {
- if (inode->i_size & (SECTOR_SIZE-1))
- panic("Odd directory size");
+ if (inode->i_size & (SECTOR_SIZE-1)) {
+ fs_panic(inode->i_sb,"Odd directory size");
+ inode->i_size = (inode->i_size+SECTOR_SIZE) &
+ ~(SECTOR_SIZE-1);
+ }
inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)->
cluster_size;
#ifdef DEBUG
@@ -246,7 +275,7 @@ int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1)
return -1;
if (!sector)
- return -1; /* FAT error ... */
+ return -1; /* beyond EOF */
*pos += sizeof(struct msdos_dir_entry);
if (*bh)
brelse(*bh);
@@ -262,101 +291,119 @@ int msdos_get_entry(struct inode *dir,int *pos,struct buffer_head **bh,
}
-/* Scans a directory for a given file (name points to its formatted name) or
- for an empty directory slot (name is NULL). Returns the inode number. */
-
-int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
- struct msdos_dir_entry **res_de,int *ino)
-{
- int pos;
- struct msdos_dir_entry *de;
- struct inode *inode;
-
- pos = 0;
- *res_bh = NULL;
- while ((*ino = msdos_get_entry(dir,&pos,res_bh,&de)) > -1) {
- if (name) {
- if (de->name[0] && ((unsigned char *) (de->name))[0]
- != DELETED_FLAG && !(de->attr & ATTR_VOLUME) &&
- !strncmp(de->name,name,MSDOS_NAME)) break;
- }
- else if (!de->name[0] || ((unsigned char *) (de->name))[0] ==
- DELETED_FLAG) {
- if (!(inode = iget(dir->i_sb,*ino))) break;
- if (!MSDOS_I(inode)->i_busy) {
- iput(inode);
- break;
- }
- /* skip deleted files that haven't been closed yet */
- iput(inode);
- }
- }
- if (*ino == -1) {
- if (*res_bh) brelse(*res_bh);
- *res_bh = NULL;
- return name ? -ENOENT : -ENOSPC;
- }
- *res_de = de;
- return 0;
-}
-
-
-/* Now an ugly part: this set of directory scan routines works on clusters
- rather than on inodes and sectors. They are necessary to locate the '..'
- directory "inode". raw_found operates in three modes: if name is non-NULL,
- the directory is scanned for an entry with that name. If ino is non-NULL,
- the directory is scanned for an entry whose data starts at *number. If name
- and ino are NULL, the directory entries are counted in *number. */
+/*
+ * Now an ugly part: this set of directory scan routines works on clusters
+ * rather than on inodes and sectors. They are necessary to locate the '..'
+ * directory "inode". raw_scan_sector operates in four modes:
+ *
+ * name number ino action
+ * -------- -------- -------- -------------------------------------------------
+ * non-NULL - X Find an entry with that name
+ * NULL non-NULL non-NULL Find an entry whose data starts at *number
+ * NULL non-NULL NULL Count subdirectories in *number. (*)
+ * NULL NULL non-NULL Find an empty entry
+ *
+ * (*) The return code should be ignored. It DOES NOT indicate success or
+ * failure. *number has to be initialized to zero.
+ *
+ * - = not used, X = a value is returned unless NULL
+ *
+ * If res_bh is non-NULL, the buffer is not deallocated but returned to the
+ * caller on success. res_de is set accordingly.
+ *
+ * If cont is non-zero, raw_found continues with the entry after the one
+ * res_bh/res_de point to.
+ */
-static int raw_found(struct super_block *sb,int sector,char *name,int *number,
- int *ino)
+#define RSS_NAME /* search for name */ \
+ done = !strncmp(data[entry].name,name,MSDOS_NAME) && \
+ !(data[entry].attr & ATTR_VOLUME);
+
+#define RSS_START /* search for start cluster */ \
+ done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number;
+
+#define RSS_FREE /* search for free entry */ \
+ { \
+ done = IS_FREE(data[entry].name); \
+ if (done) { \
+ inode = iget(sb,sector*MSDOS_DPS+entry); \
+ if (inode) { \
+ /* Directory slots of busy deleted files aren't available yet. */ \
+ done = !MSDOS_I(inode)->i_busy; \
+ iput(inode); \
+ } \
+ } \
+ }
+
+#define RSS_COUNT /* count subdirectories */ \
+ { \
+ done = 0; \
+ if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \
+ (*number)++; \
+ }
+
+static int raw_scan_sector(struct super_block *sb,int sector,char *name,
+ int *number,int *ino,struct buffer_head **res_bh,
+ struct msdos_dir_entry **res_de)
{
struct buffer_head *bh;
struct msdos_dir_entry *data;
+ struct inode *inode;
int entry,start,done;
if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO;
for (entry = 0; entry < MSDOS_DPS; entry++) {
- if (name) done = !strncmp(data[entry].name,name,MSDOS_NAME);
+ if (name) RSS_NAME
else {
- if (ino)
- done = *(unsigned char *) data[entry].name !=
- DELETED_FLAG && data[entry].start ==
- *number;
+ if (!ino) RSS_COUNT
else {
- done = 0;
- if (*data[entry].name && *(unsigned char *)
- data[entry].name != DELETED_FLAG &&
- (data[entry].attr & ATTR_DIR)) (*number)++;
+ if (number) RSS_START
+ else RSS_FREE
}
}
if (done) {
if (ino) *ino = sector*MSDOS_DPS+entry;
- start = data[entry].start;
- brelse(bh);
+ start = CF_LE_W(data[entry].start);
+ if (!res_bh) brelse(bh);
+ else {
+ *res_bh = bh;
+ *res_de = &data[entry];
+ }
return start;
}
}
brelse(bh);
- return -1;
+ return -ENOENT;
}
-static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino)
+/*
+ * raw_scan_root performs raw_scan_sector on the root directory until the
+ * requested entry is found or the end of the directory is reached.
+ */
+
+static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino,
+ struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
{
int count,cluster;
for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) {
- if ((cluster = raw_found(sb,MSDOS_SB(sb)->dir_start+count,name,
- number,ino)) >= 0) return cluster;
+ if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count,
+ name,number,ino,res_bh,res_de)) >= 0) return cluster;
}
return -ENOENT;
}
+/*
+ * raw_scan_nonroot performs raw_scan_sector on a non-root directory until the
+ * requested entry is found or the end of the directory is reached.
+ */
+
static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
- int *number,int *ino)
+ int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry
+ **res_de)
{
int count,cluster;
@@ -365,11 +412,15 @@ static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
#endif
do {
for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) {
- if ((cluster = raw_found(sb,(start-2)*MSDOS_SB(sb)->
- cluster_size+MSDOS_SB(sb)->data_start+count,name,
- number,ino)) >= 0) return cluster;
+ if ((cluster = raw_scan_sector(sb,(start-2)*
+ MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+
+ count,name,number,ino,res_bh,res_de)) >= 0)
+ return cluster;
+ }
+ if (!(start = fat_access(sb,start,-1))) {
+ fs_panic(sb,"FAT error");
+ break;
}
- if (!(start = fat_access(sb,start,-1))) panic("FAT error");
#ifdef DEBUG
printk("next start: %d\n",start);
#endif
@@ -379,34 +430,50 @@ static int raw_scan_nonroot(struct super_block *sb,int start,char *name,
}
-static int raw_scan(struct super_block *sb,int start,char *name,int number,
- int *ino)
+/*
+ * raw_scan performs raw_scan_sector on any sector.
+ *
+ * NOTE: raw_scan must not be used on a directory that is is the process of
+ * being created.
+ */
+
+static int raw_scan(struct super_block *sb,int start,char *name,int *number,
+ int *ino,struct buffer_head **res_bh,struct msdos_dir_entry **res_de)
{
- if (start) return raw_scan_nonroot(sb,start,name,&number,ino);
- else return raw_scan_root(sb,name,&number,ino);
+ if (start)
+ return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de);
+ else return raw_scan_root(sb,name,number,ino,res_bh,res_de);
}
+/*
+ * msdos_parent_ino returns the inode number of the parent directory of dir.
+ * File creation has to be deferred while msdos_parent_ino is running to
+ * prevent renames.
+ */
+
int msdos_parent_ino(struct inode *dir,int locked)
{
+ static int zero = 0;
int error,current,prev,this;
if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i");
if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino;
if (!locked) lock_creation(); /* prevent renames */
- if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,0,
- NULL)) < 0) {
+ if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT,
+ &zero,NULL,NULL,NULL)) < 0) {
if (!locked) unlock_creation();
return current;
}
if (!current) this = MSDOS_ROOT_INO;
else {
- if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,0,NULL)) <
- 0) {
+ if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,&zero,NULL,
+ NULL,NULL)) < 0) {
if (!locked) unlock_creation();
return prev;
}
- if ((error = raw_scan(dir->i_sb,prev,NULL,current,&this)) < 0) {
+ if ((error = raw_scan(dir->i_sb,prev,NULL,&current,&this,NULL,
+ NULL)) < 0) {
if (!locked) unlock_creation();
return error;
}
@@ -416,17 +483,41 @@ int msdos_parent_ino(struct inode *dir,int locked)
}
+/*
+ * msdos_subdirs counts the number of sub-directories of dir. It can be run
+ * on directories being created.
+ */
+
int msdos_subdirs(struct inode *dir)
{
int count;
count = 0;
if (dir->i_ino == MSDOS_ROOT_INO)
- (void) raw_scan_root(dir->i_sb,NULL,&count,NULL);
+ (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL);
else {
if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */
else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start,
- NULL,&count,NULL);
+ NULL,&count,NULL,NULL,NULL);
}
return count;
}
+
+
+/*
+ * Scans a directory for a given file (name points to its formatted name) or
+ * for an empty directory slot (name is NULL). Returns an error code or zero.
+ */
+
+int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh,
+ struct msdos_dir_entry **res_de,int *ino)
+{
+ int res;
+
+ if (name)
+ res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,name,NULL,ino,
+ res_bh,res_de);
+ else res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,NULL,NULL,ino,
+ res_bh,res_de);
+ return res < 0 ? res : 0;
+}
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 79988a4..66b9ec7 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -1,7 +1,7 @@
/*
* linux/fs/msdos/namei.c
*
- * Written 1992 by Werner Almesberger
+ * Written 1992,1993 by Werner Almesberger
*/
#include <asm/segment.h>
@@ -25,35 +25,33 @@ static char *reserved_names[] = {
/* Characters that are undesirable in an MS-DOS file name */
static char bad_chars[] = "*?<>|\"";
-static char bad_if_strict[] = "+=,;";
+static char bad_if_strict[] = "+=,; ";
/* Formats an MS-DOS file name. Rejects invalid names. */
-static int msdos_format_name(char conv,const char *name,int len,char *res)
+static int msdos_format_name(char conv,const char *name,int len,char *res,
+ int dot_dirs)
{
char *walk,**reserved;
char c;
int space;
- if (*(unsigned char *)name == DELETED_FLAG) return -EINVAL;
- if (name[0] == '.' && (len == 1 || (len == 2 &&
- name[1] == '.'))) {
+ if (IS_FREE(name)) return -EINVAL;
+ if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) {
+ if (!dot_dirs) return -EEXIST;
memset(res+1,' ',10);
while (len--) *res++ = '.';
return 0;
}
- space = 0; /* to make GCC happy */
+ space = 1; /* disallow names starting with a dot */
c = 0;
for (walk = res; len && walk-res < 8; walk++) {
- c = *(name++);
+ c = *name++;
len--;
if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
- if (c >= 'A' && c <= 'Z') {
- if (conv == 's') return -EINVAL;
- c += 32;
- }
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
if (c == '.') break;
space = c == ' ';
@@ -61,26 +59,22 @@ static int msdos_format_name(char conv,const char *name,int len,char *res)
}
if (space) return -EINVAL;
if (conv == 's' && len && c != '.') {
- c = *(name++);
+ c = *name++;
len--;
if (c != '.') return -EINVAL;
}
- while (c != '.' && len--) c = *(name++);
- if (walk == res) return -EINVAL;
+ while (c != '.' && len--) c = *name++;
if (c == '.') {
while (walk-res < 8) *walk++ = ' ';
while (len > 0 && walk-res < MSDOS_NAME) {
- c = *(name++);
+ c = *name++;
len--;
if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
if (conv == 's' && strchr(bad_if_strict,c))
return -EINVAL;
if (c < ' ' || c == ':' || c == '\\' || c == '.')
return -EINVAL;
- if (c >= 'A' && c <= 'Z') {
- if (conv == 's') return -EINVAL;
- c += 32;
- }
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
space = c == ' ';
*walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
}
@@ -103,7 +97,7 @@ static int msdos_find(struct inode *dir,const char *name,int len,
int res;
if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
- msdos_name)) < 0) return res;
+ msdos_name,1)) < 0) return res;
return msdos_scan(dir,msdos_name,bh,de,ino);
}
@@ -126,8 +120,7 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
*result = dir;
return 0;
}
- if (len == 2 && name[0] == '.' && name[1] == '.')
- {
+ if (len == 2 && name[0] == '.' && name[1] == '.') {
ino = msdos_parent_ino(dir,0);
iput(dir);
if (ino < 0) return ino;
@@ -152,8 +145,11 @@ int msdos_lookup(struct inode *dir,const char *name,int len,
while (MSDOS_I(*result)->i_old) {
next = MSDOS_I(*result)->i_old;
iput(*result);
- if (!(*result = iget(next->i_sb,next->i_ino)))
- panic("msdos_lookup: Can't happen");
+ if (!(*result = iget(next->i_sb,next->i_ino))) {
+ fs_panic(dir->i_sb,"msdos_lookup: Can't happen");
+ iput(dir);
+ return -ENOENT;
+ }
}
iput(dir);
return 0;
@@ -170,6 +166,7 @@ static int msdos_create_entry(struct inode *dir,char *name,int is_dir,
int res,ino;
if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) {
+ if (res != -ENOENT) return res;
if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC;
if ((res = msdos_add_cluster(dir)) < 0) return res;
if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res;
@@ -201,7 +198,7 @@ int msdos_create(struct inode *dir,const char *name,int len,int mode,
if (!dir) return -ENOENT;
if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
- msdos_name)) < 0) {
+ msdos_name,0)) < 0) {
iput(dir);
return res;
}
@@ -226,7 +223,7 @@ static void dump_fat(struct super_block *sb,int start)
printk("[");
while (start) {
printk("%d ",start);
- start = fat_access(sb,start,-1);
+ start = fat_access(sb,start,-1);
if (!start) {
printk("ERROR");
break;
@@ -248,7 +245,7 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
int ino,res;
if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len,
- msdos_name)) < 0) {
+ msdos_name,0)) < 0) {
iput(dir);
return res;
}
@@ -289,7 +286,8 @@ int msdos_mkdir(struct inode *dir,const char *name,int len,int mode)
return 0;
mkdir_error:
iput(inode);
- if (msdos_rmdir(dir,name,len) < 0) panic("rmdir in mkdir failed");
+ if (msdos_rmdir(dir,name,len) < 0)
+ fs_panic(dir->i_sb,"rmdir in mkdir failed");
unlock_creation();
return res;
}
@@ -304,9 +302,9 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
bh = NULL;
inode = NULL;
- res = -EINVAL;
- if (name[0] == '.' && (len == 1 || (len == 2 &&
- name[1] == '.'))) goto rmdir_done;
+ res = -EPERM;
+ if (name[0] == '.' && (len == 1 || (len == 2 && 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_sb,ino))) goto rmdir_done;
@@ -320,8 +318,7 @@ int msdos_rmdir(struct inode *dir,const char *name,int len)
pos = 0;
dbh = NULL;
while (msdos_get_entry(inode,&pos,&dbh,&dde) > -1)
- if (dde->name[0] && ((unsigned char *) dde->name)[0] !=
- DELETED_FLAG && strncmp(dde->name,MSDOS_DOT,
+ if (!IS_FREE(dde->name) && strncmp(dde->name,MSDOS_DOT,
MSDOS_NAME) && strncmp(dde->name,MSDOS_DOTDOT,
MSDOS_NAME)) goto rmdir_done;
if (dbh) brelse(dbh);
@@ -439,10 +436,13 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
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;
+ while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) <
+ 0) {
+ if (error != -ENOENT) return error;
+ error = msdos_add_cluster(new_dir);
+ if (error) return error;
+ }
+ exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0;
if (!(old_inode = iget(old_dir->i_sb,old_ino))) {
brelse(free_bh);
if (exists) brelse(new_bh);
@@ -536,9 +536,9 @@ int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
int old_ino,error;
if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check,
- old_name,old_len,old_msdos_name)) < 0) goto rename_done;
+ old_name,old_len,old_msdos_name,1)) < 0) goto rename_done;
if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check,
- new_name,new_len,new_msdos_name)) < 0) goto rename_done;
+ new_name,new_len,new_msdos_name,0)) < 0) goto rename_done;
if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de,
&old_ino)) < 0) goto rename_done;
lock_creation();
diff --git a/fs/xiafs/bitmap.c b/fs/xiafs/bitmap.c
index c85cc1e..03660d3 100644
--- a/fs/xiafs/bitmap.c
+++ b/fs/xiafs/bitmap.c
@@ -330,7 +330,8 @@ struct inode * xiafs_new_inode(struct inode * dir)
inode->i_ino = tmp;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_op = NULL;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
+ inode->i_blksize = XIAFS_ZSIZE(inode->i_sb);
return inode;
}
diff --git a/fs/xiafs/dir.c b/fs/xiafs/dir.c
index d39947c..ebd41f9 100644
--- a/fs/xiafs/dir.c
+++ b/fs/xiafs/dir.c
@@ -101,8 +101,10 @@ static int xiafs_readdir(struct inode * inode,
put_fs_long(de->d_ino,&dirent->d_ino);
put_fs_word(i,&dirent->d_reclen);
brelse(bh);
- inode->i_atime=CURRENT_TIME;
- inode->i_dirt=1;
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
return i;
}
de = (struct xiafs_direct *) (offset + bh->b_data);
@@ -113,9 +115,9 @@ static int xiafs_readdir(struct inode * inode,
return 0;
}
}
- inode->i_atime=CURRENT_TIME;
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
return 0;
}
-
-
-
diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c
index 4ccd327..4a0f34d 100644
--- a/fs/xiafs/file.c
+++ b/fs/xiafs/file.c
@@ -175,9 +175,10 @@ xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count)
if (!read)
return -EIO;
filp->f_reada = 1;
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
-
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return read;
}
@@ -239,7 +240,7 @@ xiafs_file_write(struct inode * inode, struct file * filp, char * buf, int count
bh->b_dirt = 1;
brelse(bh);
}
- inode->i_mtime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos;
inode->i_dirt = 1;
diff --git a/fs/xiafs/inode.c b/fs/xiafs/inode.c
index 823cc76..4d6ac37 100644
--- a/fs/xiafs/inode.c
+++ b/fs/xiafs/inode.c
@@ -176,8 +176,10 @@ int xiafs_bmap(struct inode * inode,int zone)
printk("XIA-FS: zone > big (%s %d)\n", WHERE_ERR);
return 0;
}
- inode->i_atime = CURRENT_TIME;
- inode->i_dirt = 1;
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
if (zone < 8)
return inode->u.xiafs_i.i_zone[zone];
zone -= 8;
@@ -236,6 +238,7 @@ repeat:
goto repeat;
}
*lp = tmp;
+ inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb);
return result;
}
@@ -279,17 +282,18 @@ repeat:
}
result = getblk(bh->b_dev, tmp, XIAFS_ZSIZE(inode->i_sb));
if (*lp) {
- xiafs_free_zone(inode->i_sb,tmp);
+ xiafs_free_zone(inode->i_sb, tmp);
brelse(result);
goto repeat;
}
*lp = tmp;
+ inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb);
bh->b_dirt = 1;
brelse(bh);
return result;
}
-struct buffer_head * xiafs_getblk(struct inode * inode, int zone, int create)
+struct buffer_head * xiafs_getblk(struct inode * inode, int zone, int create)
{
struct buffer_head * bh;
u_long prev_addr=0;
@@ -368,15 +372,16 @@ void xiafs_read_inode(struct inode * inode)
inode->i_mtime = raw_inode->i_mtime;
inode->i_atime = raw_inode->i_atime;
inode->i_ctime = raw_inode->i_ctime;
- inode->i_blocks = 0;
- inode->i_blksize = 0; /* let vfs estimate */
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_blksize = XIAFS_ZSIZE(inode->i_sb);
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+ inode->i_blocks=0;
inode->i_rdev = raw_inode->i_zone[0];
- else {
+ } else {
+ XIAFS_GET_BLOCKS(raw_inode, inode->i_blocks);
for (zone = 0; zone < 8; zone++)
- inode->u.xiafs_i.i_zone[zone] = raw_inode->i_zone[zone];
- inode->u.xiafs_i.i_ind_zone = raw_inode->i_ind_zone;
- inode->u.xiafs_i.i_dind_zone = raw_inode->i_dind_zone;
+ inode->u.xiafs_i.i_zone[zone] = raw_inode->i_zone[zone] & 0xffffff;
+ inode->u.xiafs_i.i_ind_zone = raw_inode->i_ind_zone & 0xffffff;
+ inode->u.xiafs_i.i_dind_zone = raw_inode->i_dind_zone & 0xffffff;
}
brelse(bh);
if (S_ISREG(inode->i_mode))
@@ -406,6 +411,12 @@ void xiafs_write_inode(struct inode * inode)
int zone;
ino_t ino;
+ if (IS_RDONLY (inode)) {
+ printk("XIA-FS: write_inode on a read-only filesystem (%s %d)\n", WHERE_ERR);
+ inode->i_dirt = 0;
+ return;
+ }
+
ino = inode->i_ino;
if (!ino || ino > inode->i_sb->u.xiafs_sb.s_ninodes) {
printk("XIA-FS: bad inode number (%s %d)\n", WHERE_ERR);
@@ -427,20 +438,20 @@ void xiafs_write_inode(struct inode * inode)
raw_inode->i_gid = inode->i_gid;
raw_inode->i_nlinks = inode->i_nlink;
raw_inode->i_size = inode->i_size;
- if (inode->i_ctime < inode->i_mtime)
- inode->i_ctime=inode->i_mtime;
- if (inode->i_atime < inode->i_ctime)
- inode->i_atime=inode->i_ctime;
raw_inode->i_atime = inode->i_atime;
raw_inode->i_ctime = inode->i_ctime;
raw_inode->i_mtime = inode->i_mtime;
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_zone[0] = inode->i_rdev;
else {
+ XIAFS_PUT_BLOCKS(raw_inode, inode->i_blocks);
for (zone = 0; zone < 8; zone++)
- raw_inode->i_zone[zone] = inode->u.xiafs_i.i_zone[zone];
- raw_inode->i_ind_zone = inode->u.xiafs_i.i_ind_zone;
- raw_inode->i_dind_zone = inode->u.xiafs_i.i_dind_zone;
+ raw_inode->i_zone[zone] = (raw_inode->i_zone[zone] & 0xff000000)
+ | (inode->u.xiafs_i.i_zone[zone] & 0xffffff);
+ raw_inode->i_ind_zone = (raw_inode->i_ind_zone & 0xff000000)
+ | (inode->u.xiafs_i.i_ind_zone & 0xffffff);
+ raw_inode->i_dind_zone = (raw_inode->i_dind_zone & 0xff000000)
+ | (inode->u.xiafs_i.i_dind_zone & 0xffffff);
}
inode->i_dirt=0;
bh->b_dirt=1;
diff --git a/fs/xiafs/namei.c b/fs/xiafs/namei.c
index 49703ee..faaf466 100644
--- a/fs/xiafs/namei.c
+++ b/fs/xiafs/namei.c
@@ -212,7 +212,7 @@ static struct buffer_head * xiafs_add_entry(struct inode * dir,
}
}
if (!de->d_ino && RNDUP4(namelen)+8 <= de->d_rec_len) {
- dir->i_mtime = CURRENT_TIME;
+ dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
memcpy(de->d_name, name, namelen);
de->d_name[namelen]=0;
@@ -316,7 +316,7 @@ int xiafs_mknod(struct inode *dir, const char *name, int len, int mode, int rdev
}
if (S_ISBLK(mode) || S_ISCHR(mode))
inode->i_rdev = rdev;
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
inode->i_dirt = 1;
bh = xiafs_add_entry(dir, name, len, &de, NULL);
if (!bh) {
@@ -357,7 +357,7 @@ int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode)
}
inode->i_op = &xiafs_dir_inode_operations;
inode->i_size = XIAFS_ZSIZE(dir->i_sb);
- inode->i_mtime = inode->i_atime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
dir_block = xiafs_bread(inode,0,1);
if (!dir_block) {
iput(dir);
@@ -524,7 +524,7 @@ int xiafs_rmdir(struct inode * dir, const char * name, int len)
inode->i_nlink=0;
inode->i_dirt=1;
dir->i_nlink--;
- dir->i_mtime = CURRENT_TIME;
+ dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt=1;
retval = 0;
end_rmdir:
@@ -569,10 +569,9 @@ repeat:
}
xiafs_rm_entry(de, de_pre);
bh->b_dirt = 1;
- dir->i_mtime = CURRENT_TIME;
+ dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
dir->i_dirt = 1;
inode->i_nlink--;
- inode->i_ctime = CURRENT_TIME;
inode->i_dirt = 1;
retval = 0;
end_unlink:
@@ -668,7 +667,7 @@ int xiafs_link(struct inode * oldinode, struct inode * dir,
brelse(bh);
iput(dir);
oldinode->i_nlink++;
- oldinode->i_ctime = CURRENT_TIME;
+ oldinode->i_atime = oldinode->i_ctime = CURRENT_TIME;
oldinode->i_dirt = 1;
iput(oldinode);
return 0;
diff --git a/fs/xiafs/symlink.c b/fs/xiafs/symlink.c
index cd68698..e3e963b 100644
--- a/fs/xiafs/symlink.c
+++ b/fs/xiafs/symlink.c
@@ -57,8 +57,10 @@ static int xiafs_readlink(struct inode * inode, char * buffer, int buflen)
if (buflen > BLOCK_SIZE)
buflen = BLOCK_SIZE;
bh = xiafs_bread(inode, 0, 0);
- inode->i_atime=CURRENT_TIME;
- inode->i_dirt=1;
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
iput(inode);
if (!bh)
return 0;
@@ -90,8 +92,10 @@ static int xiafs_follow_link(struct inode * dir, struct inode * inode,
*res_inode = inode;
return 0;
}
- inode->i_atime=CURRENT_TIME;
- inode->i_dirt=1;
+ if (!IS_RDONLY (inode)) {
+ inode->i_atime=CURRENT_TIME;
+ inode->i_dirt=1;
+ }
if (current->link_count > 5) {
iput(inode);
iput(dir);
diff --git a/fs/xiafs/truncate.c b/fs/xiafs/truncate.c
index e6a0d63..7b95b37 100644
--- a/fs/xiafs/truncate.c
+++ b/fs/xiafs/truncate.c
@@ -60,6 +60,7 @@ repeat:
else {
*lp = 0;
inode->i_dirt = 1;
+ inode->i_blocks-=2 << XIAFS_ZSHIFT(inode->i_sb);
xiafs_free_zone(inode->i_sb, tmp);
}
brelse(bh);
@@ -105,6 +106,7 @@ repeat:
else {
*indp = 0;
ind_bh->b_dirt = 1;
+ inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb);
xiafs_free_zone(inode->i_sb, tmp);
}
brelse(bh);
@@ -117,6 +119,7 @@ repeat:
else {
tmp = *lp;
*lp = 0;
+ inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb);
xiafs_free_zone(inode->i_sb, tmp);
}
}
@@ -166,6 +169,7 @@ repeat:
tmp = *lp;
*lp = 0;
inode->i_dirt = 1;
+ inode->i_blocks-=2 << XIAFS_ZSHIFT(inode->i_sb);
xiafs_free_zone(inode->i_sb, tmp);
}
}
@@ -189,7 +193,7 @@ void xiafs_truncate(struct inode * inode)
current->counter = 0;
schedule();
}
- inode->i_mtime = CURRENT_TIME;
+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
inode->i_dirt = 1;
}
diff --git a/fs/xiafs/xiafs_mac.h b/fs/xiafs/xiafs_mac.h
index f3cfdae..2c3509e 100644
--- a/fs/xiafs/xiafs_mac.h
+++ b/fs/xiafs/xiafs_mac.h
@@ -17,4 +17,16 @@ extern char internal_error_message[];
#define XIAFS_BITS_PER_Z_BITS(sp) (BLOCK_SIZE_BITS + 3 + XIAFS_ZSHIFT(sp))
#define XIAFS_INODES_PER_Z(sp) (_XIAFS_INODES_PER_BLOCK << XIAFS_ZSHIFT(sp))
+/* Use the most significant bytes of zone pointers to store block counter. */
+/* This is ugly, but it works. Note, We have another 7 bytes for "expension". */
+#define XIAFS_GET_BLOCKS(row_ip, blocks) \
+ blocks=((((row_ip)->i_zone[0] >> 24) & 0xff )|\
+ (((row_ip)->i_zone[1] >> 16) & 0xff00 )|\
+ (((row_ip)->i_zone[2] >> 8) & 0xff0000 ) )
+
+/* XIAFS_PUT_BLOCKS should be called before saving zone pointers */
+#define XIAFS_PUT_BLOCKS(row_ip, blocks) \
+ (row_ip)->i_zone[2]=((blocks)<< 8) & 0xff000000;\
+ (row_ip)->i_zone[1]=((blocks)<<16) & 0xff000000;\
+ (row_ip)->i_zone[0]=((blocks)<<24) & 0xff000000
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e69c24d..16ebe8d 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -95,7 +95,6 @@ extern int copy_page_tables(struct task_struct * new);
extern int unmap_page_range(unsigned long from, unsigned long size);
extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask);
extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
-extern void write_verify(unsigned long address);
extern void do_wp_page(unsigned long error_code, unsigned long address,
struct task_struct *tsk, unsigned long user_esp);
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index 12b9711..cb87458 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -6,6 +6,8 @@
*/
#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/fd.h>
#define MSDOS_ROOT_INO 1 /* == MINIX_ROOT_INO */
#define SECTOR_SIZE 512 /* sector size (bytes) */
@@ -32,6 +34,11 @@
/* attribute bits that are copied "as is" */
#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */
+#define IS_FREE(n) (!*(n) || *(unsigned char *) (n) == DELETED_FLAG || \
+ *(unsigned char *) (n) == FD_FILL_BYTE)
+
+#define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)
+ /* valid file mode bits */
#define MSDOS_SB(s) (&((s)->u.msdos_sb))
#define MSDOS_I(i) (&((i)->u.msdos_i))
@@ -40,10 +47,26 @@
#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */
#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */
-#define MSDOS_FAT12 4086 /* maximum number of clusters in a 12 bit FAT */
+#define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */
+
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ *
+ * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian, BE = big-
+ * endian, c: W = word (16 bits), L = longword (32 bits)
+ */
+
+#define CF_LE_W(v) (v)
+#define CF_LE_L(v) (v)
+#define CT_LE_W(v) (v)
+#define CT_LE_L(v) (v)
+
struct msdos_boot_sector {
- char ignored[13];
+ char ignored[3]; /* Boot strap short or near jump */
+ char system_id[8]; /* Name - can be used to special case
+ partition manager volumes */
+ unsigned char sector_size[2];/* bytes per logical sector */
unsigned char cluster_size; /* sectors/cluster */
unsigned short reserved; /* reserved sectors */
unsigned char fats; /* number of FATs */
@@ -51,8 +74,8 @@ struct msdos_boot_sector {
unsigned char sectors[2]; /* number of sectors */
unsigned char media; /* media code (unused) */
unsigned short fat_length; /* sectors/FAT */
- unsigned short secs_track; /* sectors per track (unused) */
- unsigned short heads; /* number of heads (unused) */
+ unsigned short secs_track; /* sectors per track */
+ unsigned short heads; /* number of heads */
unsigned long hidden; /* hidden sectors (unused) */
unsigned long total_sect; /* number of sectors (if sectors == 0) */
};
@@ -80,11 +103,11 @@ struct fat_cache {
/* Convert attribute bits and a mask to the UNIX mode. */
-#define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? 0444 : 0777))
+#define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? 0555 : 0777))
/* Convert the UNIX mode to MS-DOS attribute bits. */
-#define MSDOS_MKATTR(m) (!(m & 0200) ? ATTR_RO : ATTR_NONE)
+#define MSDOS_MKATTR(m) ((m & 0200) ? ATTR_NONE : ATTR_RO)
static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
@@ -100,6 +123,7 @@ static inline struct buffer_head *msdos_sread(int dev,int sector,void **start)
/* misc.c */
+extern void fs_panic(struct super_block *s,char *msg);
extern int is_binary(char conversion,char *extension);
extern void lock_creation(void);
extern void unlock_creation(void);
@@ -149,6 +173,7 @@ extern void msdos_statfs(struct super_block *sb,struct statfs *buf);
extern int msdos_bmap(struct inode *inode,int block);
extern void msdos_read_inode(struct inode *inode);
extern void msdos_write_inode(struct inode *inode);
+extern int msdos_notify_change(int flags,struct inode *inode);
/* dir.c */
diff --git a/include/linux/msdos_fs_i.h b/include/linux/msdos_fs_i.h
index 4dacb18..21eb999 100644
--- a/include/linux/msdos_fs_i.h
+++ b/include/linux/msdos_fs_i.h
@@ -2,8 +2,9 @@
#define _MSDOS_FS_I
/*
- * msdos file system inode data in memory
+ * MS-DOS file system inode data in memory
*/
+
struct msdos_inode_info {
int i_start; /* first cluster or 0 */
int i_attrs; /* unused attribute bits */
diff --git a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h
index 3ed1273..025d250 100644
--- a/include/linux/msdos_fs_sb.h
+++ b/include/linux/msdos_fs_sb.h
@@ -1,6 +1,10 @@
#ifndef _MSDOS_FS_SB
#define _MSDOS_FS_SB
+/*
+ * MS-DOS file system in-core superblock data
+ */
+
struct msdos_sb_info {
unsigned short cluster_size; /* sectors/cluster */
unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
@@ -15,6 +19,7 @@ struct msdos_sb_info {
unsigned char conversion; /* b = binary, t = text, a = auto */
struct wait_queue *fat_wait;
int fat_lock;
+ int prev_free; /* previously returned free cluster number */
int free_clusters; /* -1 if undefined */
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 460dd72..d853c4f 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -143,16 +143,16 @@ struct tss_struct {
struct task_struct {
/* these are hardcoded - don't touch */
- long state; /* -1 unrunnable, 0 runnable, >0 stopped */
+ long state; /* -1 unrunnable, 0 runnable, >0 stopped */
long counter;
long priority;
- long signal;
+ unsigned long signal;
+ unsigned long blocked; /* bitmap of masked signals */
+ unsigned long flags; /* per process flags, defined below */
+/* various fields */
struct sigaction sigaction[32];
- long blocked; /* bitmap of masked signals */
unsigned long saved_kernel_stack;
unsigned long kernel_stack_page;
- unsigned int flags; /* per process flags, defined below */
-/* various fields */
int exit_code;
int dumpable:1;
int swappable:1;
@@ -220,9 +220,9 @@ struct task_struct {
* your own risk!. Base=0, limit=0x1fffff (=2MB)
*/
#define INIT_TASK \
-/* state etc */ { 0,15,15, \
-/* signals */ 0,{{ 0, },},0,0,0, \
-/* flags */ 0, \
+/* state etc */ { 0,15,15,0,0,0, \
+/* signals */ {{ 0, },}, \
+/* stack */ 0,0, \
/* ec,brk... */ 0,0,0,0,0,0,0,0, \
/* argv.. */ 0,0,0,0, \
/* pid etc.. */ 0,0,0,0, \
@@ -275,7 +275,7 @@ extern void interruptible_sleep_on(struct wait_queue ** p);
extern void wake_up(struct wait_queue ** p);
extern void wake_up_interruptible(struct wait_queue ** p);
-extern int send_sig(long sig,struct task_struct * p,int priv);
+extern int send_sig(unsigned long sig,struct task_struct * p,int priv);
extern int in_group_p(gid_t grp);
extern int request_irq(unsigned int irq,void (*handler)(int));
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 45ae421..d6c15ea 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -119,6 +119,8 @@ extern int sys_vm86();
extern int sys_wait4();
extern int sys_swapoff();
extern int sys_sysinfo();
+extern int sys_ipc();
+extern int sys_fsync();
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
@@ -141,7 +143,7 @@ sys_ftruncate, sys_fchmod, sys_fchown, sys_getpriority, sys_setpriority,
sys_profil, sys_statfs, sys_fstatfs, sys_ioperm, sys_socketcall,
sys_syslog, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
sys_newfstat, sys_newuname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
-sys_wait4, sys_swapoff, sys_sysinfo };
+sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 03ee1d3..868b2a3 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -22,6 +22,8 @@
* SCSI_TIMER scsi.c timeout timer
*
* NET_TIMER tcp/ip timeout timer
+ *
+ * MISC_TIMER reserved for special uses like the 387 timeouts etc
*/
#define BLANK_TIMER 0
@@ -33,6 +35,7 @@
#define SCSI_TIMER 18
#define NET_TIMER 19
#define SOUND_TIMER 20
+#define MISC_TIMER 21
struct timer_struct {
unsigned long expires;
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 4f7eaf0..eb18e64 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -99,6 +99,7 @@ struct serial_struct {
#define ASYNC_HUP_NOTIFY 0x0001 /* Notify blocked open on hangups */
#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */
+#define ASYNC_SKIP_TEST 0x0008 /* Skip UART test on bootup */
#define ASYNC_SPD_MASK 0x0030
#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
diff --git a/include/linux/xd.h b/include/linux/xd.h
new file mode 100644
index 0000000..3ff0844
--- /dev/null
+++ b/include/linux/xd.h
@@ -0,0 +1,143 @@
+#ifndef _LINUX_XD_H
+#define _LINUX_XD_H
+
+/*
+ * This file contains the definitions for the IO ports and errors etc. for XT hard disk controllers (at least the DTC 5150X).
+ *
+ * Author: Pat Mackinlay, smackinla@cc.curtin.edu.au
+ * Date: 29/09/92
+ *
+ * Revised: 01/01/93, ...
+ *
+ * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
+ * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
+ */
+
+/* XT hard disk controller registers */
+#define XD_DATA (xd_iobase + 0x00) /* data RW register */
+#define XD_RESET (xd_iobase + 0x01) /* reset WO register */
+#define XD_STATUS (xd_iobase + 0x01) /* status RO register */
+#define XD_SELECT (xd_iobase + 0x02) /* select WO register */
+#define XD_JUMPER (xd_iobase + 0x02) /* jumper RO register */
+#define XD_CONTROL (xd_iobase + 0x03) /* DMAE/INTE WO register */
+#define XD_RESERVED (xd_iobase + 0x03) /* reserved */
+
+/* XT hard disk controller commands (incomplete list) */
+#define CMD_TESTREADY 0x00 /* test drive ready */
+#define CMD_RECALIBRATE 0x01 /* recalibrate drive */
+#define CMD_SENSE 0x03 /* request sense */
+#define CMD_FORMATDRV 0x04 /* format drive */
+#define CMD_VERIFY 0x05 /* read verify */
+#define CMD_FORMATTRK 0x06 /* format track */
+#define CMD_FORMATBAD 0x07 /* format bad track */
+#define CMD_READ 0x08 /* read */
+#define CMD_WRITE 0x0A /* write */
+#define CMD_SEEK 0x0B /* seek */
+
+/* Controller specific commands */
+#define CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X only?) */
+#define CMD_DTCGETECC 0x0D /* get ecc error length (DTC 5150X only?) */
+#define CMD_DTCREADBUF 0x0E /* read sector buffer (DTC 5150X only?) */
+#define CMD_DTCWRITEBUF 0x0F /* write sector buffer (DTC 5150X only?) */
+#define CMD_DTCREMAPTRK 0x11 /* assign alternate track (DTC 5150X only?) */
+#define CMD_DTCGETPARAM 0xFB /* get drive parameters (DTC 5150X only?) */
+#define CMD_DTCSETSTEP 0xFC /* set step rate (DTC 5150X only?) */
+#define CMD_DTCSETGEOM 0xFE /* set geometry data (DTC 5150X only?) */
+#define CMD_DTCGETGEOM 0xFF /* get geometry data (DTC 5150X only?) */
+#define CMD_ST11GETGEOM 0xF8 /* get geometry data (Seagate ST11R/M only?) */
+#define CMD_WDSETPARAM 0x0C /* set drive parameters (WD 1004A27X only?) */
+
+/* Bits for command status byte */
+#define CSB_ERROR 0x02 /* error */
+#define CSB_LUN 0x20 /* logical Unit Number */
+
+/* XT hard disk controller status bits */
+#define STAT_READY 0x01 /* controller is ready */
+#define STAT_INPUT 0x02 /* data flowing from controller to host */
+#define STAT_COMMAND 0x04 /* controller in command phase */
+#define STAT_SELECT 0x08 /* controller is selected */
+#define STAT_REQUEST 0x10 /* controller requesting data */
+#define STAT_INTERRUPT 0x20 /* controller requesting interrupt */
+
+/* XT hard disk controller control bits */
+#define PIO_MODE 0x00 /* control bits to set for PIO */
+#define DMA_MODE 0x03 /* control bits to set for DMA & interrupt */
+
+#define XD_MAXDRIVES 2 /* maximum 2 drives */
+#define XD_TIMEOUT 100 /* 1 second timeout */
+#define XD_RETRIES 4 /* maximum 4 retries */
+
+#undef DEBUG /* define for debugging output */
+#undef XD_OVERRIDE /* define to override auto-detection */
+
+#ifdef DEBUG
+ #define DEBUG_STARTUP /* debug driver initialisation */
+ #define DEBUG_OVERRIDE /* debug override geometry detection */
+ #define DEBUG_READWRITE /* debug each read/write command */
+ #define DEBUG_OTHER /* debug misc. interrupt/DMA stuff */
+ #define DEBUG_COMMAND /* debug each controller command */
+#endif DEBUG
+
+/* this structure defines the XT drives and their types */
+typedef struct {
+ u_char heads;
+ u_short cylinders;
+ u_char sectors;
+ u_char control;
+} XD_INFO;
+
+#define HDIO_GETGEO 0x0301 /* get drive geometry */
+
+/* this structure is returned to the HDIO_GETGEO ioctl */
+typedef struct {
+ u_char heads;
+ u_char sectors;
+ u_short cylinders;
+ u_long start;
+} XD_GEOMETRY;
+
+/* this structure defines a ROM BIOS signature */
+typedef struct {
+ u_long offset;
+ u_char *string;
+ void (*init_controller)(u_char *address);
+ void (*init_drive)(u_char drive);
+ u_char *name;
+} XD_SIGNATURE;
+
+extern void resetup_one_dev (struct gendisk *dev,unsigned int drive);
+
+u_long xd_init(u_long mem_start,u_long mem_end);
+static u_char xd_detect (u_char *controller,u_char **address);
+static u_char xd_initdrives (void (*init_drive)(u_char drive));
+static void xd_geninit (void);
+
+static int xd_open (struct inode *inode,struct file *file);
+static void do_xd_request (void);
+static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned int arg);
+static void xd_release (struct inode *inode,struct file *file);
+static int xd_reread_partitions (int dev);
+static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count);
+static void xd_recalibrate (u_char drive);
+
+static void xd_interrupt_handler (int unused);
+static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
+static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
+static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
+static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
+
+/* card specific setup and geometry gathering code */
+#ifndef XD_OVERRIDE
+static void xd_dtc5150x_init_controller (u_char *address);
+static void xd_dtc5150x_init_drive (u_char drive);
+static void xd_wd1004a27x_init_controller (u_char *address);
+static void xd_wd1004a27x_init_drive (u_char drive);
+static void xd_seagate11_init_controller (u_char *address);
+static void xd_seagate11_init_drive (u_char drive);
+static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
+#endif XD_OVERRIDE
+
+static void xd_override_init_controller (u_char *address);
+static void xd_override_init_drive (u_char drive);
+
+#endif _LINUX_XD_H
diff --git a/init/main.c b/init/main.c
index 72b03d4..09d7d44 100644
--- a/init/main.c
+++ b/init/main.c
@@ -18,6 +18,7 @@
#include <linux/head.h>
#include <linux/unistd.h>
#include <linux/string.h>
+#include <linux/timer.h>
extern unsigned long * prof_buffer;
extern unsigned long prof_len;
@@ -203,6 +204,17 @@ static void parse_options(char *line)
envp_init[envs+1] = NULL;
}
+static void copro_timeout(void)
+{
+#ifdef CONFIG_MATH_EMULATION
+ printk(" Trying to use software floating point\n");
+ hard_math = 0;
+ __asm__("movl %%cr0,%%eax ; xorl $6,%%eax ; movl %%eax,%%cr0":::"ax");
+#else
+ printk(" No software floating point - tough cookies\n");
+#endif
+}
+
void start_kernel(void)
{
/*
@@ -266,13 +278,19 @@ void start_kernel(void)
if (hard_math) {
unsigned short control_word;
- printk("Checking for 387 error mechanism ...");
+ timer_table[MISC_TIMER].expires = jiffies+100;
+ timer_table[MISC_TIMER].fn = copro_timeout;
+ timer_active |= 1<<MISC_TIMER;
+ printk("You have a bad 386/387 coupling.");
__asm__("fninit ; fnstcw %0 ; fwait":"=m" (*&control_word));
control_word &= 0xffc0;
__asm__("fldcw %0 ; fwait"::"m" (*&control_word));
outb_p(inb_p(0x21) | (1 << 2), 0x21);
__asm__("fldz ; fld1 ; fdiv %st,%st(1) ; fwait");
- printk(" ok, using %s.\n",ignore_irq13?"exception 16":"irq13");
+ timer_active &= ~(1<<MISC_TIMER);
+ if (hard_math)
+ printk("\rMath coprocessor using %s error reporting.\n",
+ ignore_irq13?"exception 16":"irq13");
}
move_to_user_mode();
if (!fork()) /* we count on this going ok */
diff --git a/kernel/blk_drv/Makefile b/kernel/blk_drv/Makefile
index 618a623..621e6f7 100644
--- a/kernel/blk_drv/Makefile
+++ b/kernel/blk_drv/Makefile
@@ -18,7 +18,7 @@
SUBDIRS = scsi
-OBJS = hd.o ll_rw_blk.o floppy.o ramdisk.o genhd.o
+OBJS = xd.o hd.o ll_rw_blk.o floppy.o ramdisk.o genhd.o
all: blk_drv.a scsisubdirs
@@ -38,6 +38,9 @@ dep:
$(CPP) -M *.c > .depend
for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep); done
+xd.o:
+ $(CC) $(CFLAGS) -fno-omit-frame-pointer $(RAMDISK) -c $<
+
dummy:
#
diff --git a/kernel/blk_drv/blk.h b/kernel/blk_drv/blk.h
index e054c49..e771184 100644
--- a/kernel/blk_drv/blk.h
+++ b/kernel/blk_drv/blk.h
@@ -78,6 +78,8 @@ extern void rd_load(void);
extern long rd_init(long mem_start, int length);
extern int ramdisk_size;
+extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end);
+
#define RO_IOCTLS(dev,where) \
case BLKROSET: if (!suser()) return -EPERM; \
set_device_ro((dev),get_fs_long((long *) (where))); return 0; \
@@ -147,6 +149,14 @@ extern int ramdisk_size;
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#elif (MAJOR_NR == 13)
+/* xt hard disk */
+#define DEVICE_NAME "xt disk"
+#define DEVICE_REQUEST do_xd_request
+#define DEVICE_NR(device) (MINOR(device) >> 6)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
#else
/* unknown blk device */
#error "unknown blk device"
diff --git a/kernel/blk_drv/ll_rw_blk.c b/kernel/blk_drv/ll_rw_blk.c
index 583d501..8deb1e2 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/kernel/blk_drv/ll_rw_blk.c
@@ -386,6 +386,9 @@ long blk_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_BLK_DEV_HD
mem_start = hd_init(mem_start,mem_end);
#endif
+#ifdef CONFIG_BLK_DEV_XD
+ mem_start = xd_init(mem_start,mem_end);
+#endif
if (ramdisk_size)
mem_start += rd_init(mem_start, ramdisk_size*1024);
return mem_start;
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
index f02dd4b..c41968a 100644
--- a/kernel/blk_drv/scsi/ultrastor.c
+++ b/kernel/blk_drv/scsi/ultrastor.c
@@ -91,8 +91,8 @@ struct config {
unsigned char interrupt: 4;
unsigned char dma_channel: 3;
unsigned char bios_drive_number: 1;
- unsigned char heads: 6;
- unsigned char sectors: 6;
+ unsigned char heads;
+ unsigned char sectors;
unsigned char ha_scsi_id: 3;
unsigned char subversion: 4;
};
diff --git a/kernel/blk_drv/xd.c b/kernel/blk_drv/xd.c
new file mode 100644
index 0000000..daf8a7a
--- /dev/null
+++ b/kernel/blk_drv/xd.c
@@ -0,0 +1,619 @@
+/*
+ * This file contains the driver for an XT hard disk controller (at least the DTC 5150X) for Linux.
+ *
+ * Author: Pat Mackinlay, smackinla@cc.curtin.edu.au
+ * Date: 29/09/92
+ *
+ * Revised: 01/01/93, ...
+ *
+ * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
+ * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_BLK_DEV_XD
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/genhd.h>
+#include <linux/xd.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/dma.h>
+
+#define MAJOR_NR 13
+#include "blk.h"
+
+XD_INFO xd_info[XD_MAXDRIVES];
+
+/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS
+ signature and details to the following list of signatures. A BIOS signature is a string embedded into the first
+ few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG
+ command. Run DEBUG, and then you can examine your BIOS signature with:
+
+ d xxxx:0000
+
+ where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should
+ be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters
+ in the table are, in order:
+
+ offset ; this is the offset (in bytes) from the start of your ROM where the signature starts
+ signature ; this is the actual text of the signature
+ xd_?_init_controller ; this is the controller init routine used by your controller
+ xd_?_init_drive ; this is the drive init routine used by your controller
+
+ The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
+ made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
+ best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
+ may work with your card. If none of these seem to work, try sending me some email and I'll see what I can do <grin>. */
+
+static XD_SIGNATURE xd_sigs[] = {
+ { 0x0000,"Override geometry handler",xd_override_init_controller,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
+#ifndef XD_OVERRIDE
+ { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc5150x_init_controller,xd_dtc5150x_init_drive," DTC 5150X" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
+ { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd1004a27x_init_controller,xd_wd1004a27x_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
+ { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd1004a27x_init_controller,xd_wd1004a27x_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
+ { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate11_init_controller,xd_seagate11_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
+ { 0x0010,"ST11R BIOS",xd_seagate11_init_controller,xd_seagate11_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
+#endif XD_OVERRIDE
+};
+#ifndef XD_OVERRIDE
+static u_char *xd_bases[] = { (u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xD0000,(u_char *) 0xD8000,(u_char *) 0xE0000 };
+#endif XD_OVERRIDE
+
+static struct hd_struct xd[XD_MAXDRIVES << 6];
+static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 };
+static struct gendisk xd_gendisk = { MAJOR_NR,"xd",6,1 << 6,XD_MAXDRIVES,xd_geninit,xd,xd_sizes,0,(void *) xd_info,NULL };
+static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,xd_ioctl,NULL,xd_open,xd_release };
+
+static struct wait_queue *xd_wait_exclusive = NULL,*xd_wait_int = NULL,*xd_wait_open = NULL;
+static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
+static u_char xd_busy = 0,xd_drives = 0;
+static u_char xd_irq,xd_dma,xd_maxsectors;
+static u_short xd_iobase;
+
+/* xd_init: grab the IRQ and DMA channel and initialise the drives */
+u_long xd_init (u_long mem_start,u_long mem_end)
+{
+ u_char i,controller,*address;
+
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) {
+ printk("xd_init: unable to get major number %d\n",MAJOR_NR);
+ return (mem_start);
+ }
+ read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */
+ xd_gendisk.next = gendisk_head;
+ gendisk_head = &xd_gendisk;
+
+ if (xd_detect(&controller,&address)) {
+
+ printk("xd_init: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
+ xd_sigs[controller].init_controller(address);
+ xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
+
+ printk("xd_init: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
+ for (i = 0; i < xd_drives; i++)
+ printk("xd_init: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors);
+
+ if (!request_irq(xd_irq,xd_interrupt_handler)) {
+ if (request_dma(xd_dma)) {
+ printk("xd_init: unable to get DMA%d\n",xd_dma);
+ free_irq(xd_irq);
+ }
+ }
+ else
+ printk("xd_init: unable to get IRQ%d\n",xd_irq);
+ }
+ return mem_start;
+}
+
+/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
+static u_char xd_detect (u_char *controller,u_char **address)
+{
+#ifndef XD_OVERRIDE
+ u_char i,j,found = 0;
+
+ for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
+ for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
+ if (!memcmp((u_char *) (xd_bases[i] + xd_sigs[j].offset),xd_sigs[j].string,strlen(xd_sigs[j].string))) {
+ *controller = j;
+ *address = xd_bases[i];
+ found++;
+ }
+ return (found);
+#else
+ *controller = 0;
+ *address = NULL;
+ return (1);
+#endif XD_OVERRIDE
+}
+
+/* xd_geninit: set up the "raw" device entries in the table */
+static void xd_geninit (void)
+{
+ u_char i;
+
+ for (i = 0; i < xd_drives; i++) {
+ xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors;
+ xd_valid[i] = 1;
+ }
+
+ xd_gendisk.nr_real = xd_drives;
+}
+
+/* xd_open: open a device */
+static int xd_open (struct inode *inode,struct file *file)
+{
+ int target = DEVICE_NR(MINOR(inode->i_rdev));
+
+ while (!xd_valid[target])
+ sleep_on(&xd_wait_open);
+
+ xd_access[target]++;
+
+ return (0);
+}
+
+/* do_xd_request: handle an incoming request */
+static void do_xd_request (void)
+{
+ u_int block,count,retry;
+ int code;
+
+ sti();
+ while (code = 0, CURRENT) {
+ INIT_REQUEST; /* do some checking on the request structure */
+
+ if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) {
+ block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect;
+ count = CURRENT->nr_sectors;
+
+ switch (CURRENT->cmd) {
+ case READ:
+ case WRITE: for (retry = 0; (retry < XD_RETRIES) && !code; retry++)
+ code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count);
+ break;
+ default: printk("do_xd_request: unknown request\n"); break;
+ }
+ }
+ end_request(code); /* wrap up, 0 = fail, 1 = success */
+ }
+}
+
+/* xd_ioctl: handle device ioctl's */
+static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_int arg)
+{
+ XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg;
+ int dev = DEVICE_NR(MINOR(inode->i_rdev)),err;
+
+ if (inode && (dev < xd_drives))
+ switch (cmd) {
+ case HDIO_GETGEO: if (arg) {
+ if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry))))
+ return (err);
+ put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads);
+ put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors);
+ put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders);
+ put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start);
+
+ return (0);
+ }
+ break;
+ case BLKGETSIZE: if (arg) {
+ if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long))))
+ return (err);
+ put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg);
+
+ return (0);
+ }
+ break;
+ case BLKRRPART: return (xd_reread_partitions(inode->i_rdev));
+ RO_IOCTLS(inode->i_rdev,arg);
+ }
+ return (-EINVAL);
+}
+
+/* xd_release: release the device */
+static void xd_release (struct inode *inode, struct file *file)
+{
+ sync_dev(inode->i_rdev);
+ xd_access[DEVICE_NR(MINOR(inode->i_rdev))]--;
+}
+
+/* xd_reread_partitions: rereads the partition table from a drive */
+
+/* xd_reread_partitions: rereads the partition table from a drive */
+static int xd_reread_partitions(int dev)
+{
+ int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
+
+ cli(); xd_valid[target] = (xd_access[target] != 1); sti();
+ if (xd_valid[target])
+ return (-EBUSY);
+
+ for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
+ sync_dev(MAJOR_NR << 8 | start | partition);
+ invalidate_inodes(MAJOR_NR << 8 | start | partition);
+ invalidate_buffers(MAJOR_NR << 8 | start | partition);
+ xd_gendisk.part[start + partition].start_sect = 0;
+ xd_gendisk.part[start + partition].nr_sects = 0;
+ };
+
+ xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
+ resetup_one_dev(&xd_gendisk,target);
+
+ xd_valid[target] = 1;
+ wake_up(&xd_wait_open);
+
+ return (0);
+}
+
+/* xd_readwrite: handle a read/write request */
+static int xd_readwrite (u_char operation,u_char drive,u_char *buffer,u_int block,u_int count)
+{
+ u_char cmdblk[6],sense[4];
+ u_short track,cylinder;
+ u_char head,sector,control,mode,temp;
+
+#ifdef DEBUG_READWRITE
+ printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
+#endif DEBUG_READWRITE
+
+ control = xd_info[drive].control;
+ while (count) {
+ temp = count < xd_maxsectors ? count : xd_maxsectors;
+
+ track = block / xd_info[drive].sectors;
+ head = track % xd_info[drive].heads;
+ cylinder = track / xd_info[drive].heads;
+ sector = block % xd_info[drive].sectors;
+
+#ifdef DEBUG_READWRITE
+ printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
+#endif DEBUG_READWRITE
+
+ if (xd_busy) /* get exclusive access to the controller */
+ sleep_on(&xd_wait_exclusive);
+ xd_busy = 1;
+
+ mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,buffer,temp * 0x200);
+ xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
+
+ switch (xd_command(cmdblk,mode,buffer,buffer,sense,XD_TIMEOUT)) {
+ case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); xd_busy = 0; wake_up(&xd_wait_exclusive); return (0);
+ case 2: switch ((sense[0] & 0x30) >> 4) {
+ case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
+ case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
+ case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
+ case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
+ }
+ if (sense[0] & 0x80)
+ printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
+ else
+ printk(" - no valid disk address\n");
+ xd_busy = 0; wake_up(&xd_wait_exclusive);
+ return (0);
+ }
+ count -= temp, buffer += temp * 0x200, block += temp;
+
+ xd_busy = 0; wake_up(&xd_wait_exclusive);
+ }
+ return (1);
+}
+
+/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
+static void xd_recalibrate (u_char drive)
+{
+ u_char cmdblk[6];
+
+ xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
+ if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
+ printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
+}
+
+/* xd_interrupt_handler: interrupt service routine */
+static void xd_interrupt_handler (int unused)
+{
+ if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
+#ifdef DEBUG_OTHER
+ printk("xd_interrupt_handler: interrupt detected\n");
+#endif DEBUG_OTHER
+ outb(0,XD_CONTROL); /* acknowledge interrupt */
+ wake_up(&xd_wait_int); /* and wake up sleeping processes */
+ }
+ else
+ printk("xd_interrupt_handler: unexpected interrupt\n");
+}
+
+/* xd_dma: set up the DMA controller for a data transfer */
+static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
+{
+ if (buffer < ((u_char *) 0x1000000 - count)) { /* transfer to address < 16M? */
+ if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
+#ifdef DEBUG_OTHER
+ printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
+#endif DEBUG_OTHER
+ return (PIO_MODE);
+ }
+ disable_dma(xd_dma);
+ clear_dma_ff(xd_dma);
+ set_dma_mode(xd_dma,mode);
+ set_dma_addr(xd_dma,(u_int) buffer);
+ set_dma_count(xd_dma,count);
+
+ return (DMA_MODE); /* use DMA and INT */
+ }
+#ifdef DEBUG_OTHER
+ printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
+#endif DEBUG_OTHER
+ return (PIO_MODE);
+}
+
+/* xd_build: put stuff into an array in a format suitable for the controller */
+static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
+{
+ cmdblk[0] = command;
+ cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
+ cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
+ cmdblk[3] = cylinder & 0xFF;
+ cmdblk[4] = count;
+ cmdblk[5] = control;
+
+ return (cmdblk);
+}
+
+/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
+static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
+{
+ u_long expiry = jiffies + timeout;
+
+ while (((inb(port) & mask) != flags) && (jiffies < expiry))
+ ;
+
+ return (jiffies >= expiry);
+}
+
+/* xd_command: handle all data transfers necessary for a single command */
+static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
+{
+ u_char cmdblk[6],csb,complete = 0;
+
+#ifdef DEBUG_COMMAND
+ printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
+#endif DEBUG_COMMAND
+
+ outb(0,XD_SELECT);
+ outb(mode,XD_CONTROL);
+
+ if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
+ return (1);
+
+ while (!complete) {
+ if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
+ return (1);
+ switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
+ case 0: if (mode == DMA_MODE) {
+ enable_dma(xd_dma);
+ sleep_on(&xd_wait_int);
+ disable_dma(xd_dma);
+ }
+ else
+ outb(outdata ? *outdata++ : 0,XD_DATA);
+ break;
+ case STAT_INPUT: if (mode == DMA_MODE) {
+ enable_dma(xd_dma);
+ sleep_on(&xd_wait_int);
+ disable_dma(xd_dma);
+ }
+ else
+ if (indata)
+ *indata++ = inb(XD_DATA);
+ else
+ inb(XD_DATA);
+ break;
+ case STAT_COMMAND: outb(command ? *command++ : 0,XD_DATA); break;
+ case STAT_COMMAND
+ | STAT_INPUT: complete = 1; break;
+ }
+ }
+ csb = inb(XD_DATA);
+
+ if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */
+ return (1);
+
+ if (csb & CSB_ERROR) { /* read sense data if error */
+ xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
+ if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))
+ printk("xd_command: warning! sense command failed!\n");
+ }
+
+#ifdef DEBUG_COMMAND
+ printk("xd_command: completed with csb = 0x%X\n",csb);
+#endif DEBUG_COMMAND
+
+ return (csb & CSB_ERROR);
+}
+
+static u_char xd_initdrives (void (*init_drive)(u_char drive))
+{
+ u_char cmdblk[6],i,count = 0;
+
+ for (i = 0; i < XD_MAXDRIVES; i++) {
+ xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0);
+ if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) {
+ init_drive(count);
+ count++;
+ }
+ }
+ return (count);
+}
+
+#ifndef XD_OVERRIDE
+static void xd_dtc5150x_init_controller (u_char *address)
+{
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xCA000: xd_iobase = 0x324; break;
+ }
+ xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
+ xd_dma = 3;
+ xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */
+
+ outb(0,XD_RESET); /* reset the controller */
+}
+
+static void xd_dtc5150x_init_drive (u_char drive)
+{
+ u_char cmdblk[6],buf[64];
+
+ xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0);
+ if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
+ xd_info[drive].heads = buf[0x0A]; /* heads */
+ xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */
+ xd_info[drive].sectors = 17; /* sectors */
+#if 0
+ xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
+ xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
+ xd_info[drive].ecc = buf[0x0F]; /* ecc length */
+#endif 0
+ xd_info[drive].control = 0; /* control byte */
+
+ xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
+ xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
+ if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
+ printk("xd_dtc5150x_init_drive: error setting step rate for drive %d\n",drive);
+ }
+ else
+ printk("xd_dtc5150x_init_drive: error reading geometry for drive %d\n",drive);
+}
+
+static void xd_wd1004a27x_init_controller (u_char *address)
+{
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xCA000: xd_iobase = 0x324; break;
+ case 0xD0000: xd_iobase = 0x328; break;
+ case 0xD8000: xd_iobase = 0x32C; break;
+ }
+ xd_irq = 5; /* don't know how to auto-detect this yet */
+ xd_dma = 3;
+ xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
+
+ outb(0,XD_RESET); /* reset the controller */
+}
+
+static void xd_wd1004a27x_init_drive (u_char drive)
+{
+ u_char cmdblk[6],buf[0x200];
+
+ xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0);
+ if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
+ xd_info[drive].heads = buf[0x1AF]; /* heads */
+ xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */
+ xd_info[drive].sectors = 17; /* sectors */
+#if 0
+ xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
+ xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
+ xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
+#endif 0
+ xd_info[drive].control = buf[0x1B5]; /* control byte */
+
+ xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
+ }
+ else
+ printk("xd_wd1004a27x_init_drive: error reading geometry for drive %d\n",drive);
+}
+
+static void xd_seagate11_init_controller (u_char *address)
+{
+ switch ((u_long) address) {
+ case 0xC8000: xd_iobase = 0x320; break;
+ case 0xD0000: xd_iobase = 0x324; break;
+ case 0xD8000: xd_iobase = 0x328; break;
+ case 0xE0000: xd_iobase = 0x32C; break;
+ }
+ xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
+ xd_dma = 3;
+ xd_maxsectors = 0x40;
+
+ outb(0,XD_RESET); /* reset the controller */
+}
+
+static void xd_seagate11_init_drive (u_char drive)
+{
+ u_char cmdblk[6],buf[0x200];
+
+ xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0);
+ if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) {
+ xd_info[drive].heads = buf[0x04]; /* heads */
+ xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */
+ xd_info[drive].sectors = buf[0x05]; /* sectors */
+ xd_info[drive].control = 0; /* control byte */
+ }
+ else
+ printk("xd_seagate11_init_drive: error reading geometry from drive %d\n",drive);
+}
+#endif XD_OVERRIDE
+
+/* xd_override_init_controller: sets appropriate values for unknown controllers. */
+static void xd_override_init_controller (u_char *address)
+{
+ xd_iobase = 0x320; /* standard setting */
+ xd_irq = 5; /* ditto */
+ xd_dma = 3; /* ditto */
+ xd_maxsectors = 0x01;
+
+ outb(0,XD_RESET); /* reset the controller */
+}
+
+/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
+ etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */
+static void xd_override_init_drive (u_char drive)
+{
+ u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 };
+ u_char cmdblk[6],i;
+
+ for (i = 0; i < 3; i++) {
+ while (min[i] != max[i] - 1) {
+ test[i] = (min[i] + max[i]) / 2;
+ xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0);
+ if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
+ min[i] = test[i];
+ else
+ max[i] = test[i];
+ }
+ test[i] = min[i];
+ }
+ xd_info[drive].heads = (u_char) min[0] + 1;
+ xd_info[drive].cylinders = (u_short) min[1] + 1;
+ xd_info[drive].sectors = (u_char) min[2] + 1;
+ xd_info[drive].control = 0;
+}
+
+#ifndef XD_OVERRIDE
+/* xd_setparam: set the drive characteristics */
+static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
+{
+ u_char cmdblk[14];
+
+ xd_build(cmdblk,command,drive,0,0,0,0,0);
+ cmdblk[6] = (u_char) (cylinders >> 8) & 0x03;
+ cmdblk[7] = (u_char) (cylinders & 0xFF);
+ cmdblk[8] = heads & 0x1F;
+ cmdblk[9] = (u_char) (rwrite >> 8) & 0x03;
+ cmdblk[10] = (u_char) (rwrite & 0xFF);
+ cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03;
+ cmdblk[12] = (u_char) (wprecomp & 0xFF);
+ cmdblk[13] = ecc;
+
+ if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
+ printk("xd_setparam: error setting characteristics for drive %d\n",drive);
+}
+#endif XD_OVERRIDE
+
+#endif CONFIG_BLK_DEV_XD
diff --git a/kernel/chr_drv/console.c b/kernel/chr_drv/console.c
index a0aa4dd..32bec47 100644
--- a/kernel/chr_drv/console.c
+++ b/kernel/chr_drv/console.c
@@ -54,6 +54,7 @@
#define NPAR 16
extern void vt_init(void);
+extern void register_console(void (*proc)(const char *));
unsigned long video_num_columns; /* Number of text columns */
unsigned long video_num_lines; /* Number of test lines */
@@ -1244,6 +1245,7 @@ long con_init(long kmem_start)
long base;
int orig_x = ORIG_X;
int orig_y = ORIG_Y;
+ void console_print(const char * b);
vc_scrmembuf = (unsigned short *) kmem_start;
video_num_columns = ORIG_VIDEO_COLS;
@@ -1334,6 +1336,7 @@ long con_init(long kmem_start)
display_desc,
video_num_columns,video_num_lines,
NR_CONSOLES);
+ register_console(console_print);
return kmem_start;
}
diff --git a/kernel/chr_drv/keyboard.c b/kernel/chr_drv/keyboard.c
index 803491f..30d4e83 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/kernel/chr_drv/keyboard.c
@@ -40,6 +40,7 @@
extern void do_keyboard_interrupt(void);
extern void ctrl_alt_del(void);
extern void change_console(unsigned int new_console);
+extern void fake_keyboard_interrupt(void);
unsigned long kbd_flags = 0;
unsigned long kbd_dead_keys = 0;
@@ -75,23 +76,6 @@ static inline void kb_wait(void)
break;
}
-/*
- * send_cmd() sends a command byte to the keyboard.
- */
-static inline void send_cmd(unsigned char c)
-{
- kb_wait();
- outb(c,0x64);
-}
-
-static inline unsigned char get_scancode(void)
-{
- kb_wait();
- if (inb_p(0x64) & 0x01)
- return inb(0x60);
- return 0;
-}
-
static void keyboard_interrupt(int int_pt_regs)
{
static unsigned char rep = 0xff;
@@ -102,8 +86,11 @@ static void keyboard_interrupt(int int_pt_regs)
if (!kbd_dead_keys)
kbd_prev_dead_keys = 0;
kbd_dead_keys = 0;
- send_cmd(0xAD);
- scancode = get_scancode();
+ kb_wait();
+ if (!(inb_p(0x64) & 0x01))
+ goto end_kbd_intr;
+ scancode = inb(0x60);
+ mark_bh(KEYBOARD_BH);
if (scancode == 0xfa) {
acknowledge = 1;
goto end_kbd_intr;
@@ -145,8 +132,6 @@ static void keyboard_interrupt(int int_pt_regs)
key_table[scancode](scancode);
rep = scancode;
end_kbd_intr:
- send_cmd(0xAE);
- mark_bh(KEYBOARD_BH);
}
static void put_queue(int ch)
@@ -1116,13 +1101,15 @@ unsigned int handle_diacr(unsigned int ch)
{
static unsigned char diacr_table[] =
{'`', 180, '^', '~', 168, 0}; /* Must end with 0 */
+ static unsigned char ret_diacr[] =
+ {'`', '\'', '^', '~', '"' }; /* Must not end with 0 */
int i;
for(i=0; diacr_table[i]; i++)
if (ch==diacr_table[i] && ((1<<i)&kbd->kbd_flags)) {
if (diacr == i) {
diacr=-1;
- return ch; /* pressed twice */
+ return ret_diacr[i]; /* pressed twice */
} else {
diacr=i; /* key is dead */
return 0;
@@ -1131,7 +1118,7 @@ unsigned int handle_diacr(unsigned int ch)
if (diacr == -1)
return ch;
else if (ch == ' ') {
- ch=diacr_table[diacr];
+ ch=ret_diacr[diacr];
diacr=-1;
return ch;
} else if (ch<64 || ch>122) {
@@ -1366,6 +1353,10 @@ static void kbd_bh(void * unused)
want_console = -1;
}
do_keyboard_interrupt();
+ cli();
+ if (inb_p(0x64) & 0x01)
+ fake_keyboard_interrupt();
+ sti();
}
long no_idt[2] = {0, 0};
@@ -1475,6 +1466,6 @@ unsigned long kbd_init(unsigned long kmem_start)
}
bh_base[KEYBOARD_BH].routine = kbd_bh;
request_irq(KEYBOARD_IRQ,keyboard_interrupt);
- keyboard_interrupt(0);
+ mark_bh(KEYBOARD_BH);
return kmem_start;
}
diff --git a/kernel/chr_drv/lp.c b/kernel/chr_drv/lp.c
index eb8c00b..679634f 100644
--- a/kernel/chr_drv/lp.c
+++ b/kernel/chr_drv/lp.c
@@ -299,6 +299,8 @@ static int lp_open(struct inode * inode, struct file * file)
sa.sa_restorer = NULL;
ret = irqaction(irq, &sa);
if (ret) {
+ kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
+ lp_table[minor].lp_buffer = NULL;
printk("lp%d unable to use interrupt %d, error %d\n", irq, ret);
return ret;
}
@@ -317,6 +319,7 @@ static void lp_release(struct inode * inode, struct file * file)
if ((irq = LP_IRQ(minor))) {
free_irq(irq);
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
+ lp_table[minor].lp_buffer = NULL;
}
LP_F(minor) &= ~LP_BUSY;
@@ -353,28 +356,48 @@ static int lp_ioctl(struct inode *inode, struct file *file,
case LPSETIRQ: {
int ret;
int oldirq;
+ int newirq = arg;
+ struct lp_struct *lp = &lp_table[minor];
struct sigaction sa;
if (!suser())
return -EPERM;
- if ((oldirq = LP_IRQ(minor))) {
+ oldirq = LP_IRQ(minor);
+
+ /* Allocate buffer now if we are going to need it */
+ if (!oldirq && newirq) {
+ if (!(lp->lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL)))
+ return -ENOMEM;
+ }
+
+ if (oldirq) {
free_irq(oldirq);
}
- if (arg) {
+ if (newirq) {
/* Install new irq */
sa.sa_handler = lp_interrupt;
sa.sa_flags = SA_INTERRUPT;
sa.sa_mask = 0;
sa.sa_restorer = NULL;
- if ((ret = irqaction(arg, &sa))) {
- if (oldirq)
+ if ((ret = irqaction(newirq, &sa))) {
+ if (oldirq) {
/* restore old irq */
irqaction(oldirq, &sa);
+ } else {
+ /* We don't need the buffer */
+ kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
+ lp->lp_buffer = NULL;
+ }
return ret;
}
}
- LP_IRQ(minor) = arg;
+ if (oldirq && !newirq) {
+ /* We don't need the buffer */
+ kfree_s(lp->lp_buffer, LP_BUFFER_SIZE);
+ lp->lp_buffer = NULL;
+ }
+ LP_IRQ(minor) = newirq;
lp_reset(minor);
break;
}
@@ -405,8 +428,10 @@ long lp_init(long kmem_start)
unsigned int testvalue = 0;
int count = 0;
- if (register_chrdev(6,"lp",&lp_fops))
+ if (register_chrdev(6,"lp",&lp_fops)) {
printk("unable to get major 6 for line printer\n");
+ return kmem_start;
+ }
/* take on all known port values */
for (offset = 0; offset < LP_NO; offset++) {
/* write to port & read back to check */
diff --git a/kernel/chr_drv/serial.c b/kernel/chr_drv/serial.c
index b5926d7..0637af9 100644
--- a/kernel/chr_drv/serial.c
+++ b/kernel/chr_drv/serial.c
@@ -51,7 +51,7 @@
* port.
*
*/
-
+
#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4)
/*
@@ -78,58 +78,59 @@ static int IRQ_timeout[16];
#define BASE_BAUD ( 1843200 / 16 )
struct async_struct rs_table[] = {
- { BASE_BAUD, 0x3F8, 4, 0, },
- { BASE_BAUD, 0x2F8, 3, 0, },
- { BASE_BAUD, 0x3E8, 4, 0, },
- { BASE_BAUD, 0x2E8, 3, 0, },
+ /* UART CLK PORT IRQ FLAGS */
+ { BASE_BAUD, 0x3F8, 4, ASYNC_SKIP_TEST, }, /* ttyS0 */
+ { BASE_BAUD, 0x2F8, 3, ASYNC_SKIP_TEST, }, /* ttyS1 */
+ { BASE_BAUD, 0x3E8, 4, ASYNC_SKIP_TEST, }, /* ttyS2 */
+ { BASE_BAUD, 0x2E8, 3, ASYNC_SKIP_TEST, }, /* ttyS3 */
#ifdef CONFIG_AST_FOURPORT
- { BASE_BAUD, 0x1A0, 2, ASYNC_FOURPORT },
- { BASE_BAUD, 0x1A8, 2, ASYNC_FOURPORT },
- { BASE_BAUD, 0x1B0, 2, ASYNC_FOURPORT },
- { BASE_BAUD, 0x1B8, 2, ASYNC_FOURPORT },
-
- { BASE_BAUD, 0x2A0, 5, ASYNC_FOURPORT },
- { BASE_BAUD, 0x2A8, 5, ASYNC_FOURPORT },
- { BASE_BAUD, 0x2B0, 5, ASYNC_FOURPORT },
- { BASE_BAUD, 0x2B8, 5, ASYNC_FOURPORT },
+ { BASE_BAUD, 0x1A0, 9, ASYNC_FOURPORT }, /* ttyS4 */
+ { BASE_BAUD, 0x1A8, 9, ASYNC_FOURPORT }, /* ttyS5 */
+ { BASE_BAUD, 0x1B0, 9, ASYNC_FOURPORT }, /* ttyS6 */
+ { BASE_BAUD, 0x1B8, 9, ASYNC_FOURPORT }, /* ttyS7 */
+
+ { BASE_BAUD, 0x2A0, 5, ASYNC_FOURPORT }, /* ttyS8 */
+ { BASE_BAUD, 0x2A8, 5, ASYNC_FOURPORT }, /* ttyS9 */
+ { BASE_BAUD, 0x2B0, 5, ASYNC_FOURPORT }, /* ttyS10 */
+ { BASE_BAUD, 0x2B8, 5, ASYNC_FOURPORT }, /* ttyS11 */
#else /* CONFIG_AST_FOURPORT */
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
-
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
+ { BASE_BAUD, 0x000, 0 }, /* ttyS4 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS5 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS6 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS7 */
+
+ { BASE_BAUD, 0x000, 0 }, /* ttyS8 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS9 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS10 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS11 */
#endif /* CONFIG_AST_FOURPORT */
#ifdef CONFIG_ACCENT_ASYNC
- { BASE_BAUD, 0x330, 4, 0 },
- { BASE_BAUD, 0x338, 4, 0 },
+ { BASE_BAUD, 0x330, 4, 0 }, /* ttyS12 */
+ { BASE_BAUD, 0x338, 4, 0 }, /* ttyS13 */
#else /* CONFIG_ACCENT_ASYNC */
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
+ { BASE_BAUD, 0x000, 0 }, /* ttyS12 */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS13 */
#endif /* CONFIG_ACCENT_ASYNC */
- { BASE_BAUD, 0x000, 0 },
- { BASE_BAUD, 0x000, 0 },
-
- { BASE_BAUD, 0x100, 4, 0 },
- { BASE_BAUD, 0x108, 4, 0 },
- { BASE_BAUD, 0x110, 4, 0 },
- { BASE_BAUD, 0x118, 4, 0 },
- { BASE_BAUD, 0x120, 4, 0 },
- { BASE_BAUD, 0x128, 4, 0 },
- { BASE_BAUD, 0x130, 4, 0 },
- { BASE_BAUD, 0x138, 4, 0 },
- { BASE_BAUD, 0x140, 4, 0 },
- { BASE_BAUD, 0x148, 4, 0 },
- { BASE_BAUD, 0x150, 4, 0 },
- { BASE_BAUD, 0x158, 4, 0 },
- { BASE_BAUD, 0x160, 4, 0 },
- { BASE_BAUD, 0x168, 4, 0 },
- { BASE_BAUD, 0x170, 4, 0 },
- { BASE_BAUD, 0x178, 4, 0 },
+ { BASE_BAUD, 0x000, 0 }, /* ttyS14 (spare; user configurable) */
+ { BASE_BAUD, 0x000, 0 }, /* ttyS15 (spare; user configurable) */
+
+ { BASE_BAUD, 0x100, 12, 0 }, /* ttyS16 */
+ { BASE_BAUD, 0x108, 12, 0 }, /* ttyS17 */
+ { BASE_BAUD, 0x110, 12, 0 }, /* ttyS18 */
+ { BASE_BAUD, 0x118, 12, 0 }, /* ttyS19 */
+ { BASE_BAUD, 0x120, 12, 0 }, /* ttyS20 */
+ { BASE_BAUD, 0x128, 12, 0 }, /* ttyS21 */
+ { BASE_BAUD, 0x130, 12, 0 }, /* ttyS22 */
+ { BASE_BAUD, 0x138, 12, 0 }, /* ttyS23 */
+ { BASE_BAUD, 0x140, 12, 0 }, /* ttyS24 */
+ { BASE_BAUD, 0x148, 12, 0 }, /* ttyS25 */
+ { BASE_BAUD, 0x150, 12, 0 }, /* ttyS26 */
+ { BASE_BAUD, 0x158, 12, 0 }, /* ttyS27 */
+ { BASE_BAUD, 0x160, 12, 0 }, /* ttyS28 */
+ { BASE_BAUD, 0x168, 12, 0 }, /* ttyS29 */
+ { BASE_BAUD, 0x170, 12, 0 }, /* ttyS30 */
+ { BASE_BAUD, 0x178, 12, 0 }, /* ttyS31 */
};
#define NR_PORTS (sizeof(rs_table)/sizeof(struct async_struct))
@@ -275,8 +276,7 @@ static inline void transmit_chars(struct async_struct *info, int *done_work)
(*done_work)++;
}
-static inline void check_modem_status(struct async_struct *info,
- int *done_work)
+static inline int check_modem_status(struct async_struct *info)
{
int status;
@@ -292,11 +292,12 @@ static inline void check_modem_status(struct async_struct *info,
if (info->tty->stopped) {
if (status & UART_MSR_CTS) {
info->tty->stopped = 0;
- done_work++;
+ return 1;
}
} else
info->tty->stopped = !(status & UART_MSR_CTS);
}
+ return 0;
}
static inline void figure_RS_timer(void)
@@ -334,17 +335,18 @@ static void rs_interrupt(int irq)
if (!pass_number ||
!(serial_inp(info, UART_IIR) & UART_IIR_NO_INT)) {
done = 0;
-
status = serial_inp(info, UART_LSR);
if (status & UART_LSR_DR) {
receive_chars(info, &status);
done_work++;
}
+ recheck_write:
if ((status & UART_LSR_THRE) &&
!info->tty->stopped) {
transmit_chars(info, &done_work);
}
- check_modem_status(info, &done_work);
+ if (check_modem_status(info))
+ goto recheck_write;
}
info = info->next_port;
@@ -365,7 +367,6 @@ static void rs_interrupt(int irq)
figure_RS_timer();
}
-#ifdef CONFIG_AUTO_IRQ
/*
* This is the serial driver's interrupt routine while we are probing
* for submarines.
@@ -379,7 +380,6 @@ static void rs_probe(int irq)
rs_triggered |= 1 << irq;
return;
}
-#endif
/*
* -------------------------------------------------------------------
@@ -1288,7 +1288,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
*/
static void show_serial_version(void)
{
- printk("Serial driver version 3.93 with");
+ printk("Serial driver version 3.94 with");
#ifdef CONFIG_AST_FOURPORT
printk(" AST_FOURPORT");
#define SERIAL_OPT
@@ -1309,7 +1309,6 @@ static void show_serial_version(void)
#undef SERIAL_OPT
}
-#ifdef CONFIG_AUTO_IRQ
/*
* This routine is called by init(); it attempts to determine which
* interrupt a serial port is configured to use. It is not
@@ -1361,13 +1360,12 @@ static int get_auto_irq(struct async_struct *info)
outb_p(save_ICP, ICP);
return(rs_irq_triggered);
}
-#endif
/*
* This routine is called by rs_init() to initialize a specific serial
* port. If CONFIG_AUTO_IRQ is defined, it will attempt to figure out
* which IRQ the serial port is on by calling get_auto_irq(). (See
- * above). a
+ * above).
*
* It also determines what type of UART ship this serial port is
* using: 8250, 16450, 16550, 16550A. The important question is
@@ -1378,15 +1376,54 @@ static void init(struct async_struct * info)
{
unsigned char status1, status2, scratch, scratch2;
unsigned port = info->port;
-#ifdef CONFIG_AUTO_IRQ
int retries;
-#endif
if (!port)
return;
-#ifdef CONFIG_AUTO_IRQ
- scratch2 = 0;
+ /*
+ * Do a simple existence test first; if we fail this, there's
+ * no point trying anything else.
+ */
+ scratch = serial_inp(info, UART_IER);
+ serial_outp(info, UART_IER, 0);
+ scratch2 = serial_inp(info, UART_IER);
+ serial_outp(info, UART_IER, scratch);
+ if (scratch2)
+ return; /* We failed; there's nothing here */
+
+ /*
+ * Check to see if a UART is really there. Certain broken
+ * internal modems based on the Rockwell chipset fail this
+ * test, because they apparently don't implement the loopback
+ * test mode. So this test is skipped on the COM 1 through
+ * COM 4 ports. This *should* be safe, since no board
+ * manufactucturer would be stupid enough to design a board
+ * that conflicts with COM 1-4 --- we hope!
+ */
+ if (!(info->flags & ASYNC_SKIP_TEST)) {
+ scratch = serial_inp(info, UART_MCR);
+ serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
+ scratch2 = serial_inp(info, UART_MSR);
+ serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
+ status1 = serial_inp(info, UART_MSR) & 0xF0;
+ serial_outp(info, UART_MCR, scratch);
+ serial_outp(info, UART_MSR, scratch2);
+ if (status1 != 0x90) {
+ info->type = PORT_UNKNOWN;
+ return;
+ }
+ }
+
+ /*
+ * Here's where we do the automatic IRQ detection. We always
+ * try to do this test; CONFIG_AUTO_IRQ merely determins
+ * whether or not we pay attention to the results. If
+ * CONFIG_AUTO_IRQ is off, then we merely print a warning
+ * message if the default IRQ does not match the results made
+ * by the automatic IRQ detection system.
+ */
+ scratch = scratch2 = 0;
for (retries = 0; retries < 5; retries++) {
if (!scratch)
scratch = get_auto_irq(info);
@@ -1398,28 +1435,22 @@ static void init(struct async_struct * info)
scratch = scratch2 = 0;
}
}
- if (scratch && (scratch == scratch2))
+ if (scratch && (scratch == scratch2)) {
+#ifdef CONFIG_AUTO_IRQ
info->irq = scratch;
- else {
- info->type = PORT_UNKNOWN;
- return;
- }
-#else /* CONFIG_AUTO_IRQ */
- /*
- * Check to see if a UART is really there.
- */
- scratch = serial_inp(info, UART_MCR);
- serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
- scratch2 = serial_inp(info, UART_MSR);
- serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
- status1 = serial_inp(info, UART_MSR) & 0xF0;
- serial_outp(info, UART_MCR, scratch);
- serial_outp(info, UART_MSR, scratch2);
- if (status1 != 0x90) {
+#else
+ if (info->irq != scratch)
+ printk("Warning: auto IRQ detection for tty%d found IRQ %d, not %d.\n",
+ info->line, scratch, info->irq);
+#endif
+ } else {
+#ifdef CONFIG_AUTO_IRQ
info->type = PORT_UNKNOWN;
return;
+#else
+ printk("Warning: auto IRQ detection for tty%d failed; using default IRQ.\n", info->line);
+#endif
}
-#endif /* CONFIG_AUTO_IRQ */
outb_p(UART_FCR_ENABLE_FIFO, UART_FCR + port);
scratch = inb(UART_IIR + port) >> 6;
@@ -1459,7 +1490,6 @@ long rs_init(long kmem_start)
{
int i;
struct async_struct * info;
-#ifdef CONFIG_AUTO_IRQ
int irq_lines = 0;
struct sigaction sa;
unsigned long timeout;
@@ -1469,28 +1499,26 @@ long rs_init(long kmem_start)
*/
sti();
- rs_triggered = 0;
sa.sa_handler = rs_probe;
sa.sa_flags = (SA_INTERRUPT);
sa.sa_mask = 0;
sa.sa_restorer = NULL;
-#endif
+
memset(&rs_event, 0, sizeof(rs_event));
bh_base[SERIAL_BH].routine = do_softint;
timer_table[RS_TIMER].fn = rs_timer;
timer_table[RS_TIMER].expires = 0;
IRQ_active = 0;
+ rs_triggered = 0;
for (i = 0; i < 16; i++) {
IRQ_ports[i] = 0;
IRQ_timeout[i] = 0;
-#ifdef CONFIG_AUTO_IRQ
if (!irqaction(i, &sa))
irq_lines |= 1 << i;
-#endif
}
-#ifdef CONFIG_AUTO_IRQ
- timeout = jiffies+5;
+
+ timeout = jiffies+10;
while (timeout >= jiffies)
;
for (i = 0; i < 16; i++) {
@@ -1501,7 +1529,7 @@ long rs_init(long kmem_start)
free_irq(i);
}
}
-#endif
+
show_serial_version();
for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
info->line = i;
@@ -1540,7 +1568,6 @@ long rs_init(long kmem_start)
break;
}
}
-#ifdef CONFIG_AUTO_IRQ
/*
* Turn interrupts back off, since they were off when we
* started this. See start_kernel() in init/main.c.
@@ -1550,7 +1577,6 @@ long rs_init(long kmem_start)
if (irq_lines & (1 << i))
free_irq(i);
}
-#endif
return kmem_start;
}
diff --git a/kernel/chr_drv/tty_io.c b/kernel/chr_drv/tty_io.c
index 5ffd395..aed9428 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/kernel/chr_drv/tty_io.c
@@ -1060,6 +1060,7 @@ static void release_dev(int dev, struct file * filp)
{
struct tty_struct *tty, *o_tty;
struct termios *tp, *o_tp;
+ struct task_struct **p;
tty = tty_table[dev];
tp = tty_termios[dev];
@@ -1107,6 +1108,15 @@ static void release_dev(int dev, struct file * filp)
if (tty->count)
return;
+ /*
+ * Make sure there aren't any processes that still think this
+ * tty is their controlling tty.
+ */
+ for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
+ if ((*p) && (*p)->tty == tty->line)
+ (*p)->tty = -1;
+ }
+
if (ldiscs[tty->disc].close != NULL)
ldiscs[tty->disc].close(tty);
diff --git a/kernel/exit.c b/kernel/exit.c
index bd3020f..4a1e02a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -20,9 +20,9 @@
int sys_close(int fd);
int getrusage(struct task_struct *, int, struct rusage *);
-int send_sig(long sig,struct task_struct * p,int priv)
+int send_sig(unsigned long sig,struct task_struct * p,int priv)
{
- if (!p || (sig < 0) || (sig > 32))
+ if (!p || sig > 32)
return -EINVAL;
if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
(current->euid != p->euid) && (current->uid != p->uid) && !suser())
diff --git a/kernel/fork.c b/kernel/fork.c
index ddaaef7..8bf0008 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -6,7 +6,7 @@
/*
* 'fork.c' contains the help-routines for the 'fork' system call
- * (see also system_call.s), and some misc functions ('verify_area').
+ * (see also system_call.s).
* Fork is rather simple, once you get the hang of it, but the memory
* management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
*/
@@ -24,27 +24,6 @@
long last_pid=0;
-int verify_area(int type, void * addr, unsigned long size)
-{
- unsigned long start;
-
- start = (unsigned long) addr;
- if (start >= TASK_SIZE)
- return -EFAULT;
- if (size > TASK_SIZE - start)
- return -EFAULT;
- if (type == VERIFY_READ)
- return 0;
- size += start & 0xfff;
- size >>= 12;
- start &= 0xfffff000;
- do {
- write_verify(start);
- start += 4096;
- } while (size--);
- return 0;
-}
-
static int find_empty_process(void)
{
int i, task_nr;
diff --git a/kernel/irq.c b/kernel/irq.c
index 9d503ae..2e5d29f 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -125,6 +125,11 @@ static void (*bad_interrupt[16])(void) = {
bad_IRQ14_interrupt, bad_IRQ15_interrupt
};
+void fake_keyboard_interrupt(void)
+{
+ IRQ1_interrupt();
+}
+
/*
* Initial irq handlers.
*/
diff --git a/kernel/printk.c b/kernel/printk.c
index 0f99367..8503ce6 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -2,6 +2,13 @@
* linux/kernel/printk.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Modified to make sys_syslog() more flexible: added commands to
+ * return the last 4k of kernel messages, regardless of whether
+ * they've been read or not. Added option to suppress kernel printk's
+ * to the console. Added hook for sending the console messages
+ * elsewhere, in preparation for a serial line console (someday).
+ * Ted Ts'o, 2/11/93.
*/
#include <stdarg.h>
@@ -18,46 +25,48 @@ static char buf[1024];
extern int vsprintf(char * buf, const char * fmt, va_list args);
extern void console_print(const char *);
-static unsigned long log_page = 0;
+static void (*console_print_proc)(const char *) = 0;
+static char log_buf[4096];
static unsigned long log_start = 0;
+static unsigned long logged_chars = 0;
unsigned long log_size = 0;
+int log_to_console = 1;
struct wait_queue * log_wait = NULL;
+/*
+ * Commands to sys_syslog:
+ *
+ * 0 -- Close the log. Currently a NOP.
+ * 1 -- Open and reset log.
+ * 2 -- Read from the log.
+ * 3 -- Read up to the last 4k of messages in the ring buffer.
+ * 4 -- Read and clear last 4k of messages in the ring buffer
+ * 5 -- Clear ring buffer.
+ * 6 -- Disable printk's to console
+ * 7 -- Enable printk's to console
+ */
int sys_syslog(int type, char * buf, int len)
{
- unsigned long i;
+ unsigned long i, j, count;
+ int do_clear = 0;
char c;
- if (!suser())
+ if ((type != 3) && !suser())
return -EPERM;
switch (type) {
- case 0:
- i = log_page;
- log_page = 0;
- free_page(i);
- wake_up_interruptible(&log_wait);
+ case 0: /* Close log */
return 0;
- case 1:
- i = get_free_page(GFP_KERNEL);
- if (log_page) {
- free_page(i);
- return 0;
- } else if ((log_page = i) != 0) {
- log_start = log_size = 0;
- return 0;
- }
- return -ENOMEM;
- case 2:
+ case 1: /* Open and reset log */
+ log_start += log_size;
+ log_size = 0;
+ return 0;
+ case 2: /* Read from log */
if (!buf || len < 0)
return -EINVAL;
if (!len)
return 0;
- i = verify_area(VERIFY_WRITE, buf, len);
- if (i)
- return i;
+ verify_area(VERIFY_WRITE,buf,len);
while (!log_size) {
- if (!log_page)
- return -EIO;
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
cli();
@@ -67,7 +76,7 @@ int sys_syslog(int type, char * buf, int len)
}
i = 0;
while (log_size && i < len) {
- c = *((char *) log_page+log_start);
+ c = *((char *) log_buf+log_start);
log_start++;
log_size--;
log_start &= 4095;
@@ -76,6 +85,36 @@ int sys_syslog(int type, char * buf, int len)
i++;
}
return i;
+ case 4: /* Read/clear last 4k of kernel messages */
+ do_clear = 1;
+ case 3: /* Read last 4k of kernel messages */
+ if (!buf || len < 0)
+ return -EINVAL;
+ if (!len)
+ return 0;
+ verify_area(VERIFY_WRITE,buf,len);
+ count = len;
+ if (count > 4096)
+ count = 4096;
+ if (count > logged_chars)
+ count = logged_chars;
+ j = log_start + log_size - count;
+ for (i = 0; i < count; i++) {
+ c = *((char *) log_buf + (j++ & 4095));
+ put_fs_byte(c, buf++);
+ }
+ if (do_clear)
+ logged_chars = 0;
+ return i;
+ case 5: /* Clear ring buffer */
+ logged_chars = 0;
+ return 0;
+ case 6: /* Disable logging to console */
+ log_to_console = 0;
+ return 0;
+ case 7: /* Enable logging to console */
+ log_to_console = 1;
+ return 0;
}
return -EINVAL;
}
@@ -85,21 +124,47 @@ int printk(const char *fmt, ...)
{
va_list args;
int i,j;
- char * p;
va_start(args, fmt);
i=vsprintf(buf,fmt,args);
va_end(args);
- for (j = 0; j < i && log_page ; j++) {
- p = (char *) log_page + (4095 & (log_start+log_size));
- *p = buf[j];
+ for (j = 0; j < i ; j++) {
+ log_buf[(log_start+log_size) & 4095] = buf[j];
if (log_size < 4096)
log_size++;
else
log_start++;
+ logged_chars++;
}
- if (log_page)
- wake_up_interruptible(&log_wait);
- console_print(buf);
+ wake_up_interruptible(&log_wait);
+ if (log_to_console && console_print_proc)
+ (*console_print_proc)(buf);
return i;
}
+
+/*
+ * The console driver calls this routine during kernel initialization
+ * to register the console printing procedure with printk() and to
+ * print any messages that were printed by the kernel before the
+ * console priver was initialized.
+ */
+void register_console(void (*proc)(const char *))
+{
+ int i,j;
+ int p = log_start;
+ char buf[16];
+
+ console_print_proc = proc;
+
+ for (i=0,j=0; i < log_size; i++) {
+ buf[j++] = log_buf[p];
+ p++; p &= 4095;
+ if (j < sizeof(buf)-1)
+ continue;
+ buf[j] = 0;
+ (*proc)(buf);
+ j = 0;
+ }
+ buf[j] = 0;
+ (*proc)(buf);
+}
diff --git a/kernel/sched.c b/kernel/sched.c
index ad207e2..992a3fb 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -159,8 +159,10 @@ int sys_pause(void)
if (sa->sa_handler == SIG_IGN || (sa->sa_handler == SIG_DFL
&& (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH)))
current->blocked |= mask;
- current->state = TASK_INTERRUPTIBLE;
- schedule();
+ do {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ } while (!(current->signal & ~current->blocked));
/* if a suspending signal interrupted us we must restart */
if (!(current->signal & ~current->blocked &
~(_S(SIGSTOP) | _S(SIGTSTP) | _S(SIGTTIN) | _S(SIGTTOU)))) {
diff --git a/kernel/signal.c b/kernel/signal.c
index ffa74e2..f90b7a2 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -170,87 +170,104 @@ extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
-int do_signal(long signr,struct pt_regs * regs)
+void do_signal(struct pt_regs * regs)
{
+ unsigned long signr;
unsigned long sa_handler;
long old_eip = regs->eip;
- struct sigaction * sa = current->sigaction + signr - 1;
+ struct sigaction * sa;
int longs;
unsigned long * tmp_esp;
- sa_handler = (unsigned long) sa->sa_handler;
- if ((regs->orig_eax >= 0) &&
- ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
- if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
- (sa->sa_flags & SA_INTERRUPT))
- regs->eax = -EINTR;
- else {
- regs->eax = regs->orig_eax;
- regs->eip = old_eip -= 2;
- }
+ if (regs->orig_eax >= 0 && regs->eax == -ERESTARTNOINTR) {
+ regs->eax = regs->orig_eax;
+ regs->eip = old_eip -= 2;
}
- if (sa_handler==1) {
+ signr = current->signal & ~current->blocked;
+ do {
+ __asm__("bsf %2,%1\n\t"
+ "btrl %1,%0"
+ :"=m" (current->signal),"=r" (signr)
+ :"1" (signr));
+ sa = current->sigaction + signr;
+ signr++;
+ sa_handler = (unsigned long) sa->sa_handler;
+ if (sa_handler==1) {
/* check for SIGCHLD: it's special */
- if (signr == SIGCHLD)
- while (sys_waitpid(-1,NULL,WNOHANG) > 0)
- /* nothing */;
- return(1); /* Ignore, see if there are more signals... */
- }
- if (!sa_handler) {
- if (current->pid == 1)
- return 1;
- switch (signr) {
- case SIGCONT:
- case SIGCHLD:
- case SIGWINCH:
- return(1); /* Ignore, ... */
+ if (signr == SIGCHLD)
+ while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ /* nothing */;
+ continue;
+ }
+ if (!sa_handler) {
+ if (current->pid == 1)
+ continue;
+ switch (signr) {
+ case SIGCONT:
+ case SIGCHLD:
+ case SIGWINCH:
+ continue;
- case SIGSTOP:
- case SIGTSTP:
- case SIGTTIN:
- case SIGTTOU:
- current->state = TASK_STOPPED;
- current->exit_code = signr;
- if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
- send_sig(SIGCHLD, current->p_pptr, 1);
- return(1); /* Reschedule another event */
+ case SIGSTOP:
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ send_sig(SIGCHLD, current->p_pptr, 1);
+ schedule();
+ continue;
- case SIGQUIT:
- case SIGILL:
- case SIGTRAP:
- case SIGIOT:
- case SIGFPE:
- case SIGSEGV:
- if (core_dump(signr,regs))
- signr |= 0x80;
- /* fall through */
- default:
- current->signal |= _S(signr & 0x7f);
- do_exit(signr);
+ case SIGQUIT:
+ case SIGILL:
+ case SIGTRAP:
+ case SIGIOT:
+ case SIGFPE:
+ case SIGSEGV:
+ if (core_dump(signr,regs))
+ signr |= 0x80;
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ do_exit(signr);
+ }
}
- }
- /*
- * OK, we're invoking a handler
- */
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- regs->eip = sa_handler;
- longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
- regs->esp -= longs;
- tmp_esp = (unsigned long *) regs->esp;
- verify_area(VERIFY_WRITE,tmp_esp,longs);
- put_fs_long((long) sa->sa_restorer,tmp_esp++);
- put_fs_long(signr,tmp_esp++);
- if (!(sa->sa_flags & SA_NOMASK))
- put_fs_long(current->blocked,tmp_esp++);
- put_fs_long(regs->eax,tmp_esp++);
- put_fs_long(regs->ecx,tmp_esp++);
- put_fs_long(regs->edx,tmp_esp++);
- put_fs_long(regs->eflags,tmp_esp++);
- put_fs_long(old_eip,tmp_esp++);
- current->blocked |= sa->sa_mask;
+ /*
+ * OK, we're invoking a handler
+ */
+ if (regs->orig_eax >= 0 && regs->eax == -ERESTARTSYS) {
+ if (sa->sa_flags & SA_INTERRUPT)
+ regs->eax = -EINTR;
+ else {
+ regs->eax = regs->orig_eax;
+ regs->eip = old_eip -= 2;
+ }
+ }
+ if (sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ regs->eip = sa_handler;
+ longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
+ regs->esp -= longs;
+ tmp_esp = (unsigned long *) regs->esp;
+ verify_area(VERIFY_WRITE,tmp_esp,longs);
+ put_fs_long((long) sa->sa_restorer,tmp_esp++);
+ put_fs_long(signr,tmp_esp++);
+ if (!(sa->sa_flags & SA_NOMASK))
+ put_fs_long(current->blocked,tmp_esp++);
+ put_fs_long(regs->eax,tmp_esp++);
+ put_fs_long(regs->ecx,tmp_esp++);
+ put_fs_long(regs->edx,tmp_esp++);
+ put_fs_long(regs->eflags,tmp_esp++);
+ put_fs_long(old_eip,tmp_esp++);
+ current->blocked |= sa->sa_mask;
/* force a supervisor-mode page-in of the signal handler to reduce races */
- __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
- return(0); /* Continue, execute handler */
+ __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
+ return;
+ } while ((signr = current->signal & ~current->blocked));
+ if (regs->orig_eax >= 0 && regs->eax == -ERESTARTSYS) {
+ regs->eax = regs->orig_eax;
+ regs->eip = old_eip -= 2;
+ }
}
diff --git a/kernel/sys.c b/kernel/sys.c
index a7433b4..0777f8e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -130,7 +130,12 @@ int sys_prof(void)
return -ENOSYS;
}
-unsigned long save_v86_state(int signr,struct vm86_regs * regs)
+int sys_ipc(void)
+{
+ return -ENOSYS;
+}
+
+unsigned long save_v86_state(struct vm86_regs * regs)
{
unsigned long stack;
diff --git a/kernel/sys_call.S b/kernel/sys_call.S
index 1c911dd..9b10c82 100644
--- a/kernel/sys_call.S
+++ b/kernel/sys_call.S
@@ -65,23 +65,12 @@ VM_MASK = 0x00020000
/*
* these are offsets into the task-struct.
*/
-state = 0
-counter = 4
-priority = 8
+state = 0
+counter = 4
+priority = 8
signal = 12
-sigaction = 16 # MUST be 16 (=len of sigaction)
-blocked = (33*16)
-saved_kernel_stack = ((33*16)+4)
-kernel_stack_page = ((33*16)+8)
-flags = ((33*16)+12)
-
-/*
- * offsets within sigaction
- */
-sa_handler = 0
-sa_mask = 4
-sa_flags = 8
-sa_restorer = 12
+blocked = 16
+flags = 20
ENOSYS = 38
@@ -113,6 +102,21 @@ ENOSYS = 38
movl $0x17,%edx; \
mov %dx,%fs
+#define RESTORE_ALL \
+ popl %ebx; \
+ popl %ecx; \
+ popl %edx; \
+ popl %esi; \
+ popl %edi; \
+ popl %ebp; \
+ popl %eax; \
+ pop %ds; \
+ pop %es; \
+ pop %fs; \
+ pop %gs; \
+ addl $4,%esp; \
+ iret
+
.align 4
reschedule:
pushl $ret_from_sys_call
@@ -151,16 +155,16 @@ _system_call:
ret_from_sys_call:
movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
testl $VM_MASK,%eax # different then
- jne 4f
+ jne 1f
cmpw $0x0f,CS(%esp) # was old code segment supervisor ?
jne 2f
cmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?
jne 2f
-4: sti # slow interrupts get here with interrupts disabled
+1: sti # slow interrupts get here with interrupts disabled
orl $IF_MASK,%eax # these just try to make sure
andl $~NT_MASK,%eax # the program doesn't do anything
movl %eax,EFLAGS(%esp) # stupid
-1: cmpl $0,_need_resched
+ cmpl $0,_need_resched
jne reschedule
movl _current,%eax
cmpl _task,%eax # task[0] cannot have signals
@@ -169,44 +173,28 @@ ret_from_sys_call:
jne reschedule
cmpl $0,counter(%eax) # counter
je reschedule
- movl signal(%eax),%ebx
movl blocked(%eax),%ecx
notl %ecx
- andl %ebx,%ecx
- je 2f # XXX - branch is almost always taken
- bsfl %ecx,%ecx
- btrl %ecx,signal(%eax) # change atomically (%ebx is stale)
- jnc 2f # bit became clear (can't happen?)
- incl %ecx
+ andl signal(%eax),%ecx
+ jne signal_return
+2: RESTORE_ALL
+.align 4
+signal_return:
movl %esp,%ebx
- testl $VM_MASK,EFLAGS(%esp)
- je 3f
pushl %ebx
- pushl %ecx
+ testl $VM_MASK,EFLAGS(%ebx)
+ jne v86_signal_return
+ call _do_signal
+ popl %ebx
+ RESTORE_ALL
+.align 4
+v86_signal_return:
call _save_v86_state
- popl %ecx
- movl %eax,%ebx
movl %eax,%esp
-3: pushl %ebx
- pushl %ecx
+ pushl %eax
call _do_signal
- popl %ecx
popl %ebx
- testl %eax, %eax
- jne 1b # see if we need to switch tasks, or do more signals
-2: popl %ebx
- popl %ecx
- popl %edx
- popl %esi
- popl %edi
- popl %ebp
- popl %eax
- pop %ds
- pop %es
- pop %fs
- pop %gs
- addl $4,%esp # skip the orig_eax
- iret
+ RESTORE_ALL
.align 4
_sys_execve:
diff --git a/mm/memory.c b/mm/memory.c
index 899869c..64655cc 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -563,10 +563,28 @@ void do_wp_page(unsigned long error_code, unsigned long address,
invalidate();
}
-void write_verify(unsigned long address)
+int verify_area(int type, void * addr, unsigned long size)
{
- if (address < TASK_SIZE)
- do_wp_page(1,address,current,0);
+ unsigned long start;
+
+ start = (unsigned long) addr;
+ if (start >= TASK_SIZE)
+ return -EFAULT;
+ if (size > TASK_SIZE - start)
+ return -EFAULT;
+ if (type == VERIFY_READ || !size)
+ return 0;
+ if (!size)
+ return 0;
+ size--;
+ size += start & 0xfff;
+ size >>= 12;
+ start &= 0xfffff000;
+ do {
+ do_wp_page(1,start,current,0);
+ start += 4096;
+ } while (size--);
+ return 0;
}
static void get_empty_page(struct task_struct * tsk, unsigned long address)
diff --git a/mm/swap.c b/mm/swap.c
index 39272f6..71ff3fe 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -662,7 +662,7 @@ int sys_swapon(const char * specialfile)
p->flags = 0;
return -ENOMEM;
}
- read_swap_page(type < 1,tmp);
+ read_swap_page(SWP_ENTRY(type,0),tmp);
if (strncmp("SWAP-SPACE",tmp+4086,10)) {
printk("Unable to find swap-space signature\n");
free_page((long) tmp);
diff --git a/net/tcp/arp.c b/net/tcp/arp.c
index cbb9cdb..f1243b7 100644
--- a/net/tcp/arp.c
+++ b/net/tcp/arp.c
@@ -317,40 +317,24 @@ arp_destroy(unsigned long paddr)
{
unsigned long hash;
struct arp_table *apt;
- struct arp_table *lapt;
+ struct arp_table **lapt;
PRINTK (("arp_destroy (paddr=%X)\n",paddr));
/* we don't want to destroy are own arp */
if (my_ip_addr(paddr)) return;
hash = net32(paddr) & (ARP_TABLE_SIZE - 1);
cli(); /* can't be interrupted. */
- /* make sure there is something there. */
- if (arp_table[hash] == NULL) return;
-
- /* check the first one. */
- if (arp_table[hash]->ip == paddr)
- {
- apt = (struct arp_table *)arp_table[hash];
- arp_table[hash] = arp_table[hash]->next;
- arp_free (apt, sizeof (*apt));
- sti();
- return;
- }
-
- /* now deal with it any where else in the chain. */
- lapt = (struct arp_table *)arp_table[hash];
- for (apt = (struct arp_table *)arp_table[hash]->next;
- apt != NULL;
- apt = (struct arp_table *)apt->next)
- {
- if (apt->ip == paddr)
- {
- lapt->next = apt->next;
- arp_free (apt, sizeof (*apt));
- sti();
- return;
- }
- }
+ lapt = (struct arp_table **) &arp_table[hash];
+ while ((apt = *lapt) != NULL) {
+ if (apt->ip == paddr)
+ {
+ *lapt = (struct arp_table *) apt->next;
+ arp_free(apt, sizeof(*apt));
+ sti();
+ return;
+ }
+ lapt = (struct arp_table **) &apt->next;
+ }
sti();
}
@@ -410,7 +394,7 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
tbl->last_used = timer_seq;
}
- if (!my_ip_addr(*arp_targetp(arp)))
+ if (my_ip_addr(*arp_targetp(arp)) != IS_MYADDR)
{
kfree_skb (skb, FREE_READ);
return (0);
diff --git a/net/tcp/ip.c b/net/tcp/ip.c
index 2aa7a44..e517a6b 100644
--- a/net/tcp/ip.c
+++ b/net/tcp/ip.c
@@ -192,7 +192,7 @@ int
ip_addr_match (unsigned long addr1, unsigned long addr2)
{
int i;
- if (addr1 == addr2) return (1);
+ if (addr1 == addr2) return (IS_MYADDR);
for (i = 0; i < 4; i++, addr1 >>= 8, addr2 >>= 8)
{
if ((addr1 & 0xff) != (addr2 & 0xff))
@@ -203,20 +203,22 @@ ip_addr_match (unsigned long addr1, unsigned long addr2)
{
return (0);
}
- return (1);
+ return (IS_BROADCAST);
}
}
- return (1);
+ return (IS_MYADDR);
}
int
my_ip_addr(unsigned long addr)
{
int i;
+ int result;
for (i = 0; i < MAX_IP_ADDRES; i++)
{
if (ip_addr[i] == 0) return (0);
- if (ip_addr_match (addr, ip_addr[i])) return (1);
+ result = ip_addr_match (addr, ip_addr[i]);
+ if (result) return result;
}
return (0);
}
diff --git a/net/tcp/ip.h b/net/tcp/ip.h
index 4d543f9..744efe5 100644
--- a/net/tcp/ip.h
+++ b/net/tcp/ip.h
@@ -156,6 +156,12 @@ extern int ip_ads;
#define MY_IP_ADDR ip_addr[0]
int my_ip_addr(unsigned long);
+/*
+ * returned by my_ip_addr..
+ */
+#define IS_MYADDR 1
+#define IS_BROADCAST 2
+
#include "eth.h"
void
diff --git a/tools/build.c b/tools/build.c
index d8cddfd..a15ee3b 100644
--- a/tools/build.c
+++ b/tools/build.c
@@ -94,7 +94,14 @@ int main(int argc, char ** argv)
if ((argc < 4) || (argc > 5))
usage();
if (argc > 4) {
- if (strcmp(argv[4], "FLOPPY")) {
+ if (!strcmp(argv[4], "CURRENT")) {
+ if (stat("/", &sb)) {
+ perror("/");
+ die("Couldn't stat /");
+ }
+ major_root = major(sb.st_dev);
+ minor_root = minor(sb.st_dev);
+ } else if (strcmp(argv[4], "FLOPPY")) {
if (stat(argv[4], &sb)) {
perror(argv[4]);
die("Couldn't stat root device.");
diff --git a/tools/version.h b/tools/version.h
deleted file mode 100644
index dd045d4..0000000
--- a/tools/version.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#define UTS_RELEASE "0.99.pl1-46"
-#define UTS_VERSION "12/20/92"
-#define LINUX_COMPILE_TIME "14:31:20"
-#define LINUX_COMPILE_BY "root"
-#define LINUX_COMPILE_HOST "home"