Commit fdfbbb35 authored by Linus Torvalds's avatar Linus Torvalds

As promised, here is the second patch for 0.96b which hopefully clears

up the problems with some mice by implementing most of the serial line
flags like 5-8 bit characters and parity. It mainly corrects only
serial problems, but there are a couple of other patches in it too: the
fsqrt emulation patch is here, so if you already did it, you'll get a
bad patch for that file (which you can ignore). This patch also changes
all instances of signal-setting to use the "send_sig()" subroutine which
should allow gdb to debug all signals.

Apart from the serial lines, I also cleaned up the general tty-handling
routines slightly and removed at least one race-condition in the tty
code. I don't know if it's noticeable, though.

You'll need patch1 (available from all the normal sites) in order to
apply this one. As usual, I'd like to hear if this patch does help
people, or if there are new problems. This patch will also be available
on the normal ftp sites, but as it was pretty minor, I decided I might
as well include it in the post (uuencoded and compressed).

(I also corrected the all-time favourite bug: linux now reports the
right version number once more..)

            Linus
parent d667c3cc
......@@ -90,7 +90,7 @@ all: Version Image
Version:
@./makever.sh
@echo \#define UTS_RELEASE \"0.96a-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_RELEASE \"0.96b.pl2-`cat .version`\" > include/linux/config_rel.h
@echo \#define UTS_VERSION \"`date +%D`\" > include/linux/config_ver.h
touch include/linux/config.h
......
......@@ -120,6 +120,8 @@ static int check_in(select_table * wait, struct inode * inode)
if (tty = get_tty(inode))
if (!EMPTY(tty->secondary))
return 1;
else if (tty->link && !tty->link->count)
return 1;
else
add_wait(&tty->secondary->proc_list, wait);
else if (inode->i_pipe)
......
......@@ -69,24 +69,28 @@ struct serial_struct {
static inline void PUTCH(char c, struct tty_queue * queue)
{
int head;
unsigned long flags;
cli();
__asm__("pushfl ; popl %0 ; cli":"=r" (flags));
head = (queue->head + 1) & (TTY_BUF_SIZE-1);
if (head != queue->tail) {
queue->buf[queue->head] = c;
queue->head = head;
}
sti();
__asm__("pushl %0 ; popfl"::"r" (flags));
}
static inline int GETCH(struct tty_queue * queue)
{
int result = -1;
unsigned long flags;
__asm__("pushfl ; popl %0 ; cli":"=r" (flags));
if (queue->tail != queue->head) {
result = 0xff & queue->buf[queue->tail];
queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
}
__asm__("pushl %0 ; popfl"::"r" (flags));
return result;
}
......@@ -138,6 +142,7 @@ struct tty_struct {
int count;
struct winsize winsize;
void (*write)(struct tty_struct * tty);
struct tty_struct *link;
struct tty_queue *read_q;
struct tty_queue *write_q;
struct tty_queue *secondary;
......@@ -202,28 +207,40 @@ extern long con_init(long);
extern long tty_init(long);
extern void flush_input(struct tty_struct * tty);
extern void flush_output(struct tty_struct * tty);
extern void copy_to_cooked(struct tty_struct * tty);
extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned int);
extern int is_orphaned_pgrp(int pgrp);
extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty);
extern int kill_pg(int pgrp, int sig, int priv);
/* tty write functions */
extern void rs_write(struct tty_struct * tty);
extern void con_write(struct tty_struct * tty);
extern void mpty_write(struct tty_struct * tty);
extern void spty_write(struct tty_struct * tty);
/* serial.c */
extern int serial_open(unsigned int line, struct file * filp);
extern void serial_close(unsigned int line, struct file * filp);
extern void change_speed(unsigned int line);
extern void send_break(unsigned int line);
extern int get_serial_info(unsigned int, struct serial_struct *);
extern int set_serial_info(unsigned int, struct serial_struct *);
void copy_to_cooked(struct tty_struct * tty);
/* pty.c */
extern int pty_open(unsigned int dev, struct file * filp);
extern void pty_close(unsigned int dev, struct file * filp);
/* console.c */
void update_screen(int new_console);
void blank_screen(void);
void unblank_screen(void);
int kill_pg(int pgrp, int sig, int priv);
#endif
......@@ -18,6 +18,42 @@
#include <asm/system.h>
#include <asm/io.h>
#include<errno.h>
#include<fcntl.h>
int pty_open(unsigned int dev, struct file * filp)
{
struct tty_struct * tty;
tty = tty_table + dev;
if (!tty->link)
return -ENODEV;
wake_up(&tty->read_q->proc_list);
if (filp->f_flags & O_NDELAY)
return 0;
if (IS_A_PTY_MASTER(dev))
return 0;
#if 0
while (!tty->link->count && !(current->signal & ~current->blocked))
interruptible_sleep_on(&tty->link->read_q->proc_list);
if (!tty->link->count)
return -ERESTARTSYS;
#endif
return 0;
}
void pty_close(unsigned int dev, struct file * filp)
{
struct tty_struct * tty;
tty = tty_table + dev;
wake_up(&tty->read_q->proc_list);
if (IS_A_PTY_MASTER(dev)) {
if (tty->link->pgrp > 0)
kill_pg(tty->link->pgrp,SIGHUP,1);
}
}
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
{
int c;
......@@ -45,20 +81,12 @@ static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
*/
void mpty_write(struct tty_struct * tty)
{
int nr = tty - tty_table;
if ((nr >> 6) != 2)
printk("bad mpty\n\r");
else
pty_copy(tty,tty+64);
if (tty->link)
pty_copy(tty,tty->link);
}
void spty_write(struct tty_struct * tty)
{
int nr = tty - tty_table;
if ((nr >> 6) != 3)
printk("bad spty\n\r");
else
pty_copy(tty,tty-64);
if (tty->link)
pty_copy(tty,tty->link);
}
......@@ -59,6 +59,24 @@ static void modem_status_intr(struct serial_struct * info)
#endif
}
void send_break(unsigned int line)
{
unsigned short port;
struct serial_struct * info;
if (line >= NR_SERIALS)
return;
info = serial_table + line;
if (!(port = info->port))
return;
port += 3;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + 25;
outb_p(inb_p(port) | 0x40,port);
schedule();
outb_p(inb_p(port) & 0xbf,port);
}
/*
* There are several races here: we avoid most of them by disabling timer_active
* for the crucial part of the process.. That's a good idea anyway.
......@@ -94,8 +112,9 @@ static void receive_intr(struct serial_struct * info)
unsigned short port = info->port;
struct tty_queue * queue = info->tty->read_q;
while (inb(port+5) & 1)
do {
PUTCH(inb(port),queue);
} while (inb(port+5) & 1);
timer_active |= (1<<SER1_TIMER)<<info->line;
}
......@@ -130,30 +149,9 @@ static void check_tty(struct serial_struct * info)
}
}
/*
* IRQ3 normally handles com2 and com4
*/
void do_IRQ3(void)
{
check_tty(irq_info[3]);
}
/*
* IRQ4 normally handles com1 and com3
*/
void do_IRQ4(void)
void do_IRQ(int irq)
{
check_tty(irq_info[4]);
}
void do_IRQ5(void)
{
check_tty(irq_info[5]);
}
void do_IRQ9(void)
{
check_tty(irq_info[9]);
check_tty(irq_info[irq]);
}
static void com1_timer(void)
......@@ -298,6 +296,44 @@ static void startup(unsigned short port)
inb(port+2);
}
void change_speed(unsigned int line)
{
struct serial_struct * info;
unsigned short port,quot;
unsigned cflag;
static unsigned short quotient[] = {
0, 2304, 1536, 1047, 857,
768, 576, 384, 192, 96,
64, 48, 24, 12, 6, 3
};
if (line >= NR_SERIALS)
return;
info = serial_table + line;
cflag = info->tty->termios.c_cflag;
if (!(port = info->port))
return;
quot = quotient[cflag & CBAUD];
if (!quot)
outb(0x00,port+4);
else if (!inb(port+4))
startup(port);
cli();
outb_p(0x80,port+3); /* set DLAB */
outb_p(quot & 0xff,port); /* LS of divisor */
outb_p(quot >> 8,port+1); /* MS of divisor */
outb(0x03,port+3); /* reset DLAB */
sti();
/* set byte size and parity */
quot = cflag & (CSIZE | CSTOPB);
quot >>= 4;
if (cflag & PARENB)
quot |= 8;
if (!(cflag & PARODD))
quot |= 16;
outb(quot,port+3);
}
/*
* this routine enables interrupts on 'line', and disables them for any
* other serial line that shared the same IRQ. Braindamaged AT hardware.
......
......@@ -93,15 +93,11 @@ void copy_to_cooked(struct tty_struct * tty)
return;
}
while (1) {
if (EMPTY(tty->read_q))
if (FULL(tty->secondary))
break;
if (FULL(tty->secondary)) {
if (tty->secondary->proc_list)
if (tty->secondary->proc_list != current)
current->counter = 0;
break;
}
c = GETCH(tty->read_q);
if (c < 0)
break;
if (I_STRP(tty))
c &= 0x7f;
if (c==13) {
......@@ -238,11 +234,7 @@ int is_ignored(int sig)
int tty_signal(int sig, struct tty_struct *tty)
{
(void) kill_pg(current->pgrp,sig,1);
if (current->sigaction[sig-1].sa_handler)
return -EINTR; /* We _will_ be interrupted :-) */
else
return -ERESTARTSYS; /* We _will_ be interrupted :-) */
/* (but restart after we continue) */
return -ERESTARTSYS;
}
static int read_chan(unsigned int channel, struct file * file, char * buf, int nr)
......@@ -298,6 +290,8 @@ static int read_chan(unsigned int channel, struct file * file, char * buf, int n
break;
if (IS_A_PTY_SLAVE(channel) && C_HUP(other_tty))
break;
if (other_tty && !other_tty->count)
break;
interruptible_sleep_on(&tty->secondary->proc_list);
sti();
TTY_READ_FLUSH(tty);
......@@ -461,7 +455,7 @@ static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int
static int tty_open(struct inode * inode, struct file * filp)
{
struct tty_struct *tty;
int dev;
int dev, retval;
dev = inode->i_rdev;
if (MAJOR(dev) == 5)
......@@ -475,7 +469,12 @@ static int tty_open(struct inode * inode, struct file * filp)
if (tty->count)
return -EAGAIN;
}
if (!tty->count && (!tty->link || !tty->link->count)) {
flush_input(tty);
flush_output(tty);
}
tty->count++;
retval = 0;
if (!(filp->f_flags & O_NOCTTY) &&
current->leader &&
current->tty<0 &&
......@@ -485,14 +484,18 @@ static int tty_open(struct inode * inode, struct file * filp)
tty->pgrp = current->pgrp;
}
if (IS_A_SERIAL(dev))
return serial_open(dev-64,filp);
return 0;
retval = serial_open(dev-64,filp);
else if (IS_A_PTY(dev))
retval = pty_open(dev,filp);
if (retval)
tty->count--;
return retval;
}
static void tty_release(struct inode * inode, struct file * filp)
{
int dev;
struct tty_struct * tty, * slave;
struct tty_struct * tty;
dev = inode->i_rdev;
if (MAJOR(dev) == 5)
......@@ -508,11 +511,8 @@ static void tty_release(struct inode * inode, struct file * filp)
redirect = NULL;
if (IS_A_SERIAL(dev))
serial_close(dev-64,filp);
else if (IS_A_PTY_MASTER(dev)) {
slave = tty_table + PTY_OTHER(dev);
if (slave->pgrp > 0)
kill_pg(slave->pgrp,SIGHUP,1);
}
else if (IS_A_PTY(dev))
pty_close(dev,filp);
}
static struct file_operations tty_fops = {
......@@ -553,7 +553,7 @@ long tty_init(long kmem_start)
tty_table[i] = (struct tty_struct) {
{0, 0, 0, 0, 0, INIT_C_CC},
-1, 0, 0, 0, 0, {0,0,0,0},
NULL, NULL, NULL, NULL
NULL, NULL, NULL, NULL, NULL
};
}
kmem_start = con_init(kmem_start);
......@@ -572,6 +572,7 @@ long tty_init(long kmem_start)
0, /* initial count */
{video_num_lines,video_num_columns,0,0},
con_write,
NULL, /* other-tty */
con_queues+0+i*3,con_queues+1+i*3,con_queues+2+i*3
};
}
......@@ -590,6 +591,7 @@ long tty_init(long kmem_start)
0,
{25,80,0,0},
rs_write,
NULL, /* other-tty */
rs_queues+0+i*3,rs_queues+1+i*3,rs_queues+2+i*3
};
}
......@@ -608,6 +610,7 @@ long tty_init(long kmem_start)
0,
{25,80,0,0},
mpty_write,
spty_table+i,
mpty_queues+0+i*3,mpty_queues+1+i*3,mpty_queues+2+i*3
};
spty_table[i] = (struct tty_struct) {
......@@ -624,6 +627,7 @@ long tty_init(long kmem_start)
0,
{25,80,0,0},
spty_write,
mpty_table+i,
spty_queues+0+i*3,spty_queues+1+i*3,spty_queues+2+i*3
};
}
......
......@@ -21,27 +21,6 @@ extern int do_screendump(int arg);
extern int kill_pg(int pgrp, int sig, int priv);
extern int vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg);
static unsigned short quotient[] = {
0, 2304, 1536, 1047, 857,
768, 576, 384, 192, 96,
64, 48, 24, 12, 6, 3
};
static void change_speed(struct serial_struct * info)
{
unsigned short port,quot;
if (!(port = info->port))
return;
quot = quotient[info->tty->termios.c_cflag & CBAUD];
cli();
outb_p(0x80,port+3); /* set DLAB */
outb_p(quot & 0xff,port); /* LS of divisor */
outb_p(quot >> 8,port+1); /* MS of divisor */
outb(0x03,port+3); /* reset DLAB */
sti();
}
static void flush(struct tty_queue * queue)
{
if (queue) {
......@@ -58,6 +37,22 @@ void flush_input(struct tty_struct * tty)
flush(tty->secondary);
tty->secondary->data = 0;
wake_up(&tty->read_q->proc_list);
if (tty = tty->link) {
flush(tty->write_q);
wake_up(&tty->write_q->proc_list);
}
}
void flush_output(struct tty_struct * tty)
{
flush(tty->write_q);
wake_up(&tty->write_q->proc_list);
if (tty = tty->link) {
flush(tty->read_q);
flush(tty->secondary);
tty->secondary->data = 0;
wake_up(&tty->read_q->proc_list);
}
}
static void wait_until_sent(struct tty_struct * tty)
......@@ -75,20 +70,6 @@ static void wait_until_sent(struct tty_struct * tty)
sti();
}
static void send_break(struct serial_struct * info)
{
unsigned short port;
if (!(port = info->port))
return;
port += 3;
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + 25;
outb_p(inb_p(port) | 0x40,port);
schedule();
outb_p(inb_p(port) & 0xbf,port);
}
static int do_get_ps_info(int arg)
{
struct tstruct {
......@@ -145,7 +126,7 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
for (i=0 ; i< (sizeof (*termios)) ; i++)
((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
if (IS_A_SERIAL(channel))
change_speed(serial_table+channel-64);
change_speed(channel-64);
return 0;
}
......@@ -194,7 +175,7 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
for(i=0 ; i < NCC ; i++)
tty->termios.c_cc[i] = tmp_termio.c_cc[i];
if (IS_A_SERIAL(channel))
change_speed(serial_table+channel-64);
change_speed(channel-64);
return 0;
}
......@@ -261,8 +242,6 @@ int tty_ioctl(struct inode * inode, struct file * file,
return get_termios(tty,(struct termios *) arg);
case TCSETSF:
flush_input(tty);
if (other_tty)
flush(other_tty->write_q);
/* fallthrough */
case TCSETSW:
wait_until_sent(tty);
......@@ -273,8 +252,6 @@ int tty_ioctl(struct inode * inode, struct file * file,
return get_termio(tty,(struct termio *) arg);
case TCSETAF:
flush_input(tty);
if (other_tty)
flush(other_tty->write_q);
/* fallthrough */
case TCSETAW:
wait_until_sent(tty); /* fallthrough */
......@@ -285,7 +262,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
return -EINVAL;
wait_until_sent(tty);
if (!arg)
send_break(serial_table+dev-64);
send_break(dev-64);
return 0;
case TCXONC:
switch (arg) {
......@@ -308,17 +285,13 @@ int tty_ioctl(struct inode * inode, struct file * file,
}
return -EINVAL; /* not implemented */
case TCFLSH:
if (arg==0) {
if (arg==0)
flush_input(tty);
if (other_tty)
flush(other_tty->write_q);
} else if (arg==1)
flush(tty->write_q);
else if (arg==1)
flush_output(tty);
else if (arg==2) {
flush_input(tty);
flush(tty->write_q);
if (other_tty)
flush(other_tty->write_q);
flush_output(tty);
} else
return -EINVAL;
return 0;
......
......@@ -353,7 +353,7 @@ volatile void do_exit(long code)
p->p_osptr->p_ysptr = p;
p->p_pptr->p_cptr = p;
if (p->state == TASK_ZOMBIE)
p->p_pptr->signal |= (1<<(SIGCHLD-1));
send_sig(SIGCHLD,p->p_pptr,1);
/*
* process group orphan check
* Case ii: Our child is in a different pgrp
......
......@@ -55,7 +55,7 @@ void fsqrt(const temp_real * s, temp_real * d)
src[3] = s->b;
d->exponent = 0;
d->a = d->b = 0;
if (exponent) /* fsqrt(0.0) = 0.0 */
if (!exponent) /* fsqrt(0.0) = 0.0 */
return;
if (!src[2] && !src[3])
return;
......
......@@ -392,19 +392,19 @@ void do_timer(long cpl)
for (task_p = &LAST_TASK; task_p >= &FIRST_TASK; task_p--)
if (*task_p && (*task_p)->it_real_value
&& !(--(*task_p)->it_real_value)) {
(*task_p)->signal |= (1<<(SIGALRM-1));
send_sig(SIGALRM,*task_p,1);
(*task_p)->it_real_value = (*task_p)->it_real_incr;
need_resched = 1;
}
/* Update ITIMER_PROF for the current task */
if (current->it_prof_value && !(--current->it_prof_value)) {
current->it_prof_value = current->it_prof_incr;
current->signal |= (1<<(SIGPROF-1));
send_sig(SIGPROF,current,1);
}
/* Update ITIMER_VIRT for current task if not in a system call */
if (cpl && current->it_virt_value && !(--current->it_virt_value)) {
current->it_virt_value = current->it_virt_incr;
current->signal |= (1<<(SIGVTALRM-1));
send_sig(SIGVTALRM,current,1);
}
if (cpl)
......
......@@ -258,7 +258,9 @@ _IRQ3_interrupt:
SAVE_ALL
ACK_FIRST(0x08)
sti
call _do_IRQ3
pushl $3
call _do_IRQ
addl $4,%esp
cli
UNBLK_FIRST(0x08)
jmp ret_from_sys_call
......@@ -269,7 +271,9 @@ _IRQ4_interrupt:
SAVE_ALL
ACK_FIRST(0x10)
sti
call _do_IRQ4
pushl $4
call _do_IRQ
addl $4,%esp
cli
UNBLK_FIRST(0x10)
jmp ret_from_sys_call
......@@ -280,7 +284,9 @@ _IRQ5_interrupt:
SAVE_ALL
ACK_FIRST(0x20)
sti
call _do_IRQ5
pushl $5
call _do_IRQ
addl $4,%esp
cli
UNBLK_FIRST(0x20)
jmp ret_from_sys_call
......@@ -291,7 +297,9 @@ _IRQ9_interrupt:
SAVE_ALL
ACK_SECOND(0x02)
sti
call _do_IRQ9
pushl $9
call _do_IRQ
addl $4,%esp
cli
UNBLK_SECOND(0x02)
jmp ret_from_sys_call
......
......@@ -418,7 +418,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
if (avail <= 0) {
PRINTK("unix_proto_read: AVAIL IS NEGATIVE!!!\n");
current->signal |= (1 << (SIGKILL-1));
send_sig(SIGKILL,current,1);
return -EINTR;
}
......@@ -456,7 +456,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if (sock->state != SS_CONNECTED) {
PRINTK("unix_proto_write: socket not connected\n");
if (sock->state == SS_DISCONNECTING) {
current->signal |= (1 << (SIGPIPE-1));
send_sig(SIGPIPE,current,1);
return -EINTR;
}
return -EINVAL;
......@@ -474,7 +474,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
}
if (sock->state == SS_DISCONNECTING) {
PRINTK("unix_proto_write: disconnected (SIGPIPE)\n");
current->signal |= (1 << (SIGPIPE-1));
send_sig(SIGPIPE,current,1);
return -EINTR;
}
}
......@@ -488,7 +488,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if (space <= 0) {
PRINTK("unix_proto_write: SPACE IS NEGATIVE!!!\n");
current->signal |= (1 << (SIGKILL-1));
send_sig(SIGKILL,current,1);
return -EINTR;
}
......@@ -497,7 +497,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
* for it (peerupd is safe until we close)
*/
if (sock->state == SS_DISCONNECTING) {
current->signal |= (1 << (SIGPIPE-1));
send_sig(SIGPIPE,current,1);
return -EINTR;
}
if ((cando = todo) > space)
......
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