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

Import 1.1.94

parent fde9fa96
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 93
SUBLEVEL = 94
ARCH = i386
......
......@@ -145,6 +145,18 @@ entUna:
rti
.end entUna
.align 5
.globl entSys
.ent entSys
entSys:
SAVE_ALL
bis $30,$30,$19
lda $27,do_entSys
jsr $26,($27),do_entSys
RESTORE_ALL
rti
.end entSys
.align 5
.globl sys_call_table
sys_call_table:
......
......@@ -60,19 +60,19 @@ void flush_thread(void)
}
/*
* This needs lots of work still..
* This needs some work still..
*/
unsigned long copy_thread(int nr, unsigned long clone_flags, struct task_struct * p, struct pt_regs * regs)
void copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
struct task_struct * p, struct pt_regs * regs)
{
struct pt_regs * childregs;
p->tss.usp = rdusp();
p->tss.usp = usp;
childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1;
*childregs = *regs;
p->tss.ksp = (unsigned long) childregs;
/* p->tss.pc = XXXX; */
halt();
return clone_flags;
panic("copy_thread not implemented");
}
/*
......@@ -84,9 +84,51 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
/*
* sys_execve() executes a new program.
*
* This works due to the alpha calling sequence: the first 6 args
* are gotten from registers, while the rest is on the stack, so
* we get a0-a5 for free, and then magically find "struct pt_regs"
* on the stack for us..
*
* Don't do this at home.
*/
asmlinkage int sys_execve(struct pt_regs regs)
asmlinkage int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
halt();
return 0;
int error;
char * filename;
error = getname((char *) a0, &filename);
if (error)
return error;
error = do_execve(filename, (char **) a1, (char **) a2, &regs);
putname(filename);
return error;
}
/*
* sys_fork() does the obvious thing, but not the obvious way.
* See sys_execve() above.
*/
asmlinkage int sys_fork(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
return do_fork(COPYVM | SIGCHLD, rdusp(), &regs);
}
asmlinkage int sys_clone(unsigned long a0, unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4, unsigned long a5,
struct pt_regs regs)
{
unsigned long clone_flags = a0;
unsigned long newsp;
newsp = rdusp();
if (newsp == a1 || !a1)
clone_flags |= COPYVM;
else
newsp = a1;
return do_fork(clone_flags, newsp, &regs);
}
......@@ -38,10 +38,28 @@ asmlinkage void do_entUna(unsigned long va, unsigned long opcode, unsigned long
die_if_kernel("Unaligned", regs, 0);
}
/*
* DEC means people to use the "retsys" instruction for return from
* a system call, but they are clearly misguided about this. We use
* "rti" in all cases, and fill in the stack with the return values.
* That should make signal handling etc much cleaner.
*
* Even more horribly, DEC doesn't allow system calls from kernel mode.
* "Security" features letting the user do something the kernel can't
* are a thinko. DEC palcode is strange. The PAL-code designers probably
* got terminally tainted by VMS at some point.
*/
asmlinkage void do_entSys(unsigned long sysnr, unsigned long arg1, unsigned long arg2, struct pt_regs *regs)
{
printk("System call %ld(%ld,%ld)\n", sysnr, arg1, arg2);
die_if_kernel("Syscall", regs, 0);
}
extern asmlinkage void entMM(void);
extern asmlinkage void entIF(void);
extern asmlinkage void entArith(void);
extern asmlinkage void entUna(void);
extern asmlinkage void entSys(void);
void trap_init(void)
{
......@@ -59,4 +77,5 @@ void trap_init(void)
wrent(entMM, 2);
wrent(entIF, 3);
wrent(entUna, 4);
wrent(entSys, 5);
}
......@@ -150,9 +150,8 @@ void flush_thread(void)
current->debugreg[i] = 0;
}
#define IS_CLONE (regs->orig_eax == __NR_clone)
unsigned long copy_thread(int nr, unsigned long clone_flags, struct task_struct * p, struct pt_regs * regs)
void copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
struct task_struct * p, struct pt_regs * regs)
{
int i;
struct pt_regs * childregs;
......@@ -171,15 +170,9 @@ unsigned long copy_thread(int nr, unsigned long clone_flags, struct task_struct
p->tss.eip = (unsigned long) ret_from_sys_call;
*childregs = *regs;
childregs->eax = 0;
childregs->esp = esp;
p->tss.back_link = 0;
p->tss.eflags = regs->eflags & 0xffffcfff; /* iopl is always 0 for a new process */
if (IS_CLONE) {
if (regs->ebx)
childregs->esp = regs->ebx;
clone_flags = regs->ecx;
if (childregs->esp == regs->esp)
clone_flags |= COPYVM;
}
p->tss.ldt = _LDT(nr);
if (p->ldt) {
p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
......@@ -196,7 +189,6 @@ unsigned long copy_thread(int nr, unsigned long clone_flags, struct task_struct
p->tss.io_bitmap[i] = ~0;
if (last_task_used_math == current)
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
return clone_flags;
}
/*
......@@ -238,6 +230,25 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
}
}
asmlinkage int sys_fork(struct pt_regs regs)
{
return do_fork(COPYVM | SIGCHLD, regs.esp, &regs);
}
asmlinkage int sys_clone(struct pt_regs regs)
{
unsigned long clone_flags;
unsigned long newsp;
newsp = regs.ebx;
clone_flags = regs.ecx;
if (!newsp)
newsp = regs.esp;
if (newsp == regs.esp)
clone_flags |= COPYVM;
return do_fork(clone_flags, newsp, &regs);
}
/*
* sys_execve() executes a new program.
*/
......
#define THREE_LEVEL
/* ptrace.c */
/* By Ross Biro 1/23/92 */
/* edited by Linus Torvalds */
......@@ -86,11 +87,12 @@ static inline int put_stack_long(struct task_struct *task, int offset,
static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
{
pgd_t * pgdir;
pmd_t * pgmiddle;
pte_t * pgtable;
unsigned long page;
repeat:
pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
pgdir = pgd_offset(vma->vm_task, addr);
if (pgd_none(*pgdir)) {
do_no_page(vma, addr, 0);
goto repeat;
......@@ -100,7 +102,17 @@ static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
pgd_clear(pgdir);
return 0;
}
pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
do_no_page(vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
pmd_clear(pgmiddle);
return 0;
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
do_no_page(vma, addr, 0);
goto repeat;
......@@ -126,11 +138,12 @@ static void put_long(struct vm_area_struct * vma, unsigned long addr,
unsigned long data)
{
pgd_t *pgdir;
pmd_t *pgmiddle;
pte_t *pgtable;
unsigned long page;
repeat:
pgdir = PAGE_DIR_OFFSET(vma->vm_task, addr);
pgdir = pgd_offset(vma->vm_task, addr);
if (!pgd_present(*pgdir)) {
do_no_page(vma, addr, 1);
goto repeat;
......@@ -140,7 +153,17 @@ static void put_long(struct vm_area_struct * vma, unsigned long addr,
pgd_clear(pgdir);
return;
}
pgtable = (pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
pgmiddle = pmd_offset(pgdir, addr);
if (pmd_none(*pgmiddle)) {
do_no_page(vma, addr, 0);
goto repeat;
}
if (pmd_bad(*pgmiddle)) {
printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle));
pmd_clear(pgmiddle);
return;
}
pgtable = pte_offset(pgmiddle, addr);
if (!pte_present(*pgtable)) {
do_no_page(vma, addr, 1);
goto repeat;
......
......@@ -14,11 +14,6 @@
extern unsigned long pg0[1024]; /* page table for 0-4MB for everybody */
extern void die_if_kernel(char *,struct pt_regs *,long);
/* Sparc stuff... I know this is a ugly place to put the PROM vector, don't
* remind me.
*/
extern unsigned int trapbase[];
extern unsigned int end[], etext[], msgbuf[];
struct linux_romvec *romvec;
/* foo */
......
......@@ -160,7 +160,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
* self-modifying code.
*/
a= (unsigned long) etext;
a= (unsigned long) &etext;
mask=~(PTE_NC|PTE_W); /* make cacheable + not writable */
printk("changing kernel text perms...\n");
......@@ -173,7 +173,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
for(i=0; i<8; i++)
{
b=PAGE_ALIGN((unsigned long) trapbase);
b=PAGE_ALIGN((unsigned long) &trapbase);
switch_to_context(i);
......
......@@ -4,7 +4,7 @@
* This is a modified version of the CDU-31A device driver (see below).
* Changes were made using documentation for the CDU-531 (which Sony
* assures me is very similar to the 535) and partial disassembly of the
* DOS driver. I used Minyard's driver and replaced the the CDU-31A
* DOS driver. I used Minyard's driver and replaced the the CDU-31A
* commands with the CDU-531 commands. This was complicated by a different
* interface protocol with the drive. The driver is still polled.
*
......@@ -23,18 +23,23 @@
*
* Things to do:
* - handle errors and status better, put everything into a single word
* - use interrupts, DMA
* - use interrupts (code mostly there, but a big hole still missing)
* - handle multi-session CDs?
* - use DMA?
*
* Known Bugs:
* -
*
* Ken Pizzini (ken@halcyon.com)
*
* Original by:
* Ron Jeppesen (ronj.an@site007.saic.com)
*
*
*------------------------------------------------------------------------
* Sony CDROM interface device driver.
*
* Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to ronj above)
* Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above)
*
* Colossians 3:17
*
......@@ -99,6 +104,9 @@
# include <linux/module.h>
# include <linux/malloc.h>
# include <linux/version.h>
# ifndef CONFIG_MODVERSIONS
char kernel_version[]= UTS_RELEASE;
# endif
#endif
#include <linux/errno.h>
......@@ -137,9 +145,11 @@
* proper address.
*/
#ifndef CDU535_ADDRESS
# define CDU535_ADDRESS (0x340)
# define CDU535_ADDRESS 0x340
#endif
#ifndef CDU535_INTERRUPT
# define CDU535_INTERRUPT 0
#endif
#ifndef CDU535_HANDLE
# define CDU535_HANDLE "cdu535"
#endif
......@@ -171,7 +181,9 @@
* if LOCK_DOORS is defined then the eject button is disabled while
* the device is open.
*/
#define LOCK_DOORS
#ifndef NO_LOCK_DOORS
# define LOCK_DOORS
#endif
static int read_subcode(void);
static void sony_get_toc(void);
......@@ -179,11 +191,14 @@ static int cdu_open(struct inode *inode, struct file *filp);
static inline unsigned int int_to_bcd(unsigned int val);
static unsigned int bcd_to_int(unsigned int bcd);
static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2],
Byte * response, int nResponse, int ignoreStatusBit7);
Byte * response, int n_response, int ignoreStatusBit7);
/* The base I/O address of the Sony Interface. This is a variable (not a
#define) so it can be easily changed via some future ioctl() */
static unsigned short sony_cd_base_io = CDU535_ADDRESS;
#ifndef MODULE
static
#endif
unsigned short sony535_cd_base_io = CDU535_ADDRESS;
/*
* The following are I/O addresses of the various registers for the drive. The
......@@ -217,10 +232,10 @@ static struct s535_sony_toc *sony_toc; /* Points to the table of
static struct s535_sony_subcode *last_sony_subcode; /* Points to the last
subcode address read */
#ifndef MODULE
static unsigned char *sony_buffer; /* Points to the read-ahead buffer */
static Byte *sony_buffer; /* Points to the read-ahead buffer */
#else
static unsigned char **sony_buffer; /* Points to the pointers
to the sector buffers */
static Byte **sony_buffer; /* Points to the pointers
to the sector buffers */
#endif
static int sony_inuse = 0; /* is the drive in use? Only one
open at a time allowed */
......@@ -240,8 +255,17 @@ static int sony_audio_status = CDROM_AUDIO_NO_STATUS;
* I just kept the CDU-31A driver behavior rather than using the PAUSE
* command on the CDU-535.
*/
static unsigned char cur_pos_msf[3] = {0, 0, 0};
static unsigned char final_pos_msf[3] = {0, 0, 0};
static Byte cur_pos_msf[3] = {0, 0, 0};
static Byte final_pos_msf[3] = {0, 0, 0};
/* What IRQ is the drive using? 0 if none. */
#ifndef MODULE
static
#endif
int sony535_irq_used = CDU535_INTERRUPT;
/* The interrupt handler will wake this queue up when it gets an interrupt. */
static struct wait_queue *cdu535_irq_wait = NULL;
/*
......@@ -251,10 +275,10 @@ static unsigned char final_pos_msf[3] = {0, 0, 0};
static int
cdu535_check_media_change(dev_t full_dev)
{
int retval;
int retval;
if (MINOR(full_dev) != 0) {
printk("Sony CD-ROM request error: invalid device.\n");
printk(CDU535_MESSAGE_NAME " request error: invalid device.\n");
return 0;
}
......@@ -264,18 +288,64 @@ cdu535_check_media_change(dev_t full_dev)
return retval;
}
static inline void
enable_interrupts(void)
{
#ifdef USE_IRQ
/* this code snarfed from cdu31a.c; it will not
* directly work for the cdu535 as written...
*/
curr_control_reg |= ( SONY_ATTN_INT_EN_BIT
| SONY_RES_RDY_INT_EN_BIT
| SONY_DATA_RDY_INT_EN_BIT);
outb(curr_control_reg, sony_cd_control_reg);
#endif
}
static inline void
disable_interrupts(void)
{
#ifdef USE_IRQ
/* this code snarfed from cdu31a.c; it will not
* directly work for the cdu535 as written...
*/
curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT
| SONY_RES_RDY_INT_EN_BIT
| SONY_DATA_RDY_INT_EN_BIT);
outb(curr_control_reg, sony_cd_control_reg);
#endif
}
static void
cdu535_interrupt(int irq, struct pt_regs *regs)
{
disable_interrupts();
if (cdu535_irq_wait != NULL)
wake_up(&cdu535_irq_wait);
else
printk(CDU535_MESSAGE_NAME
": Got an interrupt but nothing was waiting\n");
}
/*
* Wait a little while (used for polling the drive). If in initialization,
* setting a timeout doesn't work, so just loop for a while (we trust
* that the sony_sleep() call is protected by a test for proper jiffies count).
* setting a timeout doesn't work, so just loop for a while. (We trust
* that the sony_sleep() call is protected by a test for proper jiffies count.)
*/
static inline void
sony_sleep(void)
{
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies;
schedule();
if (sony535_irq_used <= 0) { /* poll */
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies;
schedule();
} else { /* Interrupt driven */
cli();
enable_interrupts();
interruptible_sleep_on(&cdu535_irq_wait);
sti();
}
}
/*------------------start of SONY CDU535 very specific ---------------------*/
......@@ -293,23 +363,24 @@ select_unit(int unit_no)
}
/***************************************************************************
* int read_result_reg( unsigned char *data_ptr )
* int read_result_reg( Byte *data_ptr )
*
* Read a result byte from the Sony CDU controller, store in location pointed
* to by data_ptr. Return zero on success, TIME_OUT if we did not receive
* data.
***************************************************************************/
static int
read_result_reg(unsigned char *data_ptr)
read_result_reg(Byte *data_ptr)
{
int retry_count;
int read_status;
int retry_count;
int read_status;
retry_count = jiffies + SONY_JIFFIES_TIMEOUT;
while (jiffies < retry_count) {
if (((read_status = inb(read_status_reg)) & SONY535_RESULT_NOT_READY_BIT) == 0) {
#if DEBUG > 1
printk("read_result_reg(): readStatReg = 0x%x\n", read_status);
printk(CDU535_MESSAGE_NAME
": read_result_reg(): readStatReg = 0x%x\n", read_status);
#endif
*data_ptr = inb(result_reg);
return 0;
......@@ -317,14 +388,14 @@ read_result_reg(unsigned char *data_ptr)
sony_sleep();
}
}
printk(" Sony CDROM read_result_reg: TIME OUT!\n");
printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n");
return TIME_OUT;
}
/****************************************************************************
* int read_exec_status( Byte status[2] )
*
* Read the execution status of the last command and put into status.
* Read the execution status of the last command and put into status.
* Handles reading second status word if available. Returns 0 on success,
* TIME_OUT on failure.
****************************************************************************/
......@@ -339,10 +410,8 @@ read_exec_status(Byte status[2])
return TIME_OUT;
}
#if DEBUG > 1
printk("read_exec_status: read 0x%x\n", status[0]);
if (status[0] & 0x80)
printk(" and 0x%x\n", status[1]);
printk("\n");
printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n",
status[0], status[1]);
#endif
return 0;
}
......@@ -357,9 +426,9 @@ read_exec_status(Byte status[2])
static int
check_drive_status(void)
{
Byte status, e_status[2];
int CDD, ATN;
unsigned char cmd;
Byte status, e_status[2];
int CDD, ATN;
Byte cmd;
select_unit(0);
if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */
......@@ -387,7 +456,7 @@ check_drive_status(void)
return TIME_OUT;
#if DEBUG > 1
printk("--check_drive_status() got 0x%x\n", status);
printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status);
#endif
if (status == 0)
......@@ -401,17 +470,17 @@ check_drive_status(void)
break; /* go on to CDD stuff */
case SONY535_ATN_BUSY:
if (initialized)
printk("Sony CDROM error, drive busy\n");
printk(CDU535_MESSAGE_NAME " error: drive busy\n");
return CD_BUSY;
case SONY535_ATN_EJECT_IN_PROGRESS:
printk("Sony CDROM error, eject in progress\n");
printk(CDU535_MESSAGE_NAME " error: eject in progress\n");
sony_audio_status = CDROM_AUDIO_INVALID;
return CD_BUSY;
case SONY535_ATN_RESET_OCCURRED:
case SONY535_ATN_DISC_CHANGED:
case SONY535_ATN_RESET_AND_DISC_CHANGED:
#if DEBUG > 0
printk("Sony CDROM, reset occurred or disc changed\n");
printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n");
#endif
sony_disc_changed = 1;
sony_toc_read = 0;
......@@ -425,16 +494,17 @@ check_drive_status(void)
}
return 0;
default:
printk("Sony CDROM error, drive busy (ATN=0x%x)\n", ATN);
printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN);
return CD_BUSY;
}
switch (CDD) { /* the 531 docs are not helpful in decoding this */
case 0x0: /* just use the values from the DOS driver */
switch (CDD) { /* the 531 docs are not helpful in decoding this */
case 0x0: /* just use the values from the DOS driver */
case 0x2:
case 0xa:
break; /* no error */
break; /* no error */
case 0xc:
printk("check_drive_status(): CDD = 0xc! Not properly handled!\n");
printk(CDU535_MESSAGE_NAME
": check_drive_status(): CDD = 0xc! Not properly handled!\n");
return CD_BUSY; /* ? */
default:
return CD_BUSY;
......@@ -443,14 +513,14 @@ check_drive_status(void)
} /* check_drive_status() */
/*****************************************************************************
* int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2],
* int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2],
* Byte *response, int n_response, int ignore_status_bit7 )
*
* Generic routine for executing commands. The command and its parameters
* should be placed in the cmd[] array, number of bytes in the command is
* stored in nCmd. The response from the command will be stored in the
* response array. The number of bytes you expect back (excluding status)
* should be passed in nResponse. Finally, some
* should be passed in n_response. Finally, some
* commands set bit 7 of the return status even when there is no second
* status byte, on these commands set ignoreStatusBit7 TRUE.
* If the command was sent and data received back, then we return 0,
......@@ -462,7 +532,7 @@ static int
do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2],
Byte * response, int n_response, int ignore_status_bit7)
{
int i;
int i;
/* write out the command */
for (i = 0; i < n_cmd; i++)
......@@ -471,7 +541,7 @@ do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2],
/* read back the status */
if (read_result_reg(status) != 0)
return TIME_OUT;
if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) {
if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) {
/* get second status byte */
if (read_result_reg(status + 1) != 0)
return TIME_OUT;
......@@ -479,7 +549,8 @@ do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2],
status[1] = 0;
}
#if DEBUG > 2
printk("do_sony_cmd %x: %x %x\n", *cmd, status[0], status[1]);
printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n",
*cmd, status[0], status[1]);
#endif
/* do not know about when I should read set of data and when not to */
......@@ -502,7 +573,8 @@ do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2],
static int
set_drive_mode(int mode, Byte status[2])
{
Byte cmd_buff[2], ret_buff[1];
Byte cmd_buff[2];
Byte ret_buff[1];
cmd_buff[0] = SONY535_SET_DRIVE_MODE;
cmd_buff[1] = mode;
......@@ -510,7 +582,7 @@ set_drive_mode(int mode, Byte status[2])
}
/***************************************************************************
* int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2],
* int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2],
* Byte *data_buff, int buff_size )
*
* Read n_blocks of data from the CDROM starting at position params[0:2],
......@@ -527,19 +599,19 @@ seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
Byte * data_buff, int buf_size)
#else
seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
unsigned char **buff, int buf_size)
Byte **buff, int buf_size)
#endif
{
int i;
const int block_size = 2048;
Byte cmd_buff[7];
int read_status;
int retry_count;
#ifdef MODULE
Byte *data_buff;
int sector_count = 0;
Byte cmd_buff[7];
int i;
int read_status;
int retry_count;
#ifndef MODULE
Byte *start_pos = data_buff;
#else
Byte *start_pos = data_buff;
Byte *data_buff;
int sector_count = 0;
#endif
if (buf_size < ((long)block_size) * n_blocks)
......@@ -598,11 +670,11 @@ seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2],
static int
request_toc_data(Byte status[2], struct s535_sony_toc *toc)
{
int to_status;
int i, j, n_tracks, track_no;
Byte cmd_no = 0xb2;
Byte track_address_buffer[5];
int first_track_num, last_track_num;
int to_status;
int i, j, n_tracks, track_no;
int first_track_num, last_track_num;
Byte cmd_no = 0xb2;
Byte track_address_buffer[5];
/* read the fixed portion of the table of contents */
if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0)
......@@ -636,19 +708,19 @@ request_toc_data(Byte status[2], struct s535_sony_toc *toc)
static int
spin_up_drive(Byte status[2])
{
Byte cmd_buff[1];
Byte cmd;
/* first see if the drive is already spinning */
cmd_buff[0] = SONY535_REQUEST_DRIVE_STATUS_1;
if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0)
cmd = SONY535_REQUEST_DRIVE_STATUS_1;
if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0)
return TIME_OUT;
if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0)
return 0; /* its already spinning */
return 0; /* its already spinning */
/* else, give the spin-up command */
cmd_buff[0] = SONY535_SPIN_UP;
return do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
} /* spin_up_drive() */
/* otherwise, give the spin-up command */
cmd = SONY535_SPIN_UP;
return do_sony_cmd(&cmd, 1, status, NULL, 0, 0);
}
/*--------------------end of SONY CDU535 very specific ---------------------*/
......@@ -656,8 +728,7 @@ spin_up_drive(Byte status[2])
static inline unsigned int
int_to_bcd(unsigned int val)
{
int retval;
int retval;
retval = (val / 10) << 4;
retval = retval | val % 10;
......@@ -678,7 +749,7 @@ bcd_to_int(unsigned int bcd)
* a block device) to an MSF format.
*/
static void
log_to_msf(unsigned int log, unsigned char *msf)
log_to_msf(unsigned int log, Byte *msf)
{
log = log + LOG_START_OFFSET;
msf[0] = int_to_bcd(log / 4500);
......@@ -692,7 +763,7 @@ log_to_msf(unsigned int log, unsigned char *msf)
* Convert an MSF format to a logical sector.
*/
static unsigned int
msf_to_log(unsigned char *msf)
msf_to_log(Byte *msf)
{
unsigned int log;
......@@ -711,8 +782,7 @@ msf_to_log(unsigned char *msf)
* the drive would want to see a number-of-sector value.
*/
static void
size_to_buf(unsigned int size,
unsigned char *buf)
size_to_buf(unsigned int size, Byte *buf)
{
buf[0] = size / 65536;
size = size % 65536;
......@@ -731,14 +801,15 @@ size_to_buf(unsigned int size,
static void
do_cdu535_request(void)
{
int block;
unsigned int dev;
int nsect;
unsigned char params[10];
int copyoff;
int spin_up_retry;
unsigned int read_size;
unsigned char status[2], cmd[2];
int block;
int nsect;
int copyoff;
int spin_up_retry;
Byte params[10];
Byte status[2];
Byte cmd[2];
if (!sony_inuse) {
......@@ -798,33 +869,37 @@ do_cdu535_request(void)
size_to_buf(read_size, &params[3]);
/*
* Read the data. If the drive was not spinning, spin it up and try
* once more. I know, the goto is ugly, but I am too lazy to fix it.
* Read the data. If the drive was not spinning,
* spin it up and try once more.
*/
spin_up_retry = 0;
try_read_again:
for (;;) {
#if DEBUG > 1
if (check_drive_status() != 0) { /* drive not ready */
sony_first_block = -1;
sony_last_block = -1;
end_request(0);
return;
}
if (check_drive_status() != 0) {
/* drive not ready */
sony_first_block = -1;
sony_last_block = -1;
end_request(0);
return;
}
#endif
if (seek_and_read_N_blocks(params, read_size, status, sony_buffer,
(read_size * 2048)) < 0) {
if ((status[0] & SONY535_STATUS1_NOT_SPINNING) && (!spin_up_retry)) {
printk(" Sony535 Debug -- calling spin up when reading data!\n");
cmd[0] = SONY535_SPIN_UP;
do_sony_cmd(cmd, 1, status, NULL, 0, 0);
spin_up_retry = 1;
goto try_read_again;
if (0 <= seek_and_read_N_blocks(params, read_size,
status, sony_buffer, (read_size * 2048)))
break;
if (!(status[0] & SONY535_STATUS1_NOT_SPINNING) ||
spin_up_retry) {
printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n",
status[0]);
sony_first_block = -1;
sony_last_block = -1;
end_request(0);
return;
}
printk("Sony CDROM Read error: 0x%.2x\n", status[0]);
sony_first_block = -1;
sony_last_block = -1;
end_request(0);
return;
printk(CDU535_MESSAGE_NAME
" debug: calling spin up when reading data!\n");
cmd[0] = SONY535_SPIN_UP;
do_sony_cmd(cmd, 1, status, NULL, 0, 0);
spin_up_retry = 1;
}
}
/*
......@@ -866,7 +941,7 @@ do_cdu535_request(void)
static void
sony_get_toc(void)
{
unsigned char status[2];
Byte status[2];
if (!sony_toc_read) {
/* do not call check_drive_status() from here since it can call this routine */
if (request_toc_data(status, sony_toc) < 0)
......@@ -884,8 +959,8 @@ sony_get_toc(void)
static int
find_track(int track)
{
int i;
int num_tracks;
int i;
int num_tracks;
num_tracks = bcd_to_int(sony_toc->last_track_num) -
......@@ -905,16 +980,17 @@ find_track(int track)
static int
read_subcode(void)
{
Byte cmd = SONY535_REQUEST_SUB_Q_DATA, status[2];
int dsc_status;
Byte cmd = SONY535_REQUEST_SUB_Q_DATA;
Byte status[2];
int dsc_status;
if (check_drive_status() != 0)
return -EIO;
if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode,
sizeof (struct s535_sony_subcode), 1)) != 0) {
printk("Sony CDROM error 0x%.2x, %d (read_subcode)\n", status[0],
dsc_status);
sizeof(struct s535_sony_subcode), 1)) != 0) {
printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n",
status[0], dsc_status);
return -EIO;
}
return 0;
......@@ -942,9 +1018,9 @@ sony_get_subchnl_info(long arg)
if (!sony_toc_read) {
return -EIO;
}
verify_area(VERIFY_WRITE /* and read */ , (char *)arg, sizeof (schi));
verify_area(VERIFY_WRITE /* and read */ , (char *)arg, sizeof schi);
memcpy_fromfs(&schi, (char *)arg, sizeof (schi));
memcpy_fromfs(&schi, (char *)arg, sizeof schi);
switch (sony_audio_status) {
case CDROM_AUDIO_PLAY:
......@@ -959,7 +1035,7 @@ sony_get_subchnl_info(long arg)
case CDROM_AUDIO_NO_STATUS:
schi.cdsc_audiostatus = sony_audio_status;
memcpy_tofs((char *)arg, &schi, sizeof (schi));
memcpy_tofs((char *)arg, &schi, sizeof schi);
return 0;
break;
......@@ -986,7 +1062,7 @@ sony_get_subchnl_info(long arg)
schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
}
memcpy_tofs((char *)arg, &schi, sizeof (schi));
memcpy_tofs((char *)arg, &schi, sizeof schi);
return 0;
}
......@@ -1001,9 +1077,9 @@ cdu_ioctl(struct inode *inode,
unsigned long arg)
{
unsigned int dev;
unsigned char status[2];
unsigned char cmd_buff[10], params[10];
int i, dsc_status;
Byte status[2];
Byte cmd_buff[10], params[10];
int i, dsc_status;
if (!inode) {
......@@ -1019,7 +1095,8 @@ cdu_ioctl(struct inode *inode,
switch (cmd) {
case CDROMSTART: /* Spin up the drive */
if (spin_up_drive(status) < 0) {
printk("Sony CDROM error 0x%.2x (CDROMSTART)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n",
status[0]);
return -EIO;
}
return 0;
......@@ -1038,7 +1115,8 @@ cdu_ioctl(struct inode *inode,
dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0);
if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) ||
((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) {
printk("Sony CDROM error 0x%.2x (CDROMSTOP)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n",
status[0]);
return -EIO;
}
return 0;
......@@ -1047,7 +1125,8 @@ cdu_ioctl(struct inode *inode,
case CDROMPAUSE: /* Pause the drive */
cmd_buff[0] = SONY535_HOLD; /* CDU-31 driver uses AUDIO_STOP, not pause */
if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
printk("Sony CDROM error 0x%.2x (CDROMPAUSE)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n",
status[0]);
return -EIO;
}
/* Get the current position and save it for resuming */
......@@ -1082,7 +1161,8 @@ cdu_ioctl(struct inode *inode,
cmd_buff[9] = final_pos_msf[2];
if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
printk("Sony CDROM error 0x%.2x (CDROMRESUME)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n",
status[0]);
return -EIO;
}
sony_audio_status = CDROM_AUDIO_PLAY;
......@@ -1108,7 +1188,8 @@ cdu_ioctl(struct inode *inode,
/* cmd_buff[7-9] are filled in for loop above */
if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
printk("Sony CDROM error 0x%.2x (CDROMPLAYMSF)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n",
status[0]);
return -EIO;
}
/* Save the final position for pauses and resumes */
......@@ -1128,10 +1209,10 @@ cdu_ioctl(struct inode *inode,
if (!sony_toc_read)
return -EIO;
hdr = (struct cdrom_tochdr *)arg;
verify_area(VERIFY_WRITE, hdr, sizeof (*hdr));
verify_area(VERIFY_WRITE, hdr, sizeof *hdr);
loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
memcpy_tofs(hdr, &loc_hdr, sizeof (*hdr));
memcpy_tofs(hdr, &loc_hdr, sizeof *hdr);
}
return 0;
break;
......@@ -1140,17 +1221,17 @@ cdu_ioctl(struct inode *inode,
{
struct cdrom_tocentry *entry;
struct cdrom_tocentry loc_entry;
int track_idx;
unsigned char *msf_val = NULL;
int track_idx;
Byte *msf_val = NULL;
sony_get_toc();
if (!sony_toc_read) {
return -EIO;
}
entry = (struct cdrom_tocentry *)arg;
verify_area(VERIFY_WRITE /* and read */ , entry, sizeof (*entry));
verify_area(VERIFY_WRITE /* and read */ , entry, sizeof *entry);
memcpy_fromfs(&loc_entry, entry, sizeof (loc_entry));
memcpy_fromfs(&loc_entry, entry, sizeof loc_entry);
/* Lead out is handled separately since it is special. */
if (loc_entry.cdte_track == CDROM_LEADOUT) {
......@@ -1174,7 +1255,7 @@ cdu_ioctl(struct inode *inode,
loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1));
loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2));
}
memcpy_tofs(entry, &loc_entry, sizeof (*entry));
memcpy_tofs(entry, &loc_entry, sizeof *entry);
}
return 0;
break;
......@@ -1182,14 +1263,14 @@ cdu_ioctl(struct inode *inode,
case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */
{
struct cdrom_ti ti;
int track_idx;
int track_idx;
sony_get_toc();
if (!sony_toc_read)
return -EIO;
verify_area(VERIFY_READ, (char *)arg, sizeof (ti));
verify_area(VERIFY_READ, (char *)arg, sizeof ti);
memcpy_fromfs(&ti, (char *)arg, sizeof (ti));
memcpy_fromfs(&ti, (char *)arg, sizeof ti);
if ((ti.cdti_trk0 < sony_toc->first_track_num)
|| (sony_toc->last_track_num < ti.cdti_trk0)
|| (ti.cdti_trk1 < ti.cdti_trk0)) {
......@@ -1234,9 +1315,11 @@ cdu_ioctl(struct inode *inode,
cmd_buff[9] = params[6];
if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) ||
(do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) {
printk("Params: %x %x %x %x %x %x %x\n", params[0], params[1],
params[2], params[3], params[4], params[5], params[6]);
printk("Sony CDROM error 0x%.2x (CDROMPLAYTRKIND)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n",
status[0]);
printk("... Params: %x %x %x %x %x %x %x\n",
params[0], params[1], params[2],
params[3], params[4], params[5], params[6]);
return -EIO;
}
/* Save the final position for pauses and resumes */
......@@ -1254,14 +1337,15 @@ cdu_ioctl(struct inode *inode,
{
struct cdrom_volctrl volctrl;
verify_area(VERIFY_READ, (char *)arg, sizeof (volctrl));
verify_area(VERIFY_READ, (char *)arg, sizeof volctrl);
memcpy_fromfs(&volctrl, (char *)arg, sizeof (volctrl));
memcpy_fromfs(&volctrl, (char *)arg, sizeof volctrl);
cmd_buff[0] = SONY535_SET_VOLUME;
cmd_buff[1] = volctrl.channel0;
cmd_buff[2] = volctrl.channel1;
if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) {
printk("Sony CDROM error 0x%.2x (CDROMVOLCTRL)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n",
status[0]);
return -EIO;
}
}
......@@ -1276,7 +1360,8 @@ cdu_ioctl(struct inode *inode,
sony_audio_status = CDROM_AUDIO_INVALID;
cmd_buff[0] = SONY535_EJECT_CADDY;
if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) {
printk("Sony CDROM error 0x%.2x (CDROMEJECT)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n",
status[0]);
return -EIO;
}
return 0;
......@@ -1296,7 +1381,7 @@ static int
cdu_open(struct inode *inode,
struct file *filp)
{
unsigned char status[2], cmd_buff[2];
Byte status[2], cmd_buff[2];
if (sony_inuse)
......@@ -1307,7 +1392,8 @@ cdu_open(struct inode *inode,
MOD_INC_USE_COUNT;
if (spin_up_drive(status) != 0) {
printk("Sony CDROM error 0x%.2x (cdu_open, spin up)\n", status[0]);
printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n",
status[0]);
sony_inuse = 0;
MOD_DEC_USE_COUNT;
return -EIO;
......@@ -1343,7 +1429,7 @@ static void
cdu_release(struct inode *inode,
struct file *filp)
{
unsigned char status[2], cmd_no;
Byte status[2], cmd_no;
sony_inuse = 0;
MOD_DEC_USE_COUNT;
......@@ -1392,28 +1478,44 @@ static struct file_operations cdu_fops =
unsigned long
sony535_init(unsigned long mem_start, unsigned long mem_end)
#else
int
int
init_module(void)
#endif
{
struct s535_sony_drive_config drive_config;
unsigned char cmd_buff[3], ret_buff[2];
unsigned char status[2];
int retry_count;
Byte cmd_buff[3];
Byte ret_buff[2];
Byte status[2];
int retry_count;
int tmp_irq;
#ifdef MODULE
int i;
int i;
#endif
/* Setting the base I/O address to 0xffff will disable it. */
if (sony535_cd_base_io == 0xffff)
goto bail;
/* Set up all the register locations */
result_reg = sony_cd_base_io;
command_reg = sony_cd_base_io;
data_reg = sony_cd_base_io + 1;
read_status_reg = sony_cd_base_io + 2;
select_unit_reg = sony_cd_base_io + 3;
printk("sonycd535: probing base address %03X\n", sony_cd_base_io);
if (check_region(sony_cd_base_io,4)) {
printk("sonycd535: my base address is not free!\n");
result_reg = sony535_cd_base_io;
command_reg = sony535_cd_base_io;
data_reg = sony535_cd_base_io + 1;
read_status_reg = sony535_cd_base_io + 2;
select_unit_reg = sony535_cd_base_io + 3;
#ifndef USE_IRQ
sony535_irq_used = 0; /* polling only until this is ready... */
#endif
/* we need to poll until things get initialized */
tmp_irq = sony535_irq_used;
sony535_irq_used = 0;
#if DEBUG > 0
printk(CDU535_MESSAGE_NAME ": probing base address %03X\n",
sony535_cd_base_io);
#endif
if (check_region(sony535_cd_base_io,4)) {
printk(CDU535_MESSAGE_NAME ": my base address is not free!\n");
#ifndef MODULE
return mem_start;
#else
......@@ -1433,19 +1535,46 @@ init_module(void)
select_unit(0);
if (inb(result_reg) != 0xff)
break;
sony_sleep(); /* about 1-2 ms on my machine */
sony_sleep();
}
if ((jiffies < retry_count) && (check_drive_status() != TIME_OUT)) {
/* CD-ROM drive responded -- get the drive configuration */
cmd_buff[0] = SONY535_INQUIRY;
if (do_sony_cmd(cmd_buff, 1, status, (Byte *) & drive_config, 28, 1) == 0) {
/* was able to get the configuration, set drive mode as rest of init */
if (do_sony_cmd(cmd_buff, 1, status,
(Byte *)&drive_config, 28, 1) == 0) {
/* was able to get the configuration,
* set drive mode as rest of init
*/
#if DEBUG > 0
/* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */
if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 )
printk("Inquiry command returned status = 0x%x\n", status[0]);
printk(CDU535_MESSAGE_NAME
"Inquiry command returned status = 0x%x\n", status[0]);
#endif
/* now ready to use interrupts, if available */
sony535_irq_used = tmp_irq;
#ifndef MODULE
/* This code is not in MODULEs by default, since the autoirq stuff might
* not be in the module-accessable symbol table.
*/
/* A negative sony535_irq_used will attempt an autoirq. */
if (sony535_irq_used < 0) {
autoirq_setup(0);
enable_interrupts();
outb(0, read_status_reg); /* does a reset? */
sony535_irq_used = autoirq_report(10);
disable_interrupts();
}
#endif
if (sony535_irq_used > 0) {
if (request_irq(sony535_irq_used, cdu535_interrupt,
SA_INTERRUPT, CDU535_HANDLE)) {
printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME
" driver; polling instead.\n", sony535_irq_used);
sony535_irq_used = 0;
}
}
cmd_buff[0] = SONY535_SET_DRIVE_MODE;
cmd_buff[1] = 0x0; /* default audio */
if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) == 0) {
......@@ -1453,11 +1582,14 @@ init_module(void)
sony_buffer_size = SONY535_BUFFER_SIZE;
sony_buffer_sectors = sony_buffer_size / 2048;
printk("Sony I/F CDROM : %8.8s %16.16s %4.4s",
printk(CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s",
drive_config.vendor_id,
drive_config.product_id,
drive_config.product_rev_level);
printk(" using %d byte buffer\n", sony_buffer_size);
printk(" base address %03X, ", sony535_cd_base_io);
if (tmp_irq > 0)
printk("IRQ%d, ", tmp_irq);
printk("using %d byte buffer\n", sony_buffer_size);
if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
printk("Unable to get major %d for %s\n",
......@@ -1473,21 +1605,21 @@ init_module(void)
#ifndef MODULE
sony_toc = (struct s535_sony_toc *)mem_start;
mem_start += sizeof (*sony_toc);
mem_start += sizeof *sony_toc;
last_sony_subcode = (struct s535_sony_subcode *)mem_start;
mem_start += sizeof (*last_sony_subcode);
sony_buffer = (unsigned char *)mem_start;
mem_start += sizeof *last_sony_subcode;
sony_buffer = (Byte *)mem_start;
mem_start += sony_buffer_size;
#else /* MODULE */
sony_toc = (struct s535_sony_toc *)
kmalloc(sizeof (*sony_toc), GFP_KERNEL);
kmalloc(sizeof *sony_toc, GFP_KERNEL);
last_sony_subcode = (struct s535_sony_subcode *)
kmalloc(sizeof (*last_sony_subcode), GFP_KERNEL);
sony_buffer = (unsigned char **)
kmalloc(sizeof *last_sony_subcode, GFP_KERNEL);
sony_buffer = (Byte **)
kmalloc(4 * sony_buffer_sectors, GFP_KERNEL);
for (i = 0; i < sony_buffer_sectors; i++)
sony_buffer[i] = (unsigned char *)kmalloc(2048, GFP_KERNEL);
sony_buffer[i] = (Byte *)kmalloc(2048, GFP_KERNEL);
#endif /* MODULE */
initialized = 1;
}
......@@ -1500,8 +1632,9 @@ init_module(void)
return -EIO;
#endif
} else {
request_region(sony_cd_base_io, 4, CDU535_HANDLE);
request_region(sony535_cd_base_io, 4, CDU535_HANDLE);
}
bail:
#ifndef MODULE
return mem_start;
#else
......@@ -1511,7 +1644,7 @@ init_module(void)
#ifndef MODULE
/*
* accept "kernel command line" parameters
* accept "kernel command line" parameters
* (added by emoenke@gwdg.de)
*
* use: tell LILO:
......@@ -1522,33 +1655,35 @@ init_module(void)
void
sonycd535_setup(char *strings, int *ints)
{
/* if IRQ change and default io base desired,
* then call with io base of 0
*/
if (ints[0] > 0)
sony_cd_base_io = ints[1];
#if 0 /* placeholder for future use */
if (ints[0] != 0)
sony535_cd_base_io = ints[1];
if (ints[0] > 1)
irq_used = ints[2];
#endif
sony535_irq_used = ints[2];
if ((strings != NULL) && (*strings != '\0'))
printk("%s: Warning: Unknown interface type: %s\n",
strings, CDU535_MESSAGE_NAME);
printk(CDU535_MESSAGE_NAME
": Warning: Unknown interface type: %s\n", strings);
}
#else /* MODULE */
void
void
cleanup_module(void)
{
int i;
if (MOD_IN_USE) {
printk("Sony 535 module in use, cannot remove\n");
printk(CDU535_HANDLE " module in use, cannot remove\n");
return;
}
release_region(sony_cd_base_io, 4);
kfree_s(sony_toc, sizeof (*sony_toc));
kfree_s(last_sony_subcode, sizeof (*last_sony_subcode));
release_region(sony535_cd_base_io, 4);
for (i = 0; i < sony_buffer_sectors; i++)
kfree_s(sony_buffer[i], 2048);
kfree_s(sony_buffer, 4 * sony_buffer_sectors);
kfree_s(last_sony_subcode, sizeof *last_sony_subcode);
kfree_s(sony_toc, sizeof *sony_toc);
if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
else
......
Sat Feb 18 12:13:51 1995 Theodore Y. Ts'o (tytso@rt-11)
* tty_io.c (disassociate_ctty, tty_open, tty_ioctl): Clear
current->tty_old_pgrp field when a session leader
acquires a controlling tty, and after a session leader
has disassociated from a controlling tty.
Fri Feb 17 09:34:09 1995 Theodore Y. Ts'o (tytso@rt-11)
* serial.c (rs_interrupt_single, rs_interrupt, rs_interrupt_multi):
Change the the number of passes made from 64 to be 256,
configurable with the #define RS_ISR_PASS_LIMIT.
* serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
Remove support for closing_wait2. Instead, set
tty->closing and rely on the line dispcline to prevent
echo wars.
* n_tty.c (n_tty_receive_char): IEXTEN does not need to be
enabled in order for IXANY to be active.
If tty->closing is set, then only process XON and XOFF
characters.
Sun Feb 12 23:57:48 1995 Theodore Y. Ts'o (tytso@rt-11)
* serial.c (rs_timer): Change the interrupt poll time from 60
seconds to 10 seconds, configurable with the #define
RS_STROBE_TIME.
* serial.c (rs_interrupt_multi, startup, shutdown, rs_ioctl,
set_multiport_struct, get_multiport_struct): Add
provisions for a new type of interrutp service routine,
which better supports multiple serial ports on a single
IRQ.
Sun Feb 5 19:35:11 1995 Theodore Y. Ts'o (tytso@rt-11)
* tty_ioctl.c (n_tty_ioctl, set_termios, tty_wait_until_sent):
* serial.c (rs_ioctl, rs_close):
* cyclades.c (cy_ioctl, cy_close):
* n_tty.c (n_tty_close): Rename wait_until_sent to
tty_wait_until_sent, so that it's a better name to export
in ksyms.c.
Sat Feb 4 23:36:20 1995 Theodore Y. Ts'o (tytso@rt-11)
* serial.c (rs_close): Added missing check for closing_wait2 being
ASYNC_CLOSING_WAIT_NONE.
Thu Jan 26 09:02:49 1995 Theodore Y. Ts'o (tytso@rt-11)
* serial.c (rs_init, set_serial_info, get_serial_info,
rs_close): Support close_wait in the serial driver.
This is helpful for slow devices (like serial
plotters) so that their outputs don't get flushed upon
device close. This has to be configurable because
normally we don't want ports to be hung up for long
periods of time during a close when they are not
connected to a device, or the device is powered off.
The default is to wait 30 seconds; in the case of a
very slow device, the close_wait timeout should be
lengthed. If it is set to 0, the kernel will wait
forever for all of the data to be transmitted.
Thu Jan 17 01:17:20 1995 Theodore Y. Ts'o (tytso@rt-11)
* serial.c (startup, change_speed, rs_init): Add support to detect
the StarTech 16650 chip. Treat it as a 16450 for now,
because of its FIFO bugs.
Thu Jan 5 21:21:57 1995 <dhinds@allegro.stanford.edu>
* serial.c: (receive_char): Added counter to prevent infinite loop
......
......@@ -345,7 +345,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
return;
}
if (tty->stopped && I_IXON(tty) && I_IXANY(tty) && L_IEXTEN(tty)) {
if (tty->stopped && I_IXON(tty) && I_IXANY(tty)) {
start_tty(tty);
return;
}
......@@ -355,6 +355,16 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
if (I_IUCLC(tty) && L_IEXTEN(tty))
c=tolower(c);
if (tty->closing) {
if (I_IXON(tty)) {
if (c == START_CHAR(tty))
start_tty(tty);
else if (c == STOP_CHAR(tty))
stop_tty(tty);
}
return;
}
/*
* If the previous character was LNEXT, or we know that this
* character is not one of the characters that we'll have to
......@@ -690,6 +700,7 @@ static int n_tty_open(struct tty_struct *tty)
memset(tty->read_flags, 0, sizeof(tty->read_flags));
n_tty_set_termios(tty, 0);
tty->minimum_to_wake = 1;
tty->closing = 0;
return 0;
}
......
......@@ -3,10 +3,10 @@
*
* This module exports the functions:
*
* 'int set_selection(const int arg)'
* 'int set_selection(const unsigned long arg)'
* 'void clear_selection(void)'
* 'int paste_selection(struct tty_struct *tty)'
* 'int sel_loadlut(const int arg)'
* 'int sel_loadlut(const unsigned long arg)'
*
* Now that /dev/vcs exists, most of this can disappear again.
*/
......@@ -15,6 +15,9 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <asm/segment.h>
#include "vt_kern.h"
#include "consolemap.h"
#include "selection.h"
......@@ -82,7 +85,7 @@ static inline int inword(const unsigned char c) {
}
/* set inwordLut contents. Invoked by ioctl(). */
int sel_loadlut(const int arg)
int sel_loadlut(const unsigned long arg)
{
int i = verify_area(VERIFY_READ, (char *) arg, 36);
if (i)
......@@ -107,7 +110,7 @@ static inline unsigned short limit(const unsigned short v, const unsigned short
}
/* set the current selection. Invoked by ioctl(). */
int set_selection(const int arg, struct tty_struct *tty)
int set_selection(const unsigned long arg, struct tty_struct *tty)
{
int sel_mode, new_sel_start, new_sel_end, spc;
char *bp, *obp;
......
......@@ -6,9 +6,9 @@
extern int sel_cons;
extern void clear_selection(void);
extern int set_selection(const int arg, struct tty_struct *tty);
extern int set_selection(const unsigned long arg, struct tty_struct *tty);
extern int paste_selection(struct tty_struct *tty);
extern int sel_loadlut(const int arg);
extern int sel_loadlut(const unsigned long arg);
extern int mouse_reporting(void);
extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
......@@ -33,7 +33,9 @@ extern void putconsxy(int currcons, char *p);
/* how to access screen memory */
#ifdef __alpha__
#include <asm/io.h>
static inline void scr_writew(unsigned short val, unsigned short * addr)
{
if ((long) addr < 0)
......
......@@ -67,12 +67,14 @@ static int serial_refcount;
#define SERIAL_PARANOIA_CHECK
#define CONFIG_SERIAL_NOPAUSE_IO
#define SERIAL_DO_RESTART
#define CONFIG_SERIAL_NEW_ISR
#undef SERIAL_DEBUG_INTR
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
#define RS_STROBE_TIME 10
#define RS_ISR_PASS_LIMIT 256
#define _INLINE_ inline
/*
......@@ -81,6 +83,7 @@ static int serial_refcount;
*/
static struct async_struct *IRQ_ports[16];
static struct rs_multiport_struct rs_multiport[16];
static int IRQ_timeout[16];
static volatile int rs_irq_triggered;
static volatile int rs_triggered;
......@@ -420,9 +423,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
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);
#endif
return;
}
......@@ -445,9 +446,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
if (info->xmit_cnt <= 0) {
info->IER &= ~UART_IER_THRI;
#ifdef CONFIG_SERIAL_NEW_ISR
serial_out(info, UART_IER, info->IER);
#endif
}
}
......@@ -480,9 +479,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
#endif
info->tty->hw_stopped = 0;
info->IER |= UART_IER_THRI;
#ifdef CONFIG_SERIAL_NEW_ISR
serial_out(info, UART_IER, info->IER);
#endif
rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
return;
}
......@@ -493,15 +490,12 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
#endif
info->tty->hw_stopped = 1;
info->IER &= ~UART_IER_THRI;
#ifdef CONFIG_SERIAL_NEW_ISR
serial_out(info, UART_IER, info->IER);
#endif
}
}
}
}
#ifdef CONFIG_SERIAL_NEW_ISR
/*
* This is the serial driver's generic interrupt routine
*/
......@@ -511,6 +505,8 @@ static void rs_interrupt(int irq, struct pt_regs * regs)
struct async_struct * info;
int pass_counter = 0;
struct async_struct *end_mark = 0;
int first_multi = 0;
struct rs_multiport_struct *multi;
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt(%d)...", irq);
......@@ -520,6 +516,10 @@ static void rs_interrupt(int irq, struct pt_regs * regs)
if (!info)
return;
multi = &rs_multiport[irq];
if (multi->port_monitor)
first_multi = inb(multi->port_monitor);
do {
if (!info->tty ||
(serial_in(info, UART_IIR) & UART_IIR_NO_INT)) {
......@@ -545,7 +545,7 @@ static void rs_interrupt(int irq, struct pt_regs * regs)
info = info->next_port;
if (!info) {
info = IRQ_ports[irq];
if (pass_counter++ > 64) {
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
#if 0
printk("rs loop break\n");
#endif
......@@ -554,6 +554,9 @@ static void rs_interrupt(int irq, struct pt_regs * regs)
continue;
}
} while (end_mark != info);
if (multi->port_monitor)
printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n",
info->irq, first_multi, inb(multi->port_monitor));
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
......@@ -566,7 +569,9 @@ static void rs_interrupt_single(int irq, struct pt_regs * regs)
{
int status;
int pass_counter = 0;
int first_multi = 0;
struct async_struct * info;
struct rs_multiport_struct *multi;
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d)...", irq);
......@@ -576,6 +581,10 @@ static void rs_interrupt_single(int irq, struct pt_regs * regs)
if (!info || !info->tty)
return;
multi = &rs_multiport[irq];
if (multi->port_monitor)
first_multi = inb(multi->port_monitor);
do {
status = serial_inp(info, UART_LSR) & info->read_status_mask;
#ifdef SERIAL_DEBUG_INTR
......@@ -586,7 +595,7 @@ static void rs_interrupt_single(int irq, struct pt_regs * regs)
check_modem_status(info);
if (status & UART_LSR_THRE)
transmit_chars(info, 0);
if (pass_counter++ > 64) {
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
#if 0
printk("rs_single loop break.\n");
#endif
......@@ -594,102 +603,95 @@ static void rs_interrupt_single(int irq, struct pt_regs * regs)
}
} while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT));
info->last_active = jiffies;
if (multi->port_monitor)
printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n",
info->irq, first_multi, inb(multi->port_monitor));
#ifdef SERIAL_DEBUG_INTR
printk("end.\n");
#endif
}
#else /* CONFIG_SERIAL_NEW_ISR */
/*
* This is the serial driver's generic interrupt routine
* This is the serial driver's for multiport boards
*/
static void rs_interrupt(int irq, struct pt_regs * regs)
static void rs_interrupt_multi(int irq, struct pt_regs * regs)
{
int status;
struct async_struct * info;
int done = 1, pass_counter = 0;
int pass_counter = 0;
int first_multi= 0;
struct rs_multiport_struct *multi;
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt(%d)...", irq);
printk("rs_interrupt_multi(%d)...", irq);
#endif
info = IRQ_ports[irq];
if (!info)
return;
multi = &rs_multiport[irq];
if (!multi->port1) {
/* Should never happen */
printk("rs_interrupt_multi: NULL port1!\n");
return;
}
if (multi->port_monitor)
first_multi = inb(multi->port_monitor);
while (1) {
if (!info->tty)
if (!info->tty ||
(serial_in(info, UART_IIR) & UART_IIR_NO_INT))
goto next;
serial_outp(info, UART_IER, 0);
info->last_active = jiffies;
status = serial_inp(info, UART_LSR) & info->read_status_mask;
if (status & UART_LSR_DR) {
#ifdef SERIAL_DEBUG_INTR
printk("status = %x...", status);
#endif
if (status & UART_LSR_DR)
receive_chars(info, &status);
done = 0;
}
check_modem_status(info);
if (status & UART_LSR_THRE)
transmit_chars(info, &done);
transmit_chars(info, 0);
next:
info = info->next_port;
if (!info) {
info = IRQ_ports[irq];
if (done)
break;
done = 1;
if (pass_counter++ > 64) {
#if 0
printk("rs loop break\n");
info = info->next_port;
if (info)
continue;
info = IRQ_ports[irq];
if (pass_counter++ > RS_ISR_PASS_LIMIT) {
#if 1
printk("rs_multi loop break\n");
#endif
break; /* Prevent infinite loops */
}
break; /* Prevent infinite loops */
}
}
/*
* Reset the IER registers; info is already set up from the
* above while loop.
*/
do
serial_outp(info, UART_IER, info->IER);
while ((info = info->next_port) != NULL);
}
/*
* This is the serial driver's interrupt routine for a single port
*/
static void rs_interrupt_single(int irq, struct pt_regs * regs)
{
int status;
struct async_struct * info;
if (multi->port_monitor)
printk("rs port monitor irq %d: 0x%x, 0x%x\n",
info->irq, first_multi,
inb(multi->port_monitor));
if ((inb(multi->port1) & multi->mask1) != multi->match1)
continue;
if (!multi->port2)
break;
if ((inb(multi->port2) & multi->mask2) != multi->match2)
continue;
if (!multi->port3)
break;
if ((inb(multi->port3) & multi->mask3) != multi->match3)
continue;
if (!multi->port4)
break;
if ((inb(multi->port4) & multi->mask4) == multi->match4)
continue;
break;
}
#ifdef SERIAL_DEBUG_INTR
printk("rs_interrupt_single(%d)...", irq);
printk("end.\n");
#endif
info = IRQ_ports[irq];
if (!info || !info->tty)
return;
serial_outp(info, UART_IER, 0);
status = serial_inp(info, UART_LSR) & info->read_status_mask;
if (status & UART_LSR_DR)
receive_chars(info, &status);
check_modem_status(info);
if (status & UART_LSR_THRE)
transmit_chars(info, 0);
/*
* Reset the IER register
*/
serial_outp(info, UART_IER, info->IER);
}
#endif /* CONFIG_SERIAL_NEW_ISR */
/*
* -------------------------------------------------------------------
......@@ -747,7 +749,7 @@ static void rs_timer(void)
struct async_struct *info;
unsigned int i;
if ((jiffies - last_strobe) >= 60*HZ) {
if ((jiffies - last_strobe) >= RS_STROBE_TIME*HZ) {
for (i=1; i < 16; i++) {
info = IRQ_ports[i];
if (!info)
......@@ -760,14 +762,17 @@ static void rs_timer(void)
serial_out(info, UART_IER, info->IER);
info = info->next_port;
} while (info);
rs_interrupt(i, NULL);
if (rs_multiport[i].port1)
rs_interrupt_multi(i, NULL);
else
rs_interrupt(i, NULL);
} else
rs_interrupt_single(i, NULL);
sti();
}
}
last_strobe = jiffies;
timer_table[RS_TIMER].expires = jiffies + 60 * HZ;
timer_table[RS_TIMER].expires = jiffies + RS_STROBE_TIME * HZ;
timer_active |= 1 << RS_TIMER;
if (IRQ_ports[0]) {
......@@ -877,7 +882,11 @@ static int startup(struct async_struct * info)
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
if (info->type == PORT_16550A) {
if (info->type == PORT_16650) {
serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
info->xmit_fifo_size = 1; /* disabled for now */
} else if (info->type == PORT_16550A) {
serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
info->xmit_fifo_size = 16;
......@@ -906,7 +915,10 @@ static int startup(struct async_struct * info)
!IRQ_ports[info->irq]->next_port)) {
if (IRQ_ports[info->irq]) {
free_irq(info->irq);
handler = rs_interrupt;
if (rs_multiport[info->irq].port1)
handler = rs_interrupt_multi;
else
handler = rs_interrupt;
} else
handler = rs_interrupt_single;
......@@ -1148,6 +1160,18 @@ static void change_speed(struct async_struct *info)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
} else if (info->type == PORT_16650) {
/*
* On the 16650, we disable the FIFOs altogether
* because of a design bug in how the implement
* things. We could support it by completely changing
* how we handle the interrupt driver, but not today....
*
* N.B. Because there's no way to set a FIFO trigger
* at 1 char, we'd probably disable at speed below
* 2400 baud anyway...
*/
fcr = 0;
} else
fcr = 0;
......@@ -1404,6 +1428,7 @@ static int get_serial_info(struct async_struct * info,
tmp.flags = info->flags;
tmp.baud_base = info->baud_base;
tmp.close_delay = info->close_delay;
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = info->hub6;
memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
......@@ -1471,6 +1496,7 @@ static int set_serial_info(struct async_struct * info,
info->custom_divisor = new_serial.custom_divisor;
info->type = new_serial.type;
info->close_delay = new_serial.close_delay;
info->closing_wait = new_serial.closing_wait;
release_region(info->port,8);
if (change_port || change_irq) {
......@@ -1676,6 +1702,101 @@ static int check_wild_interrupts(int doprint)
return wild_interrupts;
}
static int get_multiport_struct(struct async_struct * info,
struct serial_multiport_struct *retinfo)
{
struct serial_multiport_struct ret;
struct rs_multiport_struct *multi;
multi = &rs_multiport[info->irq];
ret.port_monitor = multi->port_monitor;
ret.port1 = multi->port1;
ret.mask1 = multi->mask1;
ret.match1 = multi->match1;
ret.port2 = multi->port2;
ret.mask2 = multi->mask2;
ret.match2 = multi->match2;
ret.port3 = multi->port3;
ret.mask3 = multi->mask3;
ret.match3 = multi->match3;
ret.port4 = multi->port4;
ret.mask4 = multi->mask4;
ret.match4 = multi->match4;
ret.irq = info->irq;
memcpy_tofs(retinfo,&ret,sizeof(*retinfo));
return 0;
}
static int set_multiport_struct(struct async_struct * info,
struct serial_multiport_struct *in_multi)
{
struct serial_multiport_struct new_multi;
struct rs_multiport_struct *multi;
int was_multi, now_multi;
int retval;
void (*handler)(int, struct pt_regs *);
if (!suser())
return -EPERM;
if (!in_multi)
return -EFAULT;
memcpy_fromfs(&new_multi, in_multi,
sizeof(struct serial_multiport_struct));
if (new_multi.irq != info->irq || info->irq == 0 ||
!IRQ_ports[info->irq])
return -EINVAL;
multi = &rs_multiport[info->irq];
was_multi = (multi->port1 != 0);
multi->port_monitor = new_multi.port_monitor;
multi->port1 = new_multi.port1;
multi->mask1 = new_multi.mask1;
multi->match1 = new_multi.match1;
multi->port2 = new_multi.port2;
multi->mask2 = new_multi.mask2;
multi->match2 = new_multi.match2;
multi->port3 = new_multi.port3;
multi->mask3 = new_multi.mask3;
multi->match3 = new_multi.match3;
multi->port4 = new_multi.port4;
multi->mask4 = new_multi.mask4;
multi->match4 = new_multi.match4;
now_multi = (multi->port1 != 0);
if (IRQ_ports[info->irq]->next_port &&
(was_multi != now_multi)) {
free_irq(info->irq);
if (now_multi)
handler = rs_interrupt_multi;
else
handler = rs_interrupt;
retval = request_irq(info->irq, handler, SA_INTERRUPT,
"serial");
if (retval) {
printk("Couldn't reallocate serial interrupt "
"driver!!\n");
}
}
return 0;
}
static int rs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
......@@ -1778,6 +1899,16 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
info, sizeof(struct async_struct));
return 0;
case TIOCSERGETMULTI:
error = verify_area(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_multiport_struct));
if (error)
return error;
return get_multiport_struct(info,
(struct serial_multiport_struct *) arg);
case TIOCSERSETMULTI:
return set_multiport_struct(info,
(struct serial_multiport_struct *) arg);
default:
return -ENOIOCTLCMD;
}
......@@ -1871,6 +2002,13 @@ 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;
/*
* Now we wait for the trnasmit buffer to clear; and we notify
* the line discpline only process XON/XOFF characters.
*/
tty->closing = 1;
if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
......@@ -1881,7 +2019,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
info->read_status_mask &= ~UART_LSR_DR;
if (info->flags & ASYNC_INITIALIZED) {
serial_out(info, UART_IER, info->IER);
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
......@@ -1901,6 +2038,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
tty->driver.flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
tty->closing = 0;
info->event = 0;
info->tty = 0;
if (tty->ldisc.num != ldiscs[N_TTY].num) {
......@@ -2155,7 +2293,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
*/
static void show_serial_version(void)
{
printk("Serial driver version 4.00 with");
printk("Serial driver version 4.11 with");
#ifdef CONFIG_HUB6
printk(" HUB-6");
#define SERIAL_OPT
......@@ -2329,6 +2467,10 @@ static void autoconfig(struct async_struct * info)
if (info->flags & ASYNC_AUTO_IRQ)
info->irq = do_auto_irq(info);
scratch2 = serial_in(info, UART_LCR);
serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
serial_outp(info, UART_LCR, scratch2);
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(info, UART_IIR) >> 6;
info->xmit_fifo_size = 1;
......@@ -2343,8 +2485,15 @@ static void autoconfig(struct async_struct * info)
info->type = PORT_16550;
break;
case 3:
info->type = PORT_16550A;
info->xmit_fifo_size = 16;
serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
if (serial_in(info, UART_EFR) == 0) {
info->type = PORT_16650;
info->xmit_fifo_size = 32;
} else {
info->type = PORT_16550A;
info->xmit_fifo_size = 16;
}
serial_outp(info, UART_LCR, scratch2);
break;
}
if (info->type == PORT_16450) {
......@@ -2398,6 +2547,7 @@ long rs_init(long kmem_start)
for (i = 0; i < 16; i++) {
IRQ_ports[i] = 0;
IRQ_timeout[i] = 0;
memset(&rs_multiport[i], 0, sizeof(struct rs_multiport_struct));
}
show_serial_version();
......@@ -2458,6 +2608,7 @@ long rs_init(long kmem_start)
info->type = PORT_UNKNOWN;
info->custom_divisor = 0;
info->close_delay = 50;
info->closing_wait = 3000;
info->x_char = 0;
info->event = 0;
info->count = 0;
......@@ -2493,6 +2644,9 @@ long rs_init(long kmem_start)
case PORT_16550A:
printk(" is a 16550A\n");
break;
case PORT_16650:
printk(" is a 16650\n");
break;
default:
printk("\n");
break;
......
......@@ -452,6 +452,7 @@ void disassociate_ctty(int priv)
kill_pg(tty->pgrp, SIGCONT, priv);
}
current->tty_old_pgrp = 0;
tty->session = 0;
tty->pgrp = -1;
......@@ -1165,6 +1166,7 @@ static int tty_open(struct inode * inode, struct file * filp)
!current->tty &&
tty->session == 0) {
current->tty = tty;
current->tty_old_pgrp = 0;
tty->session = current->session;
tty->pgrp = current->pgrp;
}
......@@ -1393,6 +1395,7 @@ static int tty_ioctl(struct inode * inode, struct file * file,
return -EPERM;
}
current->tty = tty;
current->tty_old_pgrp = 0;
tty->session = current->session;
tty->pgrp = current->pgrp;
return 0;
......
#if defined(CONFIG_WAVELAN)
Tue Jan 31 10:42:35 EST 1995
Thu Feb 23 00:10:31 EST 1995
0. This document refers to Version 5 of the Linux WaveLAN device driver software.
It has been tested successfully under the 1.1.87 release of the Linux
kernel. It is `beta-test' software, so caveat emptor. Please report bugs
to me so that I can fix them quickly.
1. At present the driver only autoprobes for a WaveLAN card at I/O address 0x390.
1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390.
The version of the card that I use (NCR) supports four I/O addresses (selectable
via a pair of DIP switches). If you want the driver to autoprobe a different
subset of the four valid addresses then you will need to edit
......@@ -28,20 +23,7 @@ Tue Jan 31 10:42:35 EST 1995
append ="ether=0,0x390,0x4321,eth0"
..
3. The files that comprise this software must be incorporated into the Linux
kernel source tree (usually rooted at /usr/src/linux). Following that a
"make clean; make config; make dep; make zImage" should produce a Linux
kernel incorporating the WaveLAN driver, ready for installation.
The files:
drivers/net/wavelan.[ch]
drivers/net/i82586.h
are unique to this package and simply may be moved into place. The
others are modified versions of pre-existing files and must
be incorporated more carefully. However, the regions of modified code
within these files are small and are bracketed by the preprocessor
symbol CONFIG_WAVELAN, so incorporation should be straightforward.
4. If you encounter any problems send me some email.
3. If you encounter any problems send me some email.
Good luck,
Bruce Janson (bruce@cs.usyd.edu.au)
......
......@@ -21,6 +21,7 @@
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
......@@ -70,7 +71,7 @@ struct net_local
extern int wavelan_probe(device *); /* See Space.c */
static char *version = "wavelan.c:v5 31/1/95\n";
static char *version = "wavelan.c:v6 22/2/95\n";
/*
* Entry point forward declarations.
......@@ -103,14 +104,6 @@ static void wavelan_local_show(device *);
static unsigned int wavelan_debug = WAVELAN_DEBUG;
static net_local *first_wavelan = (net_local *)0;
static
void
busy_loop(int i)
{
while (i-- > 0)
;
}
static
unsigned long
wavelan_splhi(void)
......@@ -150,7 +143,7 @@ hacr_write_slow(unsigned short ioaddr, int hacr)
{
hacr_write(ioaddr, hacr);
/* delay might only be needed sometimes */
busy_loop(1000);
udelay(1000);
}
/*
......@@ -444,11 +437,13 @@ wavelan_ack(device *dev)
set_chan_attn(ioaddr, lp->hacr);
for (i = 1000000; i > 0; i--)
for (i = 1000; i > 0; i--)
{
obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
if (scb_cs == 0)
break;
udelay(1000);
}
if (i <= 0)
......@@ -477,11 +472,13 @@ wavelan_synchronous_cmd(device *dev, char *str)
set_chan_attn(ioaddr, lp->hacr);
for (i = 64000; i > 0; i--)
for (i = 64; i > 0; i--)
{
obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb));
if (cb.ac_status & AC_SFLD_C)
break;
udelay(1000);
}
if (i <= 0 || !(cb.ac_status & AC_SFLD_OK))
......@@ -557,23 +554,27 @@ wavelan_hardware_reset(device *dev)
set_chan_attn(ioaddr, lp->hacr);
for (i = 1000000; i > 0; i--)
for (i = 1000; i > 0; i--)
{
obram_read(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp));
if (iscp.iscp_busy == (unsigned short)0)
break;
udelay(1000);
}
if (i <= 0)
printk("%s: wavelan_hardware_reset(): iscp_busy timeout.\n", dev->name);
for (i = 15000; i > 0; i--)
for (i = 15; i > 0; i--)
{
obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb));
if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA))
break;
udelay(1000);
}
if (i <= 0)
......@@ -970,11 +971,13 @@ wavelan_ru_start(device *dev)
set_chan_attn(ioaddr, lp->hacr);
for (i = 1000000; i > 0; i--)
for (i = 1000; i > 0; i--)
{
obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
if (scb_cs == 0)
break;
udelay(1000);
}
if (i <= 0)
......@@ -1049,11 +1052,13 @@ wavelan_cu_start(device *dev)
set_chan_attn(ioaddr, lp->hacr);
for (i = 1000000; i > 0; i--)
for (i = 1000; i > 0; i--)
{
obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs));
if (scb_cs == 0)
break;
udelay(1000);
}
if (i <= 0)
......@@ -1849,6 +1854,7 @@ void
wavelan_set_multicast_list(device *dev, int num_addrs, void *addrs)
{
net_local *lp;
unsigned long x;
lp = (net_local *)dev->priv;
......@@ -1859,7 +1865,9 @@ wavelan_set_multicast_list(device *dev, int num_addrs, void *addrs)
* Promiscuous mode: receive all packets.
*/
lp->promiscuous = 1;
x = wavelan_splhi();
(void)wavelan_hardware_reset(dev);
wavelan_splx(x);
break;
case 0:
......@@ -1868,7 +1876,9 @@ wavelan_set_multicast_list(device *dev, int num_addrs, void *addrs)
* clear multicast list.
*/
lp->promiscuous = 0;
x = wavelan_splhi();
(void)wavelan_hardware_reset(dev);
wavelan_splx(x);
break;
default:
......@@ -2319,9 +2329,9 @@ wavelan_local_show(device *dev)
* Allan Creighton (allanc@cs.usyd.edu.au),
* Matthew Geier (matthew@cs.usyd.edu.au),
* Remo di Giovanni (remo@cs.usyd.edu.au),
* Eckhard Grah (grah@wrcs1.urz.uni-wuppertal.de),
* Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
* Tim Nicholson (tim@cs.usyd.edu.au),
* Jeff Noxon (jeff@oylpatch.sccsi.com),
* Ian Parkin (ian@cs.usyd.edu.au),
* John Rosenberg (johnr@cs.usyd.edu.au),
* George Rossi (george@phm.gov.au),
......
......@@ -1363,7 +1363,7 @@ static int shrink_specific_buffers(unsigned int priority, int size)
if(priority > 3 && nlist == BUF_SHARED) continue;
bh = lru_list[nlist];
if(!bh) continue;
i = nr_buffers_type[nlist] >> priority;
i = 2*nr_buffers_type[nlist] >> priority;
for ( ; i-- > 0 ; bh = bh->b_next_free) {
/* We may have stalled while waiting for I/O to complete. */
if(bh->b_list != nlist) goto repeat1;
......
......@@ -183,14 +183,17 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
is no Rock Ridge NM field. */
else {
/* Do not report hidden or associated files */
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
if (de->flags[-high_sierra] & 5) {
if (cpnt) {
kfree(cpnt);
cpnt = NULL;
};
continue;
if (inode->i_sb->u.isofs_sb.s_unhide=='n')
{
/* Do not report hidden or associated files */
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
if (de->flags[-high_sierra] & 5) {
if (cpnt) {
kfree(cpnt);
cpnt = NULL;
};
continue;
}
}
dlen = de->name_len[0];
dpnt = de->name;
......
......@@ -63,6 +63,7 @@ struct iso9660_options{
char map;
char rock;
char cruft;
char unhide;
unsigned char conversion;
unsigned int blocksize;
mode_t mode;
......@@ -77,6 +78,7 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->map = 'n';
popt->rock = 'y';
popt->cruft = 'n';
popt->unhide = 'n';
popt->conversion = 'a';
popt->blocksize = 1024;
popt->mode = S_IRUGO;
......@@ -88,6 +90,10 @@ static int parse_options(char *options, struct iso9660_options * popt)
popt->rock = 'n';
continue;
};
if (strncmp(this_char,"unhide",6) == 0) {
popt->unhide = 'y';
continue;
};
if (strncmp(this_char,"cruft",5) == 0) {
popt->cruft = 'y';
continue;
......@@ -214,6 +220,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
printk("map = %c\n", opt.map);
printk("rock = %c\n", opt.rock);
printk("cruft = %c\n", opt.cruft);
printk("unhide = %c\n", opt.unhide);
printk("conversion = %c\n", opt.conversion);
printk("blocksize = %d\n", opt.blocksize);
printk("gid = %d\n", opt.gid);
......@@ -353,6 +360,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data,
s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
s->u.isofs_sb.s_conversion = opt.conversion;
s->u.isofs_sb.s_cruft = opt.cruft;
s->u.isofs_sb.s_unhide = opt.unhide;
s->u.isofs_sb.s_uid = opt.uid;
s->u.isofs_sb.s_gid = opt.gid;
/*
......
......@@ -73,7 +73,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
unsigned int old_offset;
unsigned int backlink;
int dlen, rrflag, match;
int high_sierra = 0;
char * dpnt;
struct iso_directory_record * de;
char c;
......@@ -155,16 +154,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
backlink = 0;
}
/* Do not report hidden or associated files */
high_sierra = dir->i_sb->u.isofs_sb.s_high_sierra;
if (de->flags[-high_sierra] & 5) {
if (cpnt) {
kfree(cpnt);
cpnt = NULL;
};
continue;
}
dlen = de->name_len[0];
dpnt = de->name;
/* Now convert the filename in the buffer to lower case */
......
......@@ -7,7 +7,7 @@
* Deadlock Detection added by Kelly Carmichael, kelly@[142.24.8.65]
* September 17, 1994.
*
* FIXME: one thing isn't handled yet:
* FIXME: one thing isn't handled yet:
* - mandatory locks (requires lots of changes elsewhere)
*
* Edited by Kai Petzke, wpp@marie.physik.tu-berlin.de
......@@ -22,7 +22,11 @@
* process. Since locks still depend on the process id, locks are inherited
* after an exec() but not after a fork(). This agrees with POSIX, and both
* BSD and SVR4 practice.
* Andy Walker (andy@keo.kvaerner.no), February 14, 1994
* Andy Walker (andy@keo.kvaerner.no), February 14, 1995
*
* Scrapped free list which is redundant now that we allocate locks
* dynamically with kmalloc()/kfree().
* Andy Walker (andy@keo.kvaerner.no), February 21, 1995
*
*/
......@@ -45,16 +49,11 @@ static int overlap(struct file_lock *fl1, struct file_lock *fl2);
static int lock_it(struct file *filp, struct file_lock *caller);
static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl);
static void free_lock(struct file_lock **fl);
static void free_list_garbage_collect(void);
#ifdef DEADLOCK_DETECTION
int locks_deadlocked(int my_pid,int blocked_pid);
#endif
#define FREE_LIST_GARBAGE_COLLECT 20
static struct file_lock *file_lock_table = NULL;
static struct file_lock *file_lock_free_list = NULL;
static int free_list_cnt = 0;
int fcntl_getlk(unsigned int fd, struct flock *l)
{
......@@ -155,7 +154,8 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
#ifdef DEADLOCK_DETECTION
if (locks_deadlocked(file_lock.fl_owner->pid,fl->fl_owner->pid)) return -EDEADLOCK;
if (locks_deadlocked(file_lock.fl_owner->pid,fl->fl_owner->pid))
return -EDEADLOCK;
#endif
interruptible_sleep_on(&fl->fl_wait);
if (current->signal & ~current->blocked)
......@@ -192,9 +192,11 @@ int locks_deadlocked(int my_pid,int blocked_pid)
dlock_wait = fl->fl_wait;
do {
if (dlock_wait->task != NULL) {
if (dlock_wait->task->pid == blocked_pid) return -EDEADLOCK;
if (dlock_wait->task->pid == blocked_pid)
return -EDEADLOCK;
ret_val = locks_deadlocked(dlock_wait->task->pid,blocked_pid);
if (ret_val) return -EDEADLOCK;
if (ret_val)
return -EDEADLOCK;
}
dlock_wait = dlock_wait->next;
} while (dlock_wait != fl->fl_wait);
......@@ -445,40 +447,26 @@ static int lock_it(struct file *filp, struct file_lock *caller)
/*
* File_lock() inserts a lock at the position pos of the linked list.
*
* Modified to create a new node if no free entries available - Chad Page
*
*/
static struct file_lock *alloc_lock(struct file_lock **pos,
struct file_lock *fl)
{
struct file_lock *tmp;
tmp = file_lock_free_list;
if (tmp == NULL)
{
/* Okay, let's make a new file_lock structure... */
tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock), GFP_KERNEL);
tmp -> fl_owner = NULL;
tmp -> fl_next = file_lock_free_list;
tmp -> fl_nextlink = file_lock_table;
file_lock_table = tmp;
}
else
{
/* remove from free list */
file_lock_free_list = tmp->fl_next;
free_list_cnt--;
}
if (tmp->fl_owner != NULL)
panic("alloc_lock: broken free list\n");
/* Okay, let's make a new file_lock structure... */
tmp = (struct file_lock *)kmalloc(sizeof(struct file_lock), GFP_KERNEL);
if (!tmp)
return tmp;
tmp->fl_nextlink = file_lock_table;
tmp->fl_prevlink = NULL;
if (file_lock_table != NULL)
file_lock_table->fl_prevlink = tmp;
file_lock_table = tmp;
tmp->fl_next = *pos; /* insert into file's list */
*pos = tmp;
tmp->fl_owner = current; /* FIXME: needed? */
tmp->fl_owner = current;
tmp->fl_wait = NULL;
tmp->fl_type = fl->fl_type;
......@@ -490,7 +478,7 @@ static struct file_lock *alloc_lock(struct file_lock **pos,
}
/*
* Add a lock to the free list ...
* Free up a lock...
*/
static void free_lock(struct file_lock **fl_p)
......@@ -498,24 +486,19 @@ static void free_lock(struct file_lock **fl_p)
struct file_lock *fl;
fl = *fl_p;
if (fl->fl_owner == NULL) /* sanity check */
panic("free_lock: broken lock list\n");
*fl_p = (*fl_p)->fl_next;
fl->fl_next = file_lock_free_list; /* add to free list */
file_lock_free_list = fl;
fl->fl_owner = NULL; /* for sanity checks */
if (fl->fl_nextlink != NULL)
fl->fl_nextlink->fl_prevlink = fl->fl_prevlink;
free_list_cnt++;
if (free_list_cnt == FREE_LIST_GARBAGE_COLLECT)
free_list_garbage_collect();
if (fl->fl_prevlink != NULL)
fl->fl_prevlink->fl_nextlink = fl->fl_nextlink;
else
file_lock_table = fl->fl_nextlink;
wake_up(&fl->fl_wait);
}
static void free_list_garbage_collect(void)
{
/* Do nothing for now */
kfree(fl);
return;
}
#define THREE_LEVEL
/*
* linux/fs/proc/mem.c
*
......@@ -25,7 +26,8 @@
static int mem_read(struct inode * inode, struct file * file,char * buf, int count)
{
pgd_t *pgdir;
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
char * page;
struct task_struct * tsk;
......@@ -50,15 +52,23 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
while (count > 0) {
if (current->signal & ~current->blocked)
break;
pgdir = PAGE_DIR_OFFSET(tsk,addr);
if (pgd_none(*pgdir))
page_dir = pgd_offset(tsk,addr);
if (pgd_none(*page_dir))
break;
if (pgd_bad(*pgdir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*pgdir));
pgd_clear(pgdir);
if (pgd_bad(*page_dir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
break;
}
pte = *(pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
page_middle = pmd_offset(page_dir,addr);
if (pmd_none(*page_middle))
break;
if (pmd_bad(*page_middle)) {
printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
pmd_clear(page_middle);
break;
}
pte = *pte_offset(page_middle,addr);
if (!pte_present(pte))
break;
page = (char *) pte_page(pte) + (addr & ~PAGE_MASK);
......@@ -78,8 +88,9 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou
static int mem_write(struct inode * inode, struct file * file,char * buf, int count)
{
pgd_t * pgdir;
pte_t * pte;
pgd_t *page_dir;
pmd_t *page_middle;
pte_t pte;
char * page;
struct task_struct * tsk;
unsigned long addr, pid;
......@@ -103,15 +114,23 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co
while (count > 0) {
if (current->signal & ~current->blocked)
break;
pgdir = PAGE_DIR_OFFSET(tsk,addr);
if (pgd_none(*pgdir))
page_dir = pgd_offset(tsk,addr);
if (pgd_none(*page_dir))
break;
if (pgd_bad(*pgdir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*pgdir));
pgd_clear(pgdir);
if (pgd_bad(*page_dir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
break;
}
pte = *(pte_t *) (PAGE_PTR(addr) + pgd_page(*pgdir));
page_middle = pmd_offset(page_dir,addr);
if (pmd_none(*page_middle))
break;
if (pmd_bad(*page_middle)) {
printk("Bad page middle entry %08lx\n", pmd_val(*page_middle));
pmd_clear(page_middle);
break;
}
pte = *pte_offset(page_middle,addr);
if (!pte_present(pte))
break;
if (!pte_write(pte))
......@@ -157,6 +176,7 @@ int mem_mmap(struct inode * inode, struct file * file,
{
struct task_struct *tsk;
pgd_t *src_dir, *dest_dir;
pmd_t *src_middle, *dest_middle;
pte_t *src_table, *dest_table;
unsigned long stmp, dtmp;
struct vm_area_struct *src_vma = NULL;
......@@ -168,7 +188,6 @@ int mem_mmap(struct inode * inode, struct file * file,
for (i = 1 ; i < NR_TASKS ; i++)
if (task[i] && task[i]->pid == (inode->i_ino >> 16)) {
tsk = task[i];
src_vma = task[i]->mm->mmap;
break;
}
......@@ -180,6 +199,7 @@ int mem_mmap(struct inode * inode, struct file * file,
moment because working out the vm_area_struct & nattach stuff isn't
worth it. */
src_vma = tsk->mm->mmap;
stmp = vma->vm_offset;
while (stmp < vma->vm_offset + (vma->vm_end - vma->vm_start)) {
while (src_vma && stmp > src_vma->vm_end)
......@@ -187,15 +207,21 @@ int mem_mmap(struct inode * inode, struct file * file,
if (!src_vma || (src_vma->vm_flags & VM_SHM))
return -EINVAL;
src_dir = PAGE_DIR_OFFSET(tsk, stmp);
src_dir = pgd_offset(tsk, stmp);
if (pgd_none(*src_dir))
return -EINVAL;
if (pgd_bad(*src_dir)) {
printk("Bad source page dir entry %08lx\n", pgd_val(*src_dir));
return -EINVAL;
}
src_table = (pte_t *)(pgd_page(*src_dir) + PAGE_PTR(stmp));
src_middle = pmd_offset(src_dir, stmp);
if (pmd_none(*src_middle))
return -EINVAL;
if (pmd_bad(*src_middle)) {
printk("Bad source page middle entry %08lx\n", pmd_val(*src_middle));
return -EINVAL;
}
src_table = pte_offset(src_middle, stmp);
if (pte_none(*src_table))
return -EINVAL;
......@@ -208,7 +234,7 @@ int mem_mmap(struct inode * inode, struct file * file,
stmp += PAGE_SIZE;
}
src_vma = task[i]->mm->mmap;
src_vma = tsk->mm->mmap;
stmp = vma->vm_offset;
dtmp = vma->vm_start;
......@@ -216,28 +242,17 @@ int mem_mmap(struct inode * inode, struct file * file,
while (src_vma && stmp > src_vma->vm_end)
src_vma = src_vma->vm_next;
src_dir = PAGE_DIR_OFFSET(tsk, stmp);
src_table = (pte_t *) (pgd_page(*src_dir) + PAGE_PTR(stmp));
dest_dir = PAGE_DIR_OFFSET(current, dtmp);
if (pgd_none(*dest_dir)) {
unsigned long page = get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
if (pgd_none(*dest_dir)) {
pgd_set(dest_dir, (pte_t *) page);
} else {
free_page(page);
}
}
if (pgd_bad(*dest_dir)) {
printk("Bad dest directory entry %08lx\n", pgd_val(*dest_dir));
return -EINVAL;
}
dest_table = (pte_t *) (pgd_page(*dest_dir) + PAGE_PTR(dtmp));
src_dir = pgd_offset(tsk, stmp);
src_middle = pmd_offset(src_dir, stmp);
src_table = pte_offset(src_middle, stmp);
dest_dir = pgd_offset(current, dtmp);
dest_middle = pmd_alloc(dest_dir, dtmp);
if (!dest_middle)
return -ENOMEM;
dest_table = pte_alloc(dest_middle, dtmp);
if (!dest_table)
return -ENOMEM;
if (!pte_present(*src_table))
do_no_page(src_vma, stmp, 1);
......
......@@ -32,14 +32,11 @@ __ntohl(unsigned long int x)
((x & 0xff000000U) >> 24));
}
extern __inline__ unsigned long int
__constant_ntohl(unsigned long int x)
{
return (((x & 0x000000ffU) << 24) |
((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) |
((x & 0xff000000U) >> 24));
}
#define __constant_ntohl(x) \
((unsigned int)((((unsigned int)(x) & 0x000000ffU) << 24) | \
(((unsigned int)(x) & 0x0000ff00U) << 8) | \
(((unsigned int)(x) & 0x00ff0000U) >> 8) | \
(((unsigned int)(x) & 0xff000000U) >> 24)))
extern __inline__ unsigned short int
__ntohs(unsigned short int x)
......@@ -48,12 +45,9 @@ __ntohs(unsigned short int x)
((x & 0xff00) >> 8));
}
extern __inline__ unsigned short int
__constant_ntohs(unsigned short int x)
{
return (((x & 0x00ff) << 8) |
((x & 0xff00) >> 8));
}
#define __constant_ntohs(x) \
((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
(((unsigned short int)(x) & 0xff00) >> 8)))
#define __htonl(x) __ntohl(x)
#define __htons(x) __ntohs(x)
......
......@@ -160,18 +160,33 @@ extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_VALID; }
extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] > 1; }
extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
extern inline void pte_reuse(pte_t * ptep)
{
if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
mem_map[MAP_NR(ptep)]++;
}
extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~_PFN_MASK) != _PAGE_TABLE || pmd_page(pmd) > high_memory; }
extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_VALID; }
extern inline int pmd_inuse(pmd_t *pmdp) { return mem_map[MAP_NR(pmdp)] > 1; }
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
extern inline void pmd_reuse(pmd_t * pmdp)
{
if (!(mem_map[MAP_NR(pmdp)] & MAP_PAGE_RESERVED))
mem_map[MAP_NR(pmdp)]++;
}
extern inline int pgd_none(pgd_t pgd) { return !pgd_val(pgd); }
extern inline int pgd_bad(pgd_t pgd) { return (pgd_val(pgd) & ~_PFN_MASK) != _PAGE_TABLE || pgd_page(pgd) > high_memory; }
extern inline int pgd_present(pgd_t pgd) { return pgd_val(pgd) & _PAGE_VALID; }
extern inline int pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)] > 1; }
extern inline void pgd_clear(pgd_t * pgdp) { pgd_val(*pgdp) = 0; }
extern inline void pgd_reuse(pgd_t * pgdp)
{
if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
mem_map[MAP_NR(pgdp)]++;
}
/*
* The following only work if pte_present() is true.
......
......@@ -27,14 +27,11 @@ __ntohl(unsigned long int x)
return x;
}
extern __inline__ unsigned long int
__constant_ntohl(unsigned long int x)
{
return (((x & 0x000000ffU) << 24) |
((x & 0x0000ff00U) << 8) |
((x & 0x00ff0000U) >> 8) |
((x & 0xff000000U) >> 24));
}
#define __constant_ntohl(x) \
((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
(((unsigned long int)(x) & 0x0000ff00U) << 8) | \
(((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
(((unsigned long int)(x) & 0xff000000U) >> 24)))
extern __inline__ unsigned short int
__ntohs(unsigned short int x)
......@@ -45,12 +42,9 @@ __ntohs(unsigned short int x)
return x;
}
extern __inline__ unsigned short int
__constant_ntohs(unsigned short int x)
{
return (((x & 0x00ff) << 8) |
((x & 0xff00) >> 8));
}
#define __constant_ntohs(x) \
((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
(((unsigned short int)(x) & 0xff00) >> 8))) \
#define __htonl(x) __ntohl(x)
#define __htons(x) __ntohs(x)
......
#ifndef __SPARC_SYSTEM_H
#define __SPARC_SYSTEM_H
#include <asm/segment.h>
/*
* System defines.. Note that this is included both from .c and .S
* files, so it does only defines, not any C code.
......
......@@ -7,8 +7,8 @@
Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu)
*/
extern unsigned int trapbase[];
extern unsigned int end[], etext[], msgbuf[];
extern unsigned long *trapbase;
extern char end, etext, msgbuf;
extern void flush_vac_context(void);
extern void flush_vac_segment(unsigned int foo_segment);
......
......@@ -266,8 +266,9 @@ struct file {
};
struct file_lock {
struct file_lock *fl_next; /* singly linked list */
struct file_lock *fl_nextlink;
struct file_lock *fl_next; /* singly linked list for this inode (or the free list) */
struct file_lock *fl_nextlink; /* doubly linked list of all locks */
struct file_lock *fl_prevlink; /* used to simplify garbage collecting */
struct task_struct *fl_owner; /* NULL if on free list, for sanity checks */
struct wait_queue *fl_wait;
char fl_type;
......
......@@ -18,6 +18,7 @@ struct isofs_sb_info {
unsigned char s_cruft; /* Broken disks with high
byte of length containing
junk */
unsigned char s_unhide;
unsigned char s_nosuid;
unsigned char s_nodev;
mode_t s_mode;
......
......@@ -268,11 +268,12 @@ extern int request_irq(unsigned int irq,void (*handler)(int, struct pt_regs *),
unsigned long flags, const char *device);
extern void free_irq(unsigned int irq);
extern unsigned long copy_thread(int, unsigned long, struct task_struct *, struct pt_regs *);
extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *, struct pt_regs *);
extern void flush_thread(void);
extern void exit_thread(void);
extern int do_execve(char *, char **, char **, struct pt_regs *);
extern int do_fork(unsigned long, unsigned long, struct pt_regs *);
asmlinkage int do_signal(unsigned long, struct pt_regs *);
/*
......
......@@ -22,9 +22,18 @@ struct serial_struct {
unsigned short close_delay;
char reserved_char[2];
int hub6;
int reserved[5];
unsigned short closing_wait; /* time to wait before closing */
unsigned short closing_wait2; /* no longer used... */
int reserved[4];
};
/*
* For the close wait times, 0 means wait forever for serial port to
* flush its output. 65535 means don't wait at all.
*/
#define ASYNC_CLOSING_WAIT_INF 0
#define ASYNC_CLOSING_WAIT_NONE 65535
/*
* These are the supported serial types.
*/
......@@ -34,7 +43,8 @@ struct serial_struct {
#define PORT_16550 3
#define PORT_16550A 4
#define PORT_CIRRUS 5
#define PORT_MAX 5
#define PORT_16650 6
#define PORT_MAX 6
/*
* Definitions for async_struct (and serial_struct) flags field
......@@ -70,6 +80,23 @@ struct serial_struct {
#define ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
/*
* Multiport serial configuration structure --- external structure
*/
struct serial_multiport_struct {
int irq;
int port1;
unsigned char mask1, match1;
int port2;
unsigned char mask2, match2;
int port3;
unsigned char mask3, match3;
int port4;
unsigned char mask4, match4;
int port_monitor;
int reserved[32];
};
#ifdef __KERNEL__
/*
* This is our internal structure for each serial port's state.
......@@ -96,6 +123,8 @@ struct async_struct {
int custom_divisor;
int x_char; /* xon/xoff character */
int close_delay;
unsigned short closing_wait;
unsigned short closing_wait2;
int IER; /* Interrupt Enable Register */
int MCR; /* Modem control register */
int MCR_noint; /* MCR with interrupts off */
......@@ -133,6 +162,21 @@ struct async_struct {
#define RS_EVENT_WRITE_WAKEUP 0
#define RS_EVENT_HANGUP 1
/*
* Multiport serial configuration structure --- internal structure
*/
struct rs_multiport_struct {
int port1;
unsigned char mask1, match1;
int port2;
unsigned char mask2, match2;
int port3;
unsigned char mask3, match3;
int port4;
unsigned char mask4, match4;
int port_monitor;
};
/* Export to allow PCMCIA to use this - Dave Hinds */
extern int register_serial(struct serial_struct *req);
extern void unregister_serial(int line);
......
......@@ -21,6 +21,8 @@
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_FCR 2 /* Out: FIFO Control Register */
#define UART_EFR 2 /* I/O: Extended Features Register */
/* (DLAB=1, 16C660 only) */
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_LSR 5 /* In: Line Status Register */
......@@ -29,6 +31,7 @@
/*
* These are the definitions for the FIFO Control Register
* (16650 only)
*/
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
......@@ -39,6 +42,15 @@
#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
/* 16650 redefinitions */
#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
/*
* These are the definitions for the Line Control Register
......@@ -109,5 +121,17 @@
#define UART_MSR_DCTS 0x01 /* Delta CTS */
#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
/*
* These are the definitions for the Extended Features Register
* (StarTech 16C660 only, when DLAB=1)
*/
#define UART_EFR_CTS 0x80 /* CTS flow control */
#define UART_EFR_RTS 0x40 /* RTS flow control */
#define UART_EFR_SCD 0x20 /* Special character detect */
#define UART_EFR_ENI 0x10 /* Enhanced Interrupt */
/*
* the low four bits control software flow control
*/
#endif /* _LINUX_SERIAL_REG_H */
......@@ -6,11 +6,6 @@
*/
#define NR_syscalls 256
/*
* These are system calls with the same entry-point
*/
#define _sys_clone _sys_fork
/*
* These are system calls that will be removed at some time
* due to newer versions existing..
......
......@@ -54,6 +54,8 @@
#define TIOCSLCKTRMIOS 0x5457
#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
#define TIOCSERGETLSR 0x5459 /* Get line status register */
#define TIOCSERGETMULTI 0x545A /* Get multiport config */
#define TIOCSERSETMULTI 0x545B /* Set multiport config */
/* Used for packet mode */
#define TIOCPKT_DATA 0
......@@ -193,6 +195,7 @@ struct termios {
#define CBAUDEX 0010000
#define B57600 0010001
#define B115200 0010002
#define B230400 0010003
#define CIBAUD 002003600000 /* input baud rate (not used) */
#define CRTSCTS 020000000000 /* flow control */
......
......@@ -222,6 +222,7 @@ struct tty_struct {
*/
unsigned int column;
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
unsigned char closing:1;
unsigned short minimum_to_wake;
unsigned overrun_time;
int num_overrun;
......
#define THREE_LEVEL
/*
* linux/ipc/shm.c
* Copyright (C) 1992, 1993 Krishna Balasubramanian
......@@ -20,7 +21,7 @@ extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
extern unsigned int get_swap_page (void);
static int findkey (key_t key);
static int newseg (key_t key, int shmflg, int size);
static int shm_map (struct vm_area_struct *shmd, int remap);
static int shm_map (struct vm_area_struct *shmd);
static void killseg (int id);
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
......@@ -411,34 +412,16 @@ static inline void remove_attach (struct shmid_ds * shp, struct vm_area_struct *
}
/*
* check range is unmapped, ensure page tables exist
* ensure page tables exist
* mark page table entries with shm_sgn.
* if remap != 0 the range is remapped.
*/
static int shm_map (struct vm_area_struct *shmd, int remap)
static int shm_map (struct vm_area_struct *shmd)
{
pgd_t *page_dir;
pmd_t *page_middle;
pte_t *page_table;
unsigned long tmp, shm_sgn;
/* check that the range is unmapped */
if (!remap)
for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
if (pgd_none(*page_dir))
continue;
if (pgd_bad(*page_dir)) {
printk("bad ipc page directory entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
continue;
}
page_table = (pte_t *) pgd_page(*page_dir);
page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
if (!pte_none(*page_table)) {
/* printk("shmat() -> EINVAL because address 0x%lx is already mapped.\n",tmp); */
return -EINVAL;
}
}
int error;
/* clear old mappings */
do_munmap(shmd->vm_start, shmd->vm_end - shmd->vm_start);
......@@ -447,35 +430,17 @@ static int shm_map (struct vm_area_struct *shmd, int remap)
insert_vm_struct(current, shmd);
merge_segments(current, shmd->vm_start, shmd->vm_end);
/* check that the range has page_tables */
for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE) {
page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
if (!pgd_none(*page_dir)) {
page_table = (pte_t *) pgd_page(*page_dir);
page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
if (!pte_none(*page_table)) {
if (pte_present(*page_table)) {
--current->mm->rss;
free_page (pte_page(*page_table));
} else
swap_free(pte_val(*page_table));
pte_clear(page_table);
}
} else {
if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL)))
return -ENOMEM;
pgd_set(page_dir, page_table);
tmp |= (PGDIR_SIZE - PAGE_SIZE);
}
}
/* map page range */
shm_sgn = shmd->vm_pte + ((shmd->vm_offset >> PAGE_SHIFT) << SHM_IDX_SHIFT);
for (tmp = shmd->vm_start; tmp < shmd->vm_end; tmp += PAGE_SIZE,
shm_sgn += (1 << SHM_IDX_SHIFT)) {
page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
page_table = (pte_t *) pgd_page(*page_dir);
page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
page_dir = pgd_offset(shmd->vm_task,tmp);
page_middle = pmd_alloc(page_dir,tmp);
if (!page_middle)
break;
page_table = pte_alloc(page_middle,tmp);
if (!page_table)
break;
pte_val(*page_table) = shm_sgn;
}
invalidate();
......@@ -553,7 +518,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
shmd->vm_ops = &shm_vm_ops;
shp->shm_nattch++; /* prevent destruction */
if ((err = shm_map (shmd, shmflg & SHM_REMAP))) {
if ((err = shm_map (shmd))) {
if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
killseg(id);
kfree(shmd);
......@@ -749,6 +714,7 @@ int shm_swap (int prio)
for (shmd = shp->attaches; ; ) {
do {
pgd_t *page_dir;
pmd_t *page_middle;
pte_t *page_table, pte;
unsigned long tmp;
......@@ -759,15 +725,21 @@ int shm_swap (int prio)
tmp = shmd->vm_start + (idx << PAGE_SHIFT) - shmd->vm_offset;
if (!(tmp >= shmd->vm_start && tmp < shmd->vm_end))
continue;
page_dir = PAGE_DIR_OFFSET(shmd->vm_task,tmp);
page_dir = pgd_offset(shmd->vm_task,tmp);
if (pgd_none(*page_dir) || pgd_bad(*page_dir)) {
printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
id, shmd->vm_start, idx);
pgd_clear(page_dir);
continue;
}
page_table = (pte_t *) pgd_page(*page_dir);
page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
page_middle = pmd_offset(page_dir,tmp);
if (pmd_none(*page_middle) || pmd_bad(*page_middle)) {
printk("shm_swap: bad pgmid! id=%ld start=%lx idx=%ld\n",
id, shmd->vm_start, idx);
pmd_clear(page_middle);
continue;
}
page_table = pte_offset(page_middle,tmp);
pte = *page_table;
if (!pte_present(pte))
continue;
......@@ -779,7 +751,8 @@ int shm_swap (int prio)
printk("shm_swap_out: page and pte mismatch\n");
pte_val(*page_table) = shmd->vm_pte | idx << SHM_IDX_SHIFT;
mem_map[MAP_NR(pte_page(pte))]--;
shmd->vm_task->mm->rss--;
if (shmd->vm_task->mm->rss > 0)
shmd->vm_task->mm->rss--;
invalid++;
/* continue looping through circular list */
} while (0);
......
......@@ -163,12 +163,11 @@ static void copy_fs(unsigned long clone_flags, struct task_struct * p)
* information (task[nr]) and sets up the necessary registers. It
* also copies the data segment in its entirety.
*/
asmlinkage int sys_fork(struct pt_regs regs)
int do_fork(unsigned long clone_flags, unsigned long usp, struct pt_regs *regs)
{
int nr;
struct task_struct *p;
unsigned long new_stack;
unsigned long clone_flags = COPYVM | SIGCHLD;
struct task_struct *p;
if(!(p = (struct task_struct*)__get_free_page(GFP_KERNEL)))
goto bad_fork;
......@@ -206,7 +205,7 @@ asmlinkage int sys_fork(struct pt_regs regs)
task[nr] = p;
/* copy all the process information */
clone_flags = copy_thread(nr, COPYVM | SIGCHLD, p, &regs);
copy_thread(nr, clone_flags, usp, p, regs);
if (copy_mm(clone_flags, p))
goto bad_fork_cleanup;
p->semundo = NULL;
......
......@@ -517,6 +517,7 @@ asmlinkage int sys_setsid(void)
current->leader = 1;
current->session = current->pgrp = current->pid;
current->tty = NULL;
current->tty_old_pgrp = 0;
return current->pgrp;
}
......
......@@ -506,11 +506,10 @@ static int swap_out_process(struct task_struct * p)
static int swap_out(unsigned int priority)
{
static int swap_task;
int loop;
int counter = NR_TASKS * 2 >> priority;
int loop, counter;
struct task_struct *p;
counter = NR_TASKS * 2 >> priority;
counter = 2*NR_TASKS >> priority;
for(; counter >= 0; counter--, swap_task++) {
/*
* Check that swap_task is suitable for swapping. If not, look for
......@@ -557,6 +556,15 @@ static int swap_out(unsigned int priority)
return 0;
}
/*
* we keep on shrinking one resource until it's considered "too hard",
* and then switch to the next one (priority being an indication on how
* hard we should try with the resource).
*
* This should automatically find the resource that can most easily be
* free'd, so hopefully we'll get reasonable behaviour even under very
* different circumstances.
*/
static int try_to_free_page(int priority)
{
static int state = 0;
......@@ -565,23 +573,19 @@ static int try_to_free_page(int priority)
switch (state) {
do {
case 0:
if (priority != GFP_NOBUFFER && shrink_buffers(i)) {
state = 1;
if (priority != GFP_NOBUFFER && shrink_buffers(i))
return 1;
}
state = 1;
case 1:
if (shm_swap(i)) {
state = 2;
if (shm_swap(i))
return 1;
}
case 2:
if (swap_out(i)) {
state = 0;
state = 2;
default:
if (swap_out(i))
return 1;
}
state = 0;
} while(--i);
}
state = 2;
return 0;
}
......
......@@ -864,11 +864,13 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
{
/* should be below! */
if (sk2->num != snum) continue;
#if 0
if (sk2->dead)
{
destroy_sock(sk2);
goto outside_loop;
}
#endif
if (!sk->reuse)
{
sti();
......
......@@ -2769,9 +2769,9 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->linger=0;
newsk->destroy = 0;
init_timer(&newsk->timer);
init_timer(&newsk->retransmit_timer);
newsk->timer.data = (unsigned long)newsk;
newsk->timer.function = &net_timer;
init_timer(&newsk->retransmit_timer);
newsk->retransmit_timer.data = (unsigned long)newsk;
newsk->retransmit_timer.function=&retransmit_timer;
newsk->dummy_th.source = skb->h.th->dest;
......@@ -4393,7 +4393,9 @@ static int tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
tcp_set_state(sk,TCP_SYN_SENT);
sk->rto = TCP_TIMEOUT_INIT;
init_timer(&sk->retransmit_timer);
#if 0 /* we already did this */
init_timer(&sk->retransmit_timer);
#endif
sk->retransmit_timer.function=&retransmit_timer;
sk->retransmit_timer.data = (unsigned long)sk;
reset_xmit_timer(sk, TIME_WRITE, sk->rto); /* Timer for repeating the SYN until an answer */
......
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