Commit 5b726c10 authored by Linus Torvalds's avatar Linus Torvalds

[PATCH] Linux-0.99.7A (March 21, 1993)

More net-1 work. It's endless.

XT harddisk support by Pat Mackinlay.

sys_fsync() and SysV IPC code sys_ipc() stubs appear.

[original announcement below]

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
parent f65d0bc9
......@@ -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
......
......@@ -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
......
......@@ -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 @@ struct buffer_head * getblk(dev_t dev, int block, int size)
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 */
......
......@@ -460,7 +460,7 @@ int do_execve(unsigned long * eip,long tmp,char * filename,
}
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;
......
......@@ -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;
......
......@@ -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;
......
/*
* 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;
......
/*
* 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;
......
/*
* linux/fs/msdos/file.c
*
* Written 1992 by Werner Almesberger
* Written 1992,1993 by Werner Almesberger
*
* MS-DOS regular file handling primitives
*/
......
/*
* 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;
}
/*
* 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;
}
/*
* 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();
......
......@@ -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;
}
......
......@@ -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;
}
......@@ -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;
......
......@@ -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 @@ dt_getblk(struct inode * inode, u_long *lp, int create, u_long prev_addr)
goto repeat;
}
*lp = tmp;
inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb);
return result;
}
......@@ -279,17 +282,18 @@ indt_getblk(struct inode * inode, struct buffer_head * bh,
}
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;
......
......@@ -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 @@ int xiafs_unlink(struct inode * dir, const char * name, int len)
}
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;
......
......@@ -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);
......
......@@ -60,6 +60,7 @@ static int trunc_direct(struct inode * inode)
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 @@ static int trunc_indirect(struct inode * inode, int addr_off, u_long * lp)
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 @@ static int trunc_indirect(struct inode * inode, int addr_off, u_long * lp)
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 @@ static int trunc_dindirect(struct inode * inode)
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;
}
......
......@@ -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
......@@ -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);
......
......@@ -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 */
......
......@@ -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 */
......
#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 */
};
......
......@@ -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));
......
......@@ -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);
......@@ -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;
......
......@@ -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 */
......
#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
......@@ -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 */
......
......@@ -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:
#
......
......@@ -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"
......
......@@ -385,6 +385,9 @@ long blk_dev_init(long mem_start, long mem_end)
memset(ro_bits,0,sizeof(ro_bits));
#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);
......
......@@ -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;
};
......
/*
* 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
......@@ -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;
}
......
......@@ -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;
}
......@@ -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 */
......
......@@ -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;
}
......@@ -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);
......
......@@ -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())
......
......@@ -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;
......
......@@ -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.
*/
......
......@@ -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);
}
......@@ -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)))) {
......
......@@ -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;
}
}
......@@ -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;
......
......@@ -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:
......
......@@ -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)
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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
......
......@@ -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.");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment