Commit 598a477a authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.41

parent 1235b44f
......@@ -419,11 +419,11 @@ S: FIN-00330 Helsingfors
S: Finland
N: David C. Niemi
E: David.Niemi@oasis.gtegsc.com
E: niemidc@slma.com
D: FSSTND, The XFree86 Project
D: DMA memory support and future floppy driver
D: DMA memory support, floppy driver
S: 2364 Old Trail Drive
S: Reston, VA 22091
S: Reston, Virginia 22091
S: USA
N: Kai Petzke
......
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 40
SUBLEVEL = 41
all: Version zImage
......
......@@ -14,10 +14,12 @@
.globl _empty_bad_page
.globl _empty_bad_page_table
.globl _empty_zero_page
.globl _tmp_floppy_area,_floppy_track_buffer
.globl _floppy_track_buffer
#include <linux/tasks.h>
#include <linux/segment.h>
#define ASSEMBLER
#include <linux/fd.h>
#define CL_MAGIC_ADDR 0x90020
#define CL_MAGIC 0xA33F
......@@ -275,13 +277,6 @@ _empty_bad_page_table:
_empty_zero_page:
.org 0x6000
/*
* tmp_floppy_area is used by the floppy-driver when DMA cannot
* reach to a buffer-block. It needs to be aligned, so that it isn't
* on a 64kB border.
*/
_tmp_floppy_area:
.fill 1024,1,0
/*
* floppy_track_buffer is used to buffer one track of floppy data: it
* has to be separate from the tmp_floppy area, as otherwise a single-
......@@ -289,7 +284,7 @@ _tmp_floppy_area:
* data (36*2*512 bytes).
*/
_floppy_track_buffer:
.fill 512*2*36,1,0
.fill 512*2*MAX_BUFFER_SECTORS,1,0
/* This is the default interrupt "handler" :-) */
int_msg:
......
......@@ -124,7 +124,7 @@ static void floppy_off(unsigned int nr);
#define DEVICE_NAME "floppy"
#define DEVICE_INTR do_floppy
#define DEVICE_REQUEST do_fd_request
#define DEVICE_NR(device) ((device) & 3)
#define DEVICE_NR(device) ( ((device) & 3) | (((device) & 0x80 ) >> 5 ))
#define DEVICE_ON(device) floppy_on(DEVICE_NR(device))
#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device))
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -73,10 +73,6 @@ static struct wait_queue * busy_wait = NULL;
static int reset = 0;
static int hd_error = 0;
#if (HD_DELAY > 0)
unsigned long last_req, read_timer();
#endif
/*
* This struct defines the HD's and their types.
*/
......@@ -100,17 +96,20 @@ static int hd_sizes[MAX_HD<<6] = {0, };
static int hd_blocksizes[MAX_HD<<6] = {0, };
#if (HD_DELAY > 0)
unsigned long last_req;
unsigned long read_timer(void)
{
unsigned long t;
unsigned long t, flags;
int i;
save_flags(flags);
cli();
t = jiffies * 11932;
outb_p(0, 0x43);
i = inb_p(0x40);
i |= inb(0x40) << 8;
sti();
restore_flags(flags);
return(t - i);
}
#endif
......@@ -287,6 +286,9 @@ static void identify_intr(void)
insw(HD_DATA,(char *)&id,sizeof(id)/2);
insw(HD_DATA,(char *)&id,sizeof(id)/2);
}
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
hd_request();
return;
}
......@@ -307,6 +309,9 @@ static void set_multmode_intr(void)
else
printk (" hd%c: disabled multiple mode\n", dev+'a');
}
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
hd_request();
return;
}
......@@ -425,7 +430,6 @@ static void read_intr(void)
if (unmask_intr[dev])
sti(); /* permit other IRQs during xfer */
read_next:
do {
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
......@@ -442,7 +446,6 @@ static void read_intr(void)
printk("hd%c: read_intr: error = 0x%02x\n",dev+'a',hd_error);
}
bad_rw_intr();
cli();
hd_request();
return;
ok_to_read:
......@@ -467,7 +470,7 @@ static void read_intr(void)
end_request(1);
if (i > 0) {
if (msect)
goto read_next;
goto ok_to_read;
SET_INTR(&read_intr);
return;
}
......@@ -535,7 +538,6 @@ static void multwrite_intr(void)
printk("hd:%c multwrite_intr: error = 0x%02x\n",dev+'a',hd_error);
}
bad_rw_intr();
cli();
hd_request();
}
......@@ -544,6 +546,8 @@ static void write_intr(void)
int i;
int retries = 100000;
if (unmask_intr[DEVICE_NR(WCURRENT.dev)])
sti();
do {
i = (unsigned) inb_p(HD_STATUS);
if (i & BUSY_STAT)
......@@ -560,7 +564,6 @@ static void write_intr(void)
printk("HD: write_intr: error = 0x%02x\n",hd_error);
}
bad_rw_intr();
cli();
hd_request();
return;
ok_to_write:
......@@ -587,6 +590,9 @@ static void recal_intr(void)
{
if (win_result())
bad_rw_intr();
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
hd_request();
}
......@@ -1067,17 +1073,19 @@ static int revalidate_hddisk(int dev, int maxusage)
int max_p;
int start;
int i;
long flags;
target = DEVICE_NR(MINOR(dev));
gdev = &GENDISK_STRUCT;
save_flags(flags);
cli();
if (DEVICE_BUSY || USAGE > maxusage) {
sti();
restore_flags(flags);
return -EBUSY;
};
DEVICE_BUSY = 1;
sti();
restore_flags(flags);
max_p = gdev->max_p;
start = target << gdev->minor_shift;
......
......@@ -125,6 +125,7 @@ int is_read_only(int dev)
major = MAJOR(dev);
minor = MINOR(dev);
if ( major == FLOPPY_MAJOR && floppy_is_wp( minor) ) return 1;
if (major < 0 || major >= MAX_BLKDEV) return 0;
return ro_bits[major][minor >> 5] & (1 << (minor & 31));
}
......@@ -225,6 +226,7 @@ static void make_request(int major,int rw, struct buffer_head * bh)
* to add links to the top entry for scsi devices.
*/
if ((major == HD_MAJOR
|| major == FLOPPY_MAJOR
|| major == SCSI_DISK_MAJOR
|| major == SCSI_CDROM_MAJOR)
&& (req = blk_dev[major].current_request))
......
......@@ -111,7 +111,7 @@ static int opost(unsigned char c, struct tty_struct *tty)
if (O_ONLCR(tty)) {
if (space < 2)
return -1;
tty->driver.write(tty, 0, "\r", 1);
tty->driver.put_char(tty, '\r');
tty->column = 0;
}
tty->canon_column = tty->column;
......
......@@ -200,7 +200,7 @@ long pty_init(long kmem_start)
pty_driver.init_termios = tty_std_termios;
pty_driver.init_termios.c_iflag = 0;
pty_driver.init_termios.c_oflag = 0;
pty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD;
pty_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_driver.init_termios.c_lflag = 0;
pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver.refcount = &pty_refcount;
......@@ -221,6 +221,7 @@ long pty_init(long kmem_start)
pty_slave_driver.subtype = PTY_TYPE_SLAVE;
pty_slave_driver.minor_start = 192;
pty_slave_driver.init_termios = tty_std_termios;
pty_slave_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
pty_slave_driver.table = ttyp_table;
pty_slave_driver.termios = ttyp_termios;
pty_slave_driver.termios_locked = ttyp_termios_locked;
......
......@@ -69,6 +69,7 @@ static int serial_refcount;
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#define _INLINE_ inline
......@@ -186,6 +187,18 @@ static struct termios *serial_termios_locked[NR_PORTS];
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/*
* tmp_buf is used as a temporary buffer by serial_write. We need to
* lock it in case the memcpy_fromfs blocks while swapping in a page,
* and some other program tries to do a serial write at the same time.
* Since the lock will only come under contention when the system is
* swapping and available memory is low, it makes sense to share one
* buffer across all the serial ports, since it significantly saves
* memory if large numbers of serial ports are open.
*/
static unsigned char *tmp_buf = 0;
static struct semaphore tmp_buf_sem = MUTEX;
static inline int serial_paranoia_check(struct async_struct *info,
dev_t device, const char *routine)
{
......@@ -283,12 +296,6 @@ static void rs_stop(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_stop"))
return;
if (info->flags & ASYNC_CLOSING) {
tty->stopped = 0;
tty->hw_stopped = 0;
return;
}
save_flags(flags); cli();
if (info->IER & UART_IER_THRI) {
info->IER &= ~UART_IER_THRI;
......@@ -405,7 +412,8 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
*intr_done = 0;
return;
}
if (!info->xmit_cnt || info->tty->stopped || info->tty->hw_stopped) {
if ((info->xmit_cnt <= 0) || info->tty->stopped ||
info->tty->hw_stopped) {
info->IER &= ~UART_IER_THRI;
#ifdef CONFIG_SERIAL_NEW_ISR
serial_out(info, UART_IER, info->IER);
......@@ -417,7 +425,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
do {
serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
if (--info->xmit_cnt == 0)
if (--info->xmit_cnt <= 0)
break;
} while (--count > 0);
......@@ -430,7 +438,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
if (intr_done)
*intr_done = 0;
if (info->xmit_cnt == 0) {
if (info->xmit_cnt <= 0) {
info->IER &= ~UART_IER_THRI;
#ifdef CONFIG_SERIAL_NEW_ISR
serial_out(info, UART_IER, info->IER);
......@@ -462,7 +470,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
if (info->flags & ASYNC_CTS_FLOW) {
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
#ifdef SERIAL_DEBUG_INTR
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
printk("CTS tx start...");
#endif
info->tty->hw_stopped = 0;
......@@ -475,7 +483,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
}
} else {
if (!(status & UART_MSR_CTS)) {
#ifdef SERIAL_DEBUG_INTR
#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
printk("CTS tx stop...");
#endif
info->tty->hw_stopped = 1;
......@@ -926,6 +934,8 @@ static int startup(struct async_struct * info)
info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
info->MCR_noint = UART_MCR_DTR | UART_MCR_RTS;
}
if (info->irq == 0)
info->MCR = info->MCR_noint;
serial_outp(info, UART_MCR, info->MCR);
/*
......@@ -1190,6 +1200,7 @@ static void change_speed(struct async_struct *info)
static void rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct async_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_put_char"))
return;
......@@ -1197,12 +1208,16 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (!tty || tty->stopped || tty->hw_stopped || !info->xmit_buf)
return;
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
save_flags(flags); cli();
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
restore_flags(flags);
return;
}
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= SERIAL_XMIT_SIZE-1;
info->xmit_cnt++;
restore_flags(flags);
}
static void rs_flush_chars(struct tty_struct *tty)
......@@ -1213,7 +1228,7 @@ static void rs_flush_chars(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return;
if (info->xmit_cnt == 0 || tty->stopped || tty->hw_stopped ||
if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
!info->xmit_buf)
return;
......@@ -1233,29 +1248,33 @@ static int rs_write(struct tty_struct * tty, int from_user,
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
if (!tty || !info->xmit_buf)
if (!tty || !info->xmit_buf || !tmp_buf)
return 0;
save_flags(flags);
while (1) {
cli();
c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
if (!c)
if (c <= 0)
break;
if (from_user)
memcpy_fromfs(info->xmit_buf + info->xmit_head,
buf, c);
else
if (from_user) {
down(&tmp_buf_sem);
memcpy_fromfs(tmp_buf, buf, c);
c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
up(&tmp_buf_sem);
} else
memcpy(info->xmit_buf + info->xmit_head, buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
cli();
info->xmit_cnt += c;
sti();
restore_flags(flags);
buf += c;
count -= c;
total += c;
}
save_flags(flags); cli();
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
!(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
......@@ -1268,10 +1287,14 @@ static int rs_write(struct tty_struct * tty, int from_user,
static int rs_write_room(struct tty_struct *tty)
{
struct async_struct *info = tty->driver_data;
int ret;
if (serial_paranoia_check(info, tty->device, "rs_write_room"))
return 0;
return SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
if (ret < 0)
ret = 0;
return ret;
}
static int rs_chars_in_buffer(struct tty_struct *tty)
......@@ -1770,7 +1793,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (info->count)
return;
info->flags |= ASYNC_CLOSING;
info->flags &= ~ASYNC_CTS_FLOW;
/*
* Save the termios structure, since this port may have
* separate termios for callout and dialin.
......@@ -1779,12 +1801,8 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
info->normal_termios = *tty->termios;
if (info->flags & ASYNC_CALLOUT_ACTIVE)
info->callout_termios = *tty->termios;
tty->stopped = 0; /* Force flush to succeed */
tty->hw_stopped = 0;
if (info->flags & ASYNC_INITIALIZED) {
rs_start(tty);
wait_until_sent(tty, 6000); /* 60 seconds timeout */
}
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, 3000); /* 30 seconds timeout */
shutdown(info);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
......@@ -1980,6 +1998,12 @@ int rs_open(struct tty_struct *tty, struct file * filp)
tty->driver_data = info;
info->tty = tty;
if (!tmp_buf) {
tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
if (!tmp_buf)
return -ENOMEM;
}
if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
*tty->termios = info->normal_termios;
......
......@@ -31,6 +31,13 @@
# define PRINTK(x) /**/
#endif
/*
* Internal flag options for termios setting behavior
*/
#define TERMIOS_FLUSH 1
#define TERMIOS_WAIT 2
#define TERMIOS_TERMIO 4
void wait_until_sent(struct tty_struct * tty, int timeout)
{
struct wait_queue wait = { current, NULL };
......@@ -79,13 +86,41 @@ static void unset_locked_termios(struct termios *termios,
old->c_cc[i] : termios->c_cc[i];
}
static int set_termios_2(struct tty_struct * tty, struct termios * termios)
static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
{
struct termio tmp_termio;
struct termios tmp_termios;
struct termios old_termios = *tty->termios;
int canon_change;
int retval, canon_change;
retval = tty_check_change(tty);
if (retval)
return retval;
if (opt & TERMIOS_TERMIO) {
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, (struct termio *) arg,
sizeof (struct termio));
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
#undef SET_LOW_BITS
} else
memcpy_fromfs(&tmp_termios, (struct termios *) arg,
sizeof (struct termios));
if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
if (opt & TERMIOS_WAIT)
wait_until_sent(tty, 0);
cli();
*tty->termios = *termios;
*tty->termios = tmp_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
if (canon_change) {
......@@ -127,14 +162,6 @@ static int set_termios_2(struct tty_struct * tty, struct termios * termios)
return 0;
}
static int set_termios(struct tty_struct * tty, struct termios * termios)
{
struct termios tmp_termios;
memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
return set_termios_2(tty, &tmp_termios);
}
static int get_termio(struct tty_struct * tty, struct termio * termio)
{
int i;
......@@ -154,27 +181,6 @@ static int get_termio(struct tty_struct * tty, struct termio * termio)
return 0;
}
static int set_termio(struct tty_struct * tty, struct termio * termio)
{
struct termio tmp_termio;
struct termios tmp_termios;
tmp_termios = *tty->termios;
memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y))
SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
#undef SET_LOW_BITS
return set_termios_2(tty, &tmp_termios);
}
static unsigned long inq_canon(struct tty_struct * tty)
{
int nr, head, tail;
......@@ -199,6 +205,7 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
{
struct tty_struct * real_tty;
int retval;
int opt = 0;
if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
tty->driver.subtype == PTY_TYPE_MASTER)
......@@ -217,34 +224,19 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
sizeof (struct termios));
return 0;
case TCSETSF:
opt |= TERMIOS_FLUSH;
case TCSETSW:
opt |= TERMIOS_WAIT;
case TCSETS:
retval = tty_check_change(real_tty);
if (retval)
return retval;
if (cmd == TCSETSF || cmd == TCSETSW) {
if (cmd == TCSETSF &&
real_tty->ldisc.flush_buffer)
real_tty->ldisc.flush_buffer(real_tty);
wait_until_sent(real_tty, 0);
}
return set_termios(real_tty,
(struct termios *) arg);
return set_termios(real_tty, arg, opt);
case TCGETA:
return get_termio(real_tty,(struct termio *) arg);
case TCSETAF:
opt |= TERMIOS_FLUSH;
case TCSETAW:
opt |= TERMIOS_WAIT;
case TCSETA:
retval = tty_check_change(real_tty);
if (retval)
return retval;
if (cmd == TCSETAF || cmd == TCSETAW) {
if (cmd == TCSETAF &&
real_tty->ldisc.flush_buffer)
real_tty->ldisc.flush_buffer(real_tty);
wait_until_sent(real_tty, 0);
}
return set_termio(real_tty, (struct termio *) arg);
return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
case TCXONC:
retval = tty_check_change(tty);
if (retval)
......
......@@ -32,6 +32,8 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
register char * p;
dev = inode->i_rdev;
if ( is_read_only( inode->i_rdev ))
return -EPERM;
blocksize = BLOCK_SIZE;
if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)])
blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];
......
......@@ -479,6 +479,9 @@ static int do_remount_sb(struct super_block *sb, int flags, char *data)
{
int retval;
if (!(flags & MS_RDONLY ) && sb->s_dev && is_read_only(sb->s_dev))
return -EACCES;
/*flags |= MS_RDONLY;*/
/* If we are remounting RDONLY, make sure there are no rw files open */
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
if (!fs_may_remount_ro(sb->s_dev))
......
#ifndef _I386_STRING_H_
#define _I386_STRING_H_
/*
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
* see especially strtok,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
extern inline char * strcpy(char * dest,const char *src)
{
__asm__ __volatile__(
"cld\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: /* no output */
:"S" (src),"D" (dest):"si","di","ax","memory");
return dest;
}
extern inline char * strncpy(char * dest,const char *src,size_t count)
{
__asm__ __volatile__(
"cld\n"
"1:\tdecl %2\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"rep\n\t"
"stosb\n"
"2:"
: /* no output */
:"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
return dest;
}
extern inline char * strcat(char * dest,const char * src)
{
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"decl %1\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: /* no output */
:"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
return dest;
}
extern inline char * strncat(char * dest,const char * src,size_t count)
{
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"decl %1\n\t"
"movl %4,%3\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %2,%2\n\t"
"stosb"
: /* no output */
:"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
:"si","di","ax","cx","memory");
return dest;
}
extern inline int strcmp(const char * cs,const char * ct)
{
register int __res;
__asm__ __volatile__(
"cld\n"
"1:\tlodsb\n\t"
"scasb\n\t"
"jne 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"jmp 3f\n"
"2:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%eax\n"
"3:"
:"=a" (__res):"S" (cs),"D" (ct):"si","di");
return __res;
}
extern inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
__asm__ __volatile__(
"cld\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
:"=a" (__res):"S" (cs),"D" (ct),"c" (count):"si","di","cx");
return __res;
}
extern inline char * strchr(const char * s,char c)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"je 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"movl $1,%1\n"
"2:\tmovl %1,%0\n\t"
"decl %0"
:"=a" (__res):"S" (s),"0" (c):"si");
return __res;
}
extern inline char * strrchr(const char * s,char c)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"jne 2f\n\t"
"leal -1(%%esi),%0\n"
"2:\ttestb %%al,%%al\n\t"
"jne 1b"
:"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
return __res;
}
extern inline size_t strspn(const char * cs, const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"je 1b\n"
"2:\tdecl %0"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
:"ax","cx","dx","di");
return __res-cs;
}
extern inline size_t strcspn(const char * cs, const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 1b\n"
"2:\tdecl %0"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
:"ax","cx","dx","di");
return __res-cs;
}
extern inline char * strpbrk(const char * cs,const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 1b\n\t"
"decl %0\n\t"
"jmp 3f\n"
"2:\txorl %0,%0\n"
"3:"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
:"ax","cx","dx","di");
return __res;
}
extern inline char * strstr(const char * cs,const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t" \
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
"movl %%ecx,%%edx\n"
"1:\tmovl %4,%%edi\n\t"
"movl %%esi,%%eax\n\t"
"movl %%edx,%%ecx\n\t"
"repe\n\t"
"cmpsb\n\t"
"je 2f\n\t" /* also works for empty string, see above */
"xchgl %%eax,%%esi\n\t"
"incl %%esi\n\t"
"cmpb $0,-1(%%eax)\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"2:"
:"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
:"cx","dx","di","si");
return __res;
}
extern inline size_t strlen(const char * s)
{
register int __res;
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
return __res;
}
extern char * ___strtok;
extern inline char * strtok(char * s,const char * ct)
{
register char * __res;
__asm__ __volatile__(
"testl %1,%1\n\t"
"jne 1f\n\t"
"testl %0,%0\n\t"
"je 8f\n\t"
"movl %0,%1\n"
"1:\txorl %0,%0\n\t"
"movl $-1,%%ecx\n\t"
"xorl %%eax,%%eax\n\t"
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"je 7f\n\t" /* empty delimeter-string */
"movl %%ecx,%%edx\n"
"2:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 7f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"je 2b\n\t"
"decl %1\n\t"
"cmpb $0,(%1)\n\t"
"je 7f\n\t"
"movl %1,%0\n"
"3:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 5f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 3b\n\t"
"decl %1\n\t"
"cmpb $0,(%1)\n\t"
"je 5f\n\t"
"movb $0,(%1)\n\t"
"incl %1\n\t"
"jmp 6f\n"
"5:\txorl %1,%1\n"
"6:\tcmpb $0,(%0)\n\t"
"jne 7f\n\t"
"xorl %0,%0\n"
"7:\ttestl %0,%0\n\t"
"jne 8f\n\t"
"movl %0,%1\n"
"8:"
:"=b" (__res),"=S" (___strtok)
:"0" (___strtok),"1" (s),"g" (ct)
:"ax","cx","dx","di","memory");
return __res;
}
extern inline void * memcpy(void * to, const void * from, size_t n)
{
__asm__ __volatile__(
"cld\n\t"
"movl %%edx, %%ecx\n\t"
"shrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"testb $1,%%dl\n\t"
"je 1f\n\t"
"movsb\n"
"1:\ttestb $2,%%dl\n\t"
"je 2f\n\t"
"movsw\n"
"2:\n"
: /* no output */
:"d" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si","memory");
return (to);
}
extern inline void * memmove(void * dest,const void * src, size_t n)
{
if (dest<src)
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"movsb"
: /* no output */
:"c" (n),"S" (src),"D" (dest)
:"cx","si","di");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: /* no output */
:"c" (n),
"S" (n-1+(const char *)src),
"D" (n-1+(char *)dest)
:"cx","si","di","memory");
return dest;
}
extern inline int memcmp(const void * cs,const void * ct,size_t count)
{
register int __res;
__asm__ __volatile__(
"cld\n\t"
"repe\n\t"
"cmpsb\n\t"
"je 1f\n\t"
"sbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"1:"
:"=a" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
:"si","di","cx");
return __res;
}
extern inline void * memchr(const void * cs,char c,size_t count)
{
register void * __res;
if (!count)
return NULL;
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"je 1f\n\t"
"movl $1,%0\n"
"1:\tdecl %0"
:"=D" (__res):"a" (c),"D" (cs),"c" (count)
:"cx");
return __res;
}
extern inline void * memset(void * s,char c,size_t count)
{
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"stosb"
: /* no output */
:"a" (c),"D" (s),"c" (count)
:"cx","di","memory");
return s;
}
#endif
......@@ -3,8 +3,11 @@
#define FDCLRPRM 0 /* clear user-defined parameters */
#define FDSETPRM 1 /* set user-defined parameters for current media */
#define FDSETMEDIAPRM 1
#define FDDEFPRM 2 /* set user-defined parameters until explicitly cleared */
#define FDDEFMEDIAPRM 2
#define FDGETPRM 3 /* get disk parameters */
#define FDGETMEDIAPRM 3
#define FDMSGON 4 /* issue kernel messages on media type change */
#define FDMSGOFF 5 /* don't issue kernel messages on media type change */
#define FDFMTBEG 6 /* begin formatting a disk */
......@@ -14,17 +17,48 @@
#define FDFLUSH 11 /* flush buffers for media; either for verifying media, or for
handling a media change without closing the file
descriptor */
#define FDSETMAXERRS 12 /* set abortion and read_track treshold */
#define FDGETMAXERRS 14 /* get abortion and read_track treshold */
#define FDGETDRVTYP 16 /* get drive type: 5 1/4 or 3 1/2 */
#define FDSETDRVPRM 20 /* set drive parameters */
#define FDGETDRVPRM 21 /* get drive parameters */
#define FDGETDRVSTAT 22 /* get drive state */
#define FDPOLLDRVSTAT 23 /* get drive state */
#define FDGETFDCSTAT 25 /* get fdc state */
#define FDRESET 24 /* reset FDC */
#define FD_RESET_IF_NEEDED 0
#define FD_RESET_IF_RAWCMD 1
#define FD_RESET_ALWAYS 2
#define FDBAILOUT 26 /* release all fdc locks */
#define FD_CLEAR_RESET 0
#define FD_COMPLETE_FORMAT 1
#define FD_UNLOCK_FDC 2
#define FDRAWCMD 30 /* send a raw command to the fdc */
#define FDTWADDLE 40 /* flicker motor-on bit before reading a sector */
/*
* Maximum number of sectors in a track buffer. Track buffering is disabled
* if tracks are bigger.
*/
#define MAX_BUFFER_SECTORS 24 /* was 18 -bb */
#define FD_FILL_BYTE 0xF6 /* format fill byte */
#define FORMAT_NONE 0 /* no format request */
#define FORMAT_WAIT 1 /* format request is waiting */
#define FORMAT_BUSY 2 /* formatting in progress */
#define FORMAT_OKAY 3 /* successful completion */
#define FORMAT_ERROR 4 /* formatting error */
#define FD_2M 0x4
#define FD_SIZECODEMASK 0x38
#define FD_SIZECODE(floppy) (((( (floppy)->rate ) & FD_SIZECODEMASK) >> 3)+ 2)
#define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \
512 : 128 << FD_SIZECODE(floppy) )
#define FD_PERP 0x40
#ifndef ASSEMBLER
struct floppy_struct {
unsigned int size, /* nr of 512-byte sectors total */
unsigned int size, /* nr of sectors total */
sect, /* sectors per track */
head, /* nr of heads */
track, /* nr of tracks */
......@@ -40,4 +74,141 @@ struct format_descr {
unsigned int device,head,track;
};
struct floppy_max_errors {
unsigned int
abort, /* number of errors to be reached before aborting */
read_track, /* maximal number of errors permitted to read an
* entire track at once */
reset, /* maximal number of errors before a reset is tried */
recal, /* maximal number of errors before a recalibrate is
* tried */
/*
* Threshold for reporting FDC errors to the console.
* Setting this to zero may flood your screen when using
* ultra cheap floppies ;-)
*/
reporting;
};
struct floppy_drive_params {
char cmos; /* cmos type */
/* Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc)
* and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA).
*/
unsigned long max_dtr; /* Step rate, usec */
unsigned long hlt; /* Head load/settle time, msec */
unsigned long hut; /* Head unload time (remnant of 8" drives) */
unsigned long srt; /* Step rate, usec */
unsigned long spinup; /* time needed for spinup ( in jiffies) */
unsigned long spindown; /* timeout needed for spindown */
unsigned char spindown_offset;/* decides in which position the disk
* will stop */
unsigned char select_delay; /* delay to wait after select */
unsigned char rps; /* rotations per second */
unsigned char tracks; /* maximum number of tracks */
unsigned long timeout; /* timeout for interrupt requests */
unsigned char interleave_sect;/* if there are more sectors, use interleave */
struct floppy_max_errors max_errors;
char flags; /* various flags, including ftd_msg */
/*
* Announce successful media type detection and media information loss after
* disk changes.
* Also used to enable/disable printing of overrun warnings.
*/
#define FTD_MSG 0x10
char read_track; /* use readtrack during probing? */
/*
* Auto-detection. Each drive type has eight formats which are
* used in succession to try to read the disk. If the FDC cannot lock onto
* the disk, the next format is tried. This uses the variable 'probing'.
*/
short autodetect[8]; /* autodetected formats */
int checkfreq; /* how often should the drive be checked for disk changes */
int native_format; /* native format of this drive */
};
struct floppy_drive_struct {
signed char flags;
/* values for these flags */
#define FD_NEED_TWADDLE 1 /* more magic */
#define FD_VERIFY 2 /* this is set at bootup to force an initial drive status
inquiry*/
#define FD_DISK_NEWCHANGE 4 /* change detected, and no action undertaken yet to
clear media change status */
#define FD_DRIVE_PRESENT 8
#define FD_DISK_WRITABLE 32
unsigned long volatile spinup_date;
unsigned long volatile select_date;
unsigned long volatile first_read_date;
short probed_format;
short track; /* current track */
short maxblock; /* id of highest block read */
short maxtrack; /* id of highest half track read */
int generation; /* how many diskchanges? */
/*
* (User-provided) media information is _not_ discarded after a media change
* if the corresponding keep_data flag is non-zero. Positive values are
* decremented after each probe.
*/
int keep_data;
/* Prevent "aliased" accesses. */
int fd_ref;
int fd_device;
int last_checked; /* when was the drive last checked for a disk change? */
};
struct floppy_fdc_state {
int spec1; /* spec1 value last used */
int spec2; /* spec2 value last used */
int dtr;
unsigned char version; /* FDC version code */
unsigned char dor;
int address; /* io address */
unsigned int rawcmd:2;
unsigned int reset:1;
unsigned int need_configure:1;
unsigned int perp_mode:2;
unsigned int has_fifo:1;
};
struct floppy_raw_cmd {
void *data;
long length;
unsigned char rate;
unsigned char flags;
unsigned char cmd_count;
unsigned char cmd[9];
unsigned char reply_count;
unsigned char reply[7];
int track;
};
#endif
/* meaning of the various bytes */
/* flags */
#define FD_RAW_READ 1
#define FD_RAW_WRITE 2
#define FD_RAW_INTR 8
#define FD_RAW_SPIN 16
#define FD_RAW_NEED_DISK 64
#define FD_RAW_NEED_SEEK 128
#define FD_RAW_USER_SUPPLIED 256
#endif
......@@ -6,13 +6,30 @@
* Handbook", Sanches and Canton.
*/
#ifdef FDPATCHES
/* Fd controller regs. S&C, about page 340 */
#define FD_STATUS (4 + fdc_state[fdc].address )
#define FD_DATA (5 + fdc_state[fdc].address )
/* Digital Output Register */
#define FD_DOR (2 + fdc_state[fdc].address )
/* Digital Input Register (read) */
#define FD_DIR (7 + fdc_state[fdc].address )
/* Diskette Control Register (write)*/
#define FD_DCR (7 + fdc_state[fdc].address )
#else
#define FD_STATUS 0x3f4
#define FD_DATA 0x3f5
#define FD_DOR 0x3f2 /* Digital Output Register */
#define FD_DIR 0x3f7 /* Digital Input Register (read) */
#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/
#endif
/* Bits of main status register */
#define STATUS_BUSYMASK 0x0F /* drive busy mask */
#define STATUS_BUSY 0x10 /* FDC busy */
......@@ -65,13 +82,23 @@
#define FD_CONFIGURE 0x13 /* configure FIFO operation */
#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */
#define FD_GETSTATUS 0x04 /* read ST3 */
#define FD_DUMPREGS 0x0E /* dump the contents of the fdc regs */
#define FD_READID 0xEA /* prints the header of a sector */
#define FD_UNLOCK 0x14 /* Fifo config unlock */
#define FD_LOCK 0x94 /* Fifo config lock */
/* DMA commands */
#define DMA_READ 0x46
#define DMA_WRITE 0x4A
/* FDC version return types */
#define FDC_TYPE_STD 0x80 /* normal 8272A clone FDC */
#define FDC_TYPE_82077 0x90 /* FIFO + perpendicular support */
#define FDC_NONE 0x00
#define FDC_UNKNOWN 0x10
#define FDC_8272A 0x20 /* Intel 8272a, NEC 765 */
#define FDC_765ED 0x30 /* Non-Intel 1MB-compatible FDC, can't detect */
#define FDC_82072 0x40 /* Intel 82072; 8272a + FIFO + DUMPREGS */
#define FDC_82077_ORIG 0x50 /* Original version of 82077AA, sans LOCK */
#define FDC_82077 0x52 /* 82077AA-1 */
#define FD_RESET_DELAY 20
#endif
......@@ -422,6 +422,7 @@ extern inline void mark_buffer_dirty(struct buffer_head * bh, int flag)
extern int check_disk_change(dev_t dev);
extern void invalidate_inodes(dev_t dev);
extern void invalidate_buffers(dev_t dev);
extern int floppy_is_wp(int minor);
extern void sync_inodes(dev_t dev);
extern void sync_dev(dev_t dev);
extern int fsync_dev(dev_t dev);
......@@ -446,6 +447,7 @@ extern struct buffer_head * getblk(dev_t dev, int block, int size);
extern void ll_rw_block(int rw, int nr, struct buffer_head * bh[]);
extern void ll_rw_page(int rw, int dev, int nr, char * buffer);
extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer);
extern int is_read_only(int dev);
extern void brelse(struct buffer_head * buf);
extern void set_blocksize(dev_t dev, int size);
extern struct buffer_head * bread(dev_t dev, int block, int size);
......
......@@ -11,430 +11,27 @@
extern "C" {
#endif
/*
* This string-include defines all string functions as inline
* functions. Use gcc. It also assumes ds=es=data space, this should be
* normal. Most of the string-functions are rather heavily hand-optimized,
* see especially strtok,strstr,str[c]spn. They should work, but are not
* very easy to understand. Everything is done entirely within the register
* set, making the functions fast and clean. String instructions have been
* used through-out, making for "slightly" unclear code :-)
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
extern inline char * strcpy(char * dest,const char *src)
{
__asm__ __volatile__(
"cld\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: /* no output */
:"S" (src),"D" (dest):"si","di","ax","memory");
return dest;
}
extern inline char * strncpy(char * dest,const char *src,size_t count)
{
__asm__ __volatile__(
"cld\n"
"1:\tdecl %2\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"rep\n\t"
"stosb\n"
"2:"
: /* no output */
:"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory");
return dest;
}
extern inline char * strcat(char * dest,const char * src)
{
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"decl %1\n"
"1:\tlodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b"
: /* no output */
:"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx");
return dest;
}
extern inline char * strncat(char * dest,const char * src,size_t count)
{
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"decl %1\n\t"
"movl %4,%3\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"stosb\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %2,%2\n\t"
"stosb"
: /* no output */
:"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count)
:"si","di","ax","cx","memory");
return dest;
}
extern inline int strcmp(const char * cs,const char * ct)
{
register int __res;
__asm__ __volatile__(
"cld\n"
"1:\tlodsb\n\t"
"scasb\n\t"
"jne 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"jmp 3f\n"
"2:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%eax\n"
"3:"
:"=a" (__res):"S" (cs),"D" (ct):"si","di");
return __res;
}
extern inline int strncmp(const char * cs,const char * ct,size_t count)
{
register int __res;
__asm__ __volatile__(
"cld\n"
"1:\tdecl %3\n\t"
"js 2f\n\t"
"lodsb\n\t"
"scasb\n\t"
"jne 3f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n"
"2:\txorl %%eax,%%eax\n\t"
"jmp 4f\n"
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
:"=a" (__res):"S" (cs),"D" (ct),"c" (count):"si","di","cx");
return __res;
}
extern inline char * strchr(const char * s,char c)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"je 2f\n\t"
"testb %%al,%%al\n\t"
"jne 1b\n\t"
"movl $1,%1\n"
"2:\tmovl %1,%0\n\t"
"decl %0"
:"=a" (__res):"S" (s),"0" (c):"si");
return __res;
}
extern inline char * strrchr(const char * s,char c)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movb %%al,%%ah\n"
"1:\tlodsb\n\t"
"cmpb %%ah,%%al\n\t"
"jne 2f\n\t"
"leal -1(%%esi),%0\n"
"2:\ttestb %%al,%%al\n\t"
"jne 1b"
:"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si");
return __res;
}
extern inline size_t strspn(const char * cs, const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"je 1b\n"
"2:\tdecl %0"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
:"ax","cx","dx","di");
return __res-cs;
}
extern inline size_t strcspn(const char * cs, const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 1b\n"
"2:\tdecl %0"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
:"ax","cx","dx","di");
return __res-cs;
}
extern inline char * strpbrk(const char * cs,const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"movl %%ecx,%%edx\n"
"1:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 2f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 1b\n\t"
"decl %0\n\t"
"jmp 3f\n"
"2:\txorl %0,%0\n"
"3:"
:"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct)
:"ax","cx","dx","di");
return __res;
}
extern inline char * strstr(const char * cs,const char * ct)
{
register char * __res;
__asm__ __volatile__(
"cld\n\t" \
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */
"movl %%ecx,%%edx\n"
"1:\tmovl %4,%%edi\n\t"
"movl %%esi,%%eax\n\t"
"movl %%edx,%%ecx\n\t"
"repe\n\t"
"cmpsb\n\t"
"je 2f\n\t" /* also works for empty string, see above */
"xchgl %%eax,%%esi\n\t"
"incl %%esi\n\t"
"cmpb $0,-1(%%eax)\n\t"
"jne 1b\n\t"
"xorl %%eax,%%eax\n\t"
"2:"
:"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct)
:"cx","dx","di","si");
return __res;
}
extern inline size_t strlen(const char * s)
{
register int __res;
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"notl %0\n\t"
"decl %0"
:"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di");
return __res;
}
extern char * ___strtok;
extern inline char * strtok(char * s,const char * ct)
{
register char * __res;
__asm__ __volatile__(
"testl %1,%1\n\t"
"jne 1f\n\t"
"testl %0,%0\n\t"
"je 8f\n\t"
"movl %0,%1\n"
"1:\txorl %0,%0\n\t"
"movl $-1,%%ecx\n\t"
"xorl %%eax,%%eax\n\t"
"cld\n\t"
"movl %4,%%edi\n\t"
"repne\n\t"
"scasb\n\t"
"notl %%ecx\n\t"
"decl %%ecx\n\t"
"je 7f\n\t" /* empty delimeter-string */
"movl %%ecx,%%edx\n"
"2:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 7f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"je 2b\n\t"
"decl %1\n\t"
"cmpb $0,(%1)\n\t"
"je 7f\n\t"
"movl %1,%0\n"
"3:\tlodsb\n\t"
"testb %%al,%%al\n\t"
"je 5f\n\t"
"movl %4,%%edi\n\t"
"movl %%edx,%%ecx\n\t"
"repne\n\t"
"scasb\n\t"
"jne 3b\n\t"
"decl %1\n\t"
"cmpb $0,(%1)\n\t"
"je 5f\n\t"
"movb $0,(%1)\n\t"
"incl %1\n\t"
"jmp 6f\n"
"5:\txorl %1,%1\n"
"6:\tcmpb $0,(%0)\n\t"
"jne 7f\n\t"
"xorl %0,%0\n"
"7:\ttestl %0,%0\n\t"
"jne 8f\n\t"
"movl %0,%1\n"
"8:"
:"=b" (__res),"=S" (___strtok)
:"0" (___strtok),"1" (s),"g" (ct)
:"ax","cx","dx","di","memory");
return __res;
}
extern inline void * memcpy(void * to, const void * from, size_t n)
{
__asm__ __volatile__(
"cld\n\t"
"movl %%edx, %%ecx\n\t"
"shrl $2,%%ecx\n\t"
"rep ; movsl\n\t"
"testb $1,%%dl\n\t"
"je 1f\n\t"
"movsb\n"
"1:\ttestb $2,%%dl\n\t"
"je 2f\n\t"
"movsw\n"
"2:\n"
: /* no output */
:"d" (n),"D" ((long) to),"S" ((long) from)
: "cx","di","si","memory");
return (to);
}
extern inline void * memmove(void * dest,const void * src, size_t n)
{
if (dest<src)
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"movsb"
: /* no output */
:"c" (n),"S" (src),"D" (dest)
:"cx","si","di");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: /* no output */
:"c" (n),
"S" (n-1+(const char *)src),
"D" (n-1+(char *)dest)
:"cx","si","di","memory");
return dest;
}
extern inline int memcmp(const void * cs,const void * ct,size_t count)
{
register int __res;
__asm__ __volatile__(
"cld\n\t"
"repe\n\t"
"cmpsb\n\t"
"je 1f\n\t"
"sbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"1:"
:"=a" (__res):"0" (0),"S" (cs),"D" (ct),"c" (count)
:"si","di","cx");
return __res;
}
extern inline void * memchr(const void * cs,char c,size_t count)
{
register void * __res;
if (!count)
return NULL;
__asm__ __volatile__(
"cld\n\t"
"repne\n\t"
"scasb\n\t"
"je 1f\n\t"
"movl $1,%0\n"
"1:\tdecl %0"
:"=D" (__res):"a" (c),"D" (cs),"c" (count)
:"cx");
return __res;
}
extern inline void * memset(void * s,char c,size_t count)
{
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"stosb"
: /* no output */
:"a" (c),"D" (s),"c" (count)
:"cx","di","memory");
return s;
}
#include <i386/string.h> /* inline functions for i386.. */
extern char * strcpy(char *, const char *);
extern char * strncpy(char *, const char *, size_t);
extern char * strcat(char *, const char *);
extern char * strncat(char *, const char *, size_t);
extern int strcmp(const char *, const char *);
extern int strncmp(const char *, const char *, size_t);
extern char * strchr(const char *, char);
extern char * strrchr(const char *, char);
extern size_t strspn(const char *, const char *);
extern size_t strcspn(const char *, const char *);
extern char * strpbrk(const char *, const char *);
extern char * strstr(const char *, const char *);
extern size_t strlen(const char *);
extern char * strtok(char *, const char *);
extern void * memcpy(void *, const void *, size_t);
extern void * memmove(void *, const void *, size_t);
extern int memcmp(const void *, const void *, size_t);
extern void * memchr(const void *, char, size_t);
extern void * memset(void *, char, size_t);
#ifdef __cplusplus
}
......
......@@ -57,61 +57,76 @@ static int skip_atoi(const char **s)
#define SPACE 8 /* space if plus */
#define LEFT 16 /* left justified */
#define SPECIAL 32 /* 0x */
#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
#define do_div(n,base) ({ \
int __res; \
__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
__res = ((unsigned long) n) % (unsigned) base; \
n = ((unsigned long) n) / (unsigned) base; \
__res; })
static char * number(char * str, int num, int base, int size, int precision
static char * number(char * str, long num, int base, int size, int precision
,int type)
{
char c,sign,tmp[36];
const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
int i;
if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
if (type&LEFT) type &= ~ZEROPAD;
if (base<2 || base>36)
if (type & LARGE)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (type & LEFT)
type &= ~ZEROPAD;
if (base < 2 || base > 36)
return 0;
c = (type & ZEROPAD) ? '0' : ' ' ;
if (type&SIGN && num<0) {
sign='-';
c = (type & ZEROPAD) ? '0' : ' ';
sign = 0;
if (type & SIGN) {
if (num < 0) {
sign = '-';
num = -num;
} else
sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0);
if (sign) size--;
if (type&SPECIAL)
if (base==16) size -= 2;
else if (base==8) size--;
i=0;
if (num==0)
size--;
} else if (type & PLUS) {
sign = '+';
size--;
} else if (type & SPACE) {
sign = ' ';
size--;
}
}
if (type & SPECIAL) {
if (base == 16)
size -= 2;
else if (base == 8)
size--;
}
i = 0;
if (num == 0)
tmp[i++]='0';
else while (num!=0)
tmp[i++]=digits[do_div(num,base)];
if (i>precision) precision=i;
else while (num != 0)
tmp[i++] = digits[do_div(num,base)];
if (i > precision)
precision = i;
size -= precision;
if (!(type&(ZEROPAD+LEFT)))
while(size-->0)
*str++ = ' ';
if (sign)
*str++ = sign;
if (type&SPECIAL)
if (type & SPECIAL)
if (base==8)
*str++ = '0';
else if (base==16) {
*str++ = '0';
*str++ = digits[33];
}
if (!(type&LEFT))
while(size-->0)
if (!(type & LEFT))
while (size-- > 0)
*str++ = c;
while(i<precision--)
while (i < precision--)
*str++ = '0';
while(i-->0)
while (i-- > 0)
*str++ = tmp[i];
while(size-->0)
while (size-- > 0)
*str++ = ' ';
return str;
}
......@@ -119,10 +134,10 @@ static char * number(char * str, int num, int base, int size, int precision
int vsprintf(char *buf, const char *fmt, va_list args)
{
int len;
int i;
unsigned long num;
int i, base;
char * str;
char *s;
int *ip;
int flags; /* flags to number() */
......@@ -183,6 +198,9 @@ int vsprintf(char *buf, const char *fmt, va_list args)
++fmt;
}
/* default base */
base = 10;
switch (*fmt) {
case 'c':
if (!(flags & LEFT))
......@@ -191,7 +209,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
*str++ = (unsigned char) va_arg(args, int);
while (--field_width > 0)
*str++ = ' ';
break;
continue;
case 's':
s = va_arg(args, char *);
......@@ -210,12 +228,7 @@ int vsprintf(char *buf, const char *fmt, va_list args)
*str++ = *s++;
while (len < field_width--)
*str++ = ' ';
break;
case 'o':
str = number(str, va_arg(args, unsigned long), 8,
field_width, precision, flags);
break;
continue;
case 'p':
if (field_width == -1) {
......@@ -225,26 +238,34 @@ int vsprintf(char *buf, const char *fmt, va_list args)
str = number(str,
(unsigned long) va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
} else {
int * ip = va_arg(args, int *);
*ip = (str - buf);
}
continue;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
case 'x':
flags |= SMALL;
case 'X':
str = number(str, va_arg(args, unsigned long), 16,
field_width, precision, flags);
flags |= LARGE;
case 'x':
base = 16;
break;
case 'd':
case 'i':
flags |= SIGN;
case 'u':
str = number(str, va_arg(args, unsigned long), 10,
field_width, precision, flags);
break;
case 'n':
ip = va_arg(args, int *);
*ip = (str - buf);
break;
default:
......@@ -254,8 +275,20 @@ int vsprintf(char *buf, const char *fmt, va_list args)
*str++ = *fmt;
else
--fmt;
break;
continue;
}
if (qualifier == 'l')
num = va_arg(args, unsigned long);
else if (qualifier == 'h')
if (flags & SIGN)
num = va_arg(args, short);
else
num = va_arg(args, unsigned short);
else if (flags & SIGN)
num = va_arg(args, int);
else
num = va_arg(args, unsigned int);
str = number(str, num, base, field_width, precision, flags);
}
*str = '\0';
return str-buf;
......
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