Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
8151e895
Commit
8151e895
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 1.1.32
parent
3dd3f561
Changes
31
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
965 additions
and
311 deletions
+965
-311
Makefile
Makefile
+1
-1
config.in
config.in
+1
-1
drivers/block/README.hd
drivers/block/README.hd
+98
-0
drivers/block/hd.c
drivers/block/hd.c
+332
-40
drivers/char/console.c
drivers/char/console.c
+59
-3
drivers/char/keyboard.c
drivers/char/keyboard.c
+6
-1
drivers/char/mem.c
drivers/char/mem.c
+1
-1
drivers/char/tty_io.c
drivers/char/tty_io.c
+7
-0
drivers/net/Space.c
drivers/net/Space.c
+9
-1
drivers/net/ppp.c
drivers/net/ppp.c
+9
-4
drivers/sound/Makefile
drivers/sound/Makefile
+1
-1
drivers/sound/Readme
drivers/sound/Readme
+3
-2
drivers/sound/ad1848.c
drivers/sound/ad1848.c
+7
-7
drivers/sound/configure.c
drivers/sound/configure.c
+8
-1
drivers/sound/dev_table.h
drivers/sound/dev_table.h
+3
-0
drivers/sound/dmabuf.c
drivers/sound/dmabuf.c
+1
-1
drivers/sound/sb_dsp.c
drivers/sound/sb_dsp.c
+18
-4
drivers/sound/sb_mixer.c
drivers/sound/sb_mixer.c
+73
-14
drivers/sound/sb_mixer.h
drivers/sound/sb_mixer.h
+40
-0
drivers/sound/sound_calls.h
drivers/sound/sound_calls.h
+1
-1
drivers/sound/sound_config.h
drivers/sound/sound_config.h
+2
-2
include/linux/hdreg.h
include/linux/hdreg.h
+11
-0
include/linux/mm.h
include/linux/mm.h
+4
-4
include/linux/wait.h
include/linux/wait.h
+4
-0
kernel/ptrace.c
kernel/ptrace.c
+59
-25
kernel/sched.c
kernel/sched.c
+56
-40
mm/memory.c
mm/memory.c
+122
-154
net/inet/af_inet.c
net/inet/af_inet.c
+1
-0
net/inet/arp.c
net/inet/arp.c
+3
-1
net/inet/dev.c
net/inet/dev.c
+13
-0
net/inet/tcp.c
net/inet/tcp.c
+12
-2
No files found.
Makefile
View file @
8151e895
VERSION
=
1
PATCHLEVEL
=
1
SUBLEVEL
=
3
1
SUBLEVEL
=
3
2
all
:
Version zImage
...
...
config.in
View file @
8151e895
...
...
@@ -81,7 +81,6 @@ if [ "$CONFIG_SLIP" = "y" ]; then
fi
bool 'PPP (point-to-point) support' CONFIG_PPP n
bool 'PLIP (parallel port) support' CONFIG_PLIP n
bool 'SK_G16 support' CONFIG_SK_G16 n
bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
...
...
@@ -110,6 +109,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
fi
bool 'HP PCLAN support' CONFIG_HPLAN n
bool 'NE2000/NE1000 support' CONFIG_NE2000 y
bool 'SK_G16 support' CONFIG_SK_G16 n
fi
bool 'EISA and on board controllers' CONFIG_NET_EISA n
if [ "$CONFIG_NET_ALPHA" = "y" ]; then
...
...
drivers/block/README.hd
0 → 100644
View file @
8151e895
IDE Performance Enhancements Version 2.0
============================ ===========
This version of hd.c includes support for two optional features:
(1) The disk I/O routines can now run with interrupts unmasked
most of the time, making them much friendlier to high
speed serial ports and other system activity.
(2) Support is included for IDE "Multiple Sector Mode", the use
of which can reduce disk I/O kernel overhead by 10-30%
on many systems, with a corresponding 10-20% increase in
data throughput.
By default, both features are DISABLED, for compatibility with
systems on which they may cause troubles.
The IRQ unmasking has been known to CORRUPT FILESYSTEMS in the
past on systems with strange hard drives. Backup before trying!
It works on most systems, but use at your own risk!!
Drives which support "Multiple Sector Mode" are identified by the
kernel at boot time, and a message is displayed indicating the
largest possible setting for "MaxMult". I recommend using settings
of 8, 16, or 32. Many drives also support non-powers of two,
but many other drives do not -- try strange values at your own risk!
For more detailed boot-time information about your drive, change
the definition of VERBOSE_DRIVE_INFO from 0 to 1 near the top
of hd.c and rebuild/reinstall the kernel.
Some drives (mostly older CONNER drives) do not implement multiple mode
correctly, and data corruption may occur.. but if you wait long enough
the error recovery logic *should* be able to recover eventually.
To try this out more safely, mount the drive's partitions read-only
before using hdparm (see below) for the first time. If it doesn't
work, email me (mlord@bnr.ca) with the drive name as displayed at
boot time, so I can warn others and possibly add a hook to the code.
To enable the features, a small program is included: hdparm.c
This one is *different* from previous versions -- be sure to recompile it!
Compile this using cc -O -o /usr/bin/hdparm hdparm.c
and then use it to enable/disable the new features, as follows:
To turn on 16-sector multiple mode, with interrupt unmasking:
hdparm /dev/hda 16 1
To view the current settings:
hdparm /dev/hda
If you have more than one drive, a separate command would need to be issued for the second drive as well, using the same or different
settings as desired:
hdparm /dev/hdb 16 1
To turn off both features on the first drive, use:
hdparm /dev/hda 0 0
To benchmark the performance difference, try:
hdparm /dev/hda 0 0
sync
time dd if=/dev/hda of=/dev/null bs=1024k count=30
time dd if=/dev/hda of=/dev/null bs=1024k count=30
time dd if=/dev/hda of=/dev/null bs=1024k count=30
hdparm /dev/hda 16 1
sync
time dd if=/dev/hda of=/dev/null bs=1024k count=30
time dd if=/dev/hda of=/dev/null bs=1024k count=30
time dd if=/dev/hda of=/dev/null bs=1024k count=30
This gives before and after views. Compare the total elapsed times,
as well as the percent of CPU used in each case. Run several trials
to ensure/verify consistent results. Some drives are actually *slower*
with multiple mode enabled, but those are very rare indeed. Most systems
experience a 10-30% increase in throughput, with a corresponding 5-50%
decrease in kernel/system CPU usage.
If you are using linux kernel 1.1.4 or higher (with the "cluster" code),
then you may not notice a big difference with the above tests. However,
I have noticed that the iozone benchmark program does seem to work fairly
reliably under kernels with the "cluster" code, so you could try that
instead (under older kernels, iozone seems to give wildly varying results
from trial to trial, at least on my system).
To have your favorite settings installed automatically at boot time,
place the hdparm command(s) into the /etc/rc.d/rc.local file.
Alternatively, one could modify the DEFAULTs near the top of hd.c
and rebuild and install the new kernel.
Enjoy,
mlord@bnr.ca
drivers/block/hd.c
View file @
8151e895
...
...
@@ -14,9 +14,15 @@
*
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
* in the early extended-partition checks and added DM partitions
*
* IDE IRQ-unmask & drive-id & multiple-mode code added by Mark Lord.
*/
#define DEFAULT_MULT_COUNT 0
/* set to 0 to disable multiple mode at boot */
#define DEFAULT_UNMASK_INTR 0
/* set to 0 to *NOT* unmask irq's more often */
#define VERBOSE_DRIVE_INFO 0
/* set to 1 for more drive info at boot time */
#include <asm/irq.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
...
...
@@ -211,6 +217,128 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
outb_p
(
cmd
,
++
port
);
}
static
void
hd_request
(
void
);
unsigned
int
identified
[
MAX_HD
]
=
{
0
,};
/* 1 = drive ID already displayed */
unsigned
int
unmask_intr
[
MAX_HD
]
=
{
0
,};
/* 1 = unmask IRQs during I/O */
unsigned
int
max_mult
[
MAX_HD
]
=
{
0
,};
/* max sectors for MultMode */
unsigned
int
mult_req
[
MAX_HD
]
=
{
0
,};
/* requested MultMode count */
unsigned
int
mult_count
[
MAX_HD
]
=
{
0
,};
/* currently enabled MultMode count */
struct
request
WCURRENT
;
static
void
rawstring
(
char
*
prefix
,
char
*
s
,
int
n
)
{
if
(
prefix
)
printk
(
prefix
);
if
(
s
&&
*
s
)
{
int
i
;
for
(
i
=
0
;
i
<
n
&&
s
[
i
^
1
]
==
' '
;
++
i
);
/* skip blanks */
for
(;
i
<
n
&&
s
[
i
^
1
];
++
i
)
/* flip bytes */
if
(
s
[
i
^
1
]
!=
' '
||
((
i
+
1
)
<
n
&&
s
[(
i
+
1
)
^
1
]
!=
' '
))
printk
(
"%c"
,
s
[
i
^
1
]);
}
}
#if VERBOSE_DRIVE_INFO
char
*
cfg_str
[]
=
{
""
,
" HardSect"
,
" SoftSect"
,
" NotMFM"
,
" HdSw>15uSec"
,
" SpinMotCtl"
,
" Fixed"
,
" Removeable"
,
" DTR<=5Mbs"
,
" DTR>5Mbs"
,
" DTR>10Mbs"
,
" RotSpdTol>.5%"
,
" dStbOff"
,
" TrkOff"
,
" FmtGapReq"
,
""
,
};
char
*
ioready
[]
=
{
"no"
,
"?"
,
"yes"
,
"on/off"
};
char
*
SlowMedFast
[]
=
{
"slow"
,
"medium"
,
"fast"
};
char
*
BuffType
[]
=
{
"?"
,
"1Sect"
,
"DualPort"
,
"DualPortCache"
};
#define YN(b) (((b)==0)?"no":"yes")
static
void
dmpstr
(
char
*
prefix
,
unsigned
int
i
,
char
*
s
[],
unsigned
int
maxi
)
{
printk
(
prefix
);
printk
(
(
i
>
maxi
)
?
"?"
:
s
[
i
]
);
}
static
void
dump_identity
(
unsigned
int
dev
,
unsigned
short
ib
[])
{
int
i
;
char
dashes
[]
=
"
\n
+-------------------------------------------------------------------+
\n
"
;
printk
(
dashes
);
printk
(
"hd%c: Drive Identification Info:
\n
"
,
dev
+
'a'
);
rawstring
(
" Model="
,(
char
*
)
&
ib
[
27
],
40
);
rawstring
(
", FwRev="
,(
char
*
)
&
ib
[
23
],
8
);
rawstring
(
", SerialNo="
,(
char
*
)
&
ib
[
10
],
20
);
printk
(
"
\n
Config={"
);
for
(
i
=
0
;
i
<=
15
;
i
++
)
if
(
ib
[
0
]
&
(
1
<<
i
))
printk
(
cfg_str
[
i
]);
printk
(
" }
\n
"
);
printk
(
" Default c/h/s=%d/%d/%d, TrkSize=%d, SectSize=%d, ECCbytes=%d
\n
"
,
ib
[
1
],
ib
[
3
],
ib
[
6
],
ib
[
4
],
ib
[
5
],
ib
[
22
]);
dmpstr
(
" BuffType="
,
ib
[
20
],
BuffType
,
3
);
ib
[
47
]
&=
0xFF
;
printk
(
", BuffSize=%dKB, MaxMultSect=%d
\n
"
,
ib
[
21
]
/
2
,
ib
[
47
]);
printk
(
" Features: DblWordIO=%s, IORDY=%s, LBA=%s, DMA=%s"
,
YN
(
ib
[
48
]
&
1
),
ioready
[(
ib
[
49
]
&
0xC00
)
>>
10
],
YN
(
ib
[
49
]
&
0x200
),
YN
(
ib
[
49
]
&
0x100
));
dmpstr
(
", tPIO="
,
ib
[
51
]
>>
8
,
SlowMedFast
,
2
);
if
(
ib
[
49
]
&
0x100
&&
(
ib
[
53
]
&
1
))
dmpstr
(
", tDMA="
,
ib
[
52
]
>>
8
,
SlowMedFast
,
2
);
printk
(
"
\n
(%s): Current c/h/s=%d/%d/%d, TotSect=%d"
,
(((
ib
[
53
]
&
1
)
==
0
)
?
"maybe"
:
"valid"
),
ib
[
54
],
ib
[
55
],
ib
[
56
],
*
(
int
*
)
&
ib
[
57
]);
if
(
ib
[
49
]
&
0x200
)
printk
(
", MaxLBAsect=%d"
,
*
(
int
*
)
&
ib
[
60
]);
printk
(
"
\n
CurMultSect=%d%s"
,
ib
[
59
]
&
0xFF
,(
ib
[
59
]
&
0x100
)
?
""
:
"?"
);
if
(
ib
[
49
]
&
0x100
)
printk
(
", DMA-1w=%04X, DMA-mw=%04X"
,
ib
[
62
],
ib
[
63
]);
printk
(
"%s
\n
"
,
dashes
);
}
#endif
/* VERBOSE_DRIVE_INFO */
static
void
identify_intr
(
void
)
{
unsigned
int
dev
=
DEVICE_NR
(
CURRENT
->
dev
);
unsigned
short
ib
[
64
],
stat
=
inb_p
(
HD_STATUS
);
if
(
unmask_intr
[
dev
])
sti
();
if
(
stat
&
(
BUSY_STAT
|
ERR_STAT
))
printk
(
" hd%c: multiple mode not supported
\n
"
,
dev
+
'a'
);
else
{
insw
(
HD_DATA
,(
char
*
)
ib
,
64
);
/* get first 128 ID bytes */
#if VERBOSE_DRIVE_INFO
dump_identity
(
dev
,
ib
);
#endif
printk
(
" hd%c: "
,
dev
+
'a'
);
rawstring
(
NULL
,
(
char
*
)
&
ib
[
27
],
40
);
max_mult
[
dev
]
=
ib
[
47
]
&
0xff
;
printk
(
" (%dMB IDE w/%dKB Cache, MaxMult=%d)
\n
"
,
ib
[
1
]
*
ib
[
3
]
*
ib
[
6
]
/
2048
,
ib
[
21
]
>>
1
,
max_mult
[
dev
]);
insw
(
HD_DATA
,(
char
*
)
ib
,
64
);
/* flush remaining 384 ID bytes */
insw
(
HD_DATA
,(
char
*
)
ib
,
64
);
insw
(
HD_DATA
,(
char
*
)
ib
,
64
);
}
hd_request
();
return
;
}
static
void
set_multmode_intr
(
void
)
{
unsigned
int
dev
=
DEVICE_NR
(
CURRENT
->
dev
),
stat
=
inb_p
(
HD_STATUS
);
if
(
unmask_intr
[
dev
])
sti
();
if
(
stat
&
(
BUSY_STAT
|
ERR_STAT
))
{
mult_req
[
dev
]
=
mult_count
[
dev
]
=
0
;
printk
(
" hd%c: set multiple mode failed
\n
"
,
dev
+
'a'
);
}
else
{
if
((
mult_count
[
dev
]
=
mult_req
[
dev
]))
printk
(
" hd%c: enabled %d-sector multiple mode
\n
"
,
dev
+
'a'
,
mult_count
[
dev
]);
else
printk
(
" hd%c: disabled multiple mode
\n
"
,
dev
+
'a'
);
}
hd_request
();
return
;
}
static
int
drive_busy
(
void
)
{
unsigned
int
i
;
...
...
@@ -254,14 +382,21 @@ static void reset_hd(void)
if
(
reset
)
goto
repeat
;
}
i
++
;
if
(
i
<
NR_HD
)
{
if
(
++
i
<
NR_HD
)
{
if
(
unmask_intr
[
i
])
{
printk
(
"hd%c: disabled irq-unmasking
\n
"
,
i
+
'a'
);
unmask_intr
[
i
]
=
0
;
}
if
(
mult_req
[
i
]
||
mult_count
[
i
])
{
printk
(
"hd%c: disabled multiple mode
\n
"
,
i
+
'a'
);
mult_req
[
i
]
=
mult_count
[
i
]
=
0
;
}
hd_out
(
i
,
hd_info
[
i
].
sect
,
hd_info
[
i
].
sect
,
hd_info
[
i
].
head
-
1
,
hd_info
[
i
].
cyl
,
WIN_SPECIFY
,
&
reset_hd
);
if
(
reset
)
goto
repeat
;
}
else
do_
hd_request
();
hd_request
();
}
/*
...
...
@@ -313,9 +448,11 @@ static inline int wait_DRQ(void)
static
void
read_intr
(
void
)
{
int
i
;
int
retries
=
100000
;
unsigned
int
dev
=
DEVICE_NR
(
CURRENT
->
dev
)
;
int
i
,
retries
=
100000
,
msect
,
nsect
;
if
(
unmask_intr
[
dev
])
sti
();
/* permit other IRQs during xfer */
do
{
i
=
(
unsigned
)
inb_p
(
HD_STATUS
);
if
(
i
&
BUSY_STAT
)
...
...
@@ -326,42 +463,111 @@ static void read_intr(void)
goto
ok_to_read
;
}
while
(
--
retries
>
0
);
sti
();
printk
(
"
HD: read_intr: status = 0x%02x
\n
"
,
i
);
printk
(
"
hd%c: read_intr: status = 0x%02x
\n
"
,
dev
+
'a'
,
i
);
if
(
i
&
ERR_STAT
)
{
hd_error
=
(
unsigned
)
inb
(
HD_ERROR
);
printk
(
"
HD: read_intr: error = 0x%02x
\n
"
,
hd_error
);
printk
(
"
hd%c: read_intr: error = 0x%02x
\n
"
,
dev
+
'a'
,
hd_error
);
}
bad_rw_intr
();
cli
();
do_
hd_request
();
hd_request
();
return
;
ok_to_read:
insw
(
HD_DATA
,
CURRENT
->
buffer
,
256
);
msect
=
mult_count
[
dev
];
read_next:
if
(
msect
)
{
if
((
nsect
=
CURRENT
->
current_nr_sectors
)
>
msect
)
nsect
=
msect
;
msect
-=
nsect
;
}
else
nsect
=
1
;
insw
(
HD_DATA
,
CURRENT
->
buffer
,
nsect
<<
8
);
CURRENT
->
sector
+=
nsect
;
CURRENT
->
buffer
+=
nsect
<<
9
;
CURRENT
->
errors
=
0
;
CURRENT
->
buffer
+=
512
;
CURRENT
->
sector
++
;
i
=
--
CURRENT
->
nr_sectors
;
--
CURRENT
->
current_nr_sectors
;
i
=
(
CURRENT
->
nr_sectors
-=
nsect
);
#ifdef DEBUG
printk
(
"hd%
d : sector = %d, %d remaining to buffer = %08
x
\n
"
,
MINOR
(
CURRENT
->
dev
),
CURRENT
->
sector
,
i
,
CURRENT
->
buffer
);
printk
(
"hd%
c: read: sectors(%ld-%ld), remaining=%ld, buffer=%08l
x
\n
"
,
dev
+
'a'
,
CURRENT
->
sector
,
CURRENT
->
sector
+
nsect
,
CURRENT
->
nr_sectors
,
(
long
)
CURRENT
->
buffer
+
(
nsect
<<
9
)
);
#endif
if
(
!
i
||
(
CURRENT
->
bh
&&
!
SUBSECTOR
(
i
))
)
if
(
(
CURRENT
->
current_nr_sectors
-=
nsect
)
<=
0
)
end_request
(
1
);
if
(
i
>
0
)
{
if
(
msect
)
goto
read_next
;
SET_INTR
(
&
read_intr
);
sti
();
return
;
}
(
void
)
inb_p
(
HD_STATUS
);
#if (HD_DELAY > 0)
last_req
=
read_timer
();
#endif
do_hd_request
();
if
(
CURRENT
)
hd_request
();
return
;
}
static
inline
void
multwrite
(
unsigned
int
dev
)
{
unsigned
int
mcount
=
mult_count
[
dev
];
while
(
mcount
--
)
{
outsw
(
HD_DATA
,
WCURRENT
.
buffer
,
256
);
if
(
!--
WCURRENT
.
nr_sectors
)
return
;
WCURRENT
.
buffer
+=
512
;
if
(
!--
WCURRENT
.
current_nr_sectors
)
{
WCURRENT
.
bh
=
WCURRENT
.
bh
->
b_reqnext
;
if
(
WCURRENT
.
bh
==
NULL
)
panic
(
"buffer list corrupted
\n
"
);
WCURRENT
.
current_nr_sectors
=
WCURRENT
.
bh
->
b_size
>>
9
;
WCURRENT
.
buffer
=
WCURRENT
.
bh
->
b_data
;
}
}
}
static
void
multwrite_intr
(
void
)
{
int
i
;
unsigned
int
dev
=
DEVICE_NR
(
WCURRENT
.
dev
);
if
(
unmask_intr
[
dev
])
sti
();
if
(((
i
=
inb_p
(
HD_STATUS
))
&
STAT_MASK
)
==
STAT_OK
)
{
if
(
i
&
DRQ_STAT
)
{
if
(
WCURRENT
.
nr_sectors
)
{
multwrite
(
dev
);
SET_INTR
(
&
multwrite_intr
);
return
;
}
}
else
{
if
(
!
WCURRENT
.
nr_sectors
)
{
/* all done? */
for
(
i
=
CURRENT
->
nr_sectors
;
i
>
0
;){
i
-=
CURRENT
->
current_nr_sectors
;
end_request
(
1
);
}
#if (HD_DELAY > 0)
last_req
=
read_timer
();
#endif
if
(
CURRENT
)
hd_request
();
return
;
}
}
}
sti
();
printk
(
"hd%c: multwrite_intr: status = 0x%02x
\n
"
,
dev
+
'a'
,
i
);
if
(
i
&
ERR_STAT
)
{
hd_error
=
(
unsigned
)
inb
(
HD_ERROR
);
printk
(
"hd:%c multwrite_intr: error = 0x%02x
\n
"
,
dev
+
'a'
,
hd_error
);
}
bad_rw_intr
();
cli
();
hd_request
();
}
static
void
write_intr
(
void
)
{
int
i
;
...
...
@@ -384,7 +590,7 @@ static void write_intr(void)
}
bad_rw_intr
();
cli
();
do_
hd_request
();
hd_request
();
return
;
ok_to_write:
CURRENT
->
sector
++
;
...
...
@@ -401,7 +607,7 @@ static void write_intr(void)
#if (HD_DELAY > 0)
last_req
=
read_timer
();
#endif
do_
hd_request
();
hd_request
();
}
return
;
}
...
...
@@ -410,7 +616,7 @@ static void recal_intr(void)
{
if
(
win_result
())
bad_rw_intr
();
do_
hd_request
();
hd_request
();
}
/*
...
...
@@ -433,7 +639,7 @@ static void hd_times_out(void)
end_request
(
0
);
}
do_
hd_request
();
hd_request
();
}
/*
...
...
@@ -443,7 +649,7 @@ static void hd_times_out(void)
* worst that can happen is that an unexpected HD-interrupt comes in and
* sets the "reset" variable and starts the timer)
*/
static
void
do_
hd_request
(
void
)
static
void
hd_request
(
void
)
{
unsigned
int
block
,
dev
;
unsigned
int
sec
,
head
,
cyl
,
track
;
...
...
@@ -462,7 +668,7 @@ static void do_hd_request(void)
nsect
=
CURRENT
->
nr_sectors
;
if
(
dev
>=
(
NR_HD
<<
6
)
||
block
>=
hd
[
dev
].
nr_sects
)
{
#ifdef DEBUG
printk
(
"hd
%d
: attempted read for sector %d past end of device at sector %d.
\n
"
,
printk
(
"hd : attempted read for sector %d past end of device at sector %d.
\n
"
,
block
,
hd
[
dev
].
nr_sects
);
#endif
end_request
(
0
);
...
...
@@ -475,17 +681,18 @@ static void do_hd_request(void)
head
=
track
%
hd_info
[
dev
].
head
;
cyl
=
track
/
hd_info
[
dev
].
head
;
#ifdef DEBUG
printk
(
"hd%
d
: cyl = %d, head = %d, sector = %d, buffer = %08x
\n
"
,
dev
,
cyl
,
head
,
sec
,
CURRENT
->
buffer
);
printk
(
"hd%
c
: cyl = %d, head = %d, sector = %d, buffer = %08x
\n
"
,
dev
+
'a'
,
cyl
,
head
,
sec
,
CURRENT
->
buffer
);
#endif
cli
();
if
(
!
unmask_intr
[
dev
])
cli
();
if
(
reset
)
{
int
i
;
for
(
i
=
0
;
i
<
NR_HD
;
i
++
)
recalibrate
[
i
]
=
1
;
cli
();
/* better play it safe, as resets are the last resort */
reset_hd
();
sti
();
return
;
}
if
(
recalibrate
[
dev
])
{
...
...
@@ -493,32 +700,70 @@ static void do_hd_request(void)
hd_out
(
dev
,
hd_info
[
dev
].
sect
,
0
,
0
,
0
,
WIN_RESTORE
,
&
recal_intr
);
if
(
reset
)
goto
repeat
;
sti
();
return
;
}
if
(
CURRENT
->
cmd
==
WRITE
)
{
hd_out
(
dev
,
nsect
,
sec
,
head
,
cyl
,
WIN_WRITE
,
&
write_intr
);
if
(
!
identified
[
dev
])
{
identified
[
dev
]
=
1
;
unmask_intr
[
dev
]
=
DEFAULT_UNMASK_INTR
;
mult_req
[
dev
]
=
DEFAULT_MULT_COUNT
;
hd_out
(
dev
,
0
,
0
,
0
,
0
,
WIN_IDENTIFY
,
&
identify_intr
);
if
(
reset
)
goto
repeat
;
if
(
wait_DRQ
())
{
printk
(
"HD: do_hd_request: no DRQ
\n
"
);
bad_rw_intr
();
return
;
}
if
(
mult_req
[
dev
]
!=
mult_count
[
dev
])
{
hd_out
(
dev
,
mult_req
[
dev
],
0
,
0
,
0
,
WIN_SETMULT
,
&
set_multmode_intr
);
if
(
reset
)
goto
repeat
;
}
outsw
(
HD_DATA
,
CURRENT
->
buffer
,
256
);
sti
();
return
;
}
if
(
CURRENT
->
cmd
==
READ
)
{
hd_out
(
dev
,
nsect
,
sec
,
head
,
cyl
,
WIN_READ
,
&
read_intr
);
unsigned
int
cmd
=
mult_count
[
dev
]
>
1
?
WIN_MULTREAD
:
WIN_READ
;
hd_out
(
dev
,
nsect
,
sec
,
head
,
cyl
,
cmd
,
&
read_intr
);
if
(
reset
)
goto
repeat
;
sti
();
#ifdef DEBUG
printk
(
"hd%c: reading %d sectors(%ld-%ld), buffer=%08lx
\n
"
,
dev
+
'a'
,
nsect
,
CURRENT
->
sector
,
CURRENT
->
sector
+
nsect
-
1
,
(
long
)
CURRENT
->
buffer
);
#endif
return
;
}
if
(
CURRENT
->
cmd
==
WRITE
)
{
if
(
mult_count
[
dev
])
hd_out
(
dev
,
nsect
,
sec
,
head
,
cyl
,
WIN_MULTWRITE
,
&
multwrite_intr
);
else
hd_out
(
dev
,
nsect
,
sec
,
head
,
cyl
,
WIN_WRITE
,
&
write_intr
);
if
(
reset
)
goto
repeat
;
#ifdef DEBUG
printk
(
"hd%c: writing %d sectors(%ld-%ld), buffer=%08lx
\n
"
,
dev
+
'a'
,
nsect
,
CURRENT
->
sector
,
CURRENT
->
sector
+
nsect
-
1
,
(
long
)
CURRENT
->
buffer
);
#endif
if
(
wait_DRQ
())
{
printk
(
"hd%c: hd_request: no DRQ
\n
"
,
dev
+
'a'
);
bad_rw_intr
();
goto
repeat
;
}
if
(
mult_count
[
dev
])
{
WCURRENT
=
*
CURRENT
;
multwrite
(
dev
);
}
else
{
outsw
(
HD_DATA
,
CURRENT
->
buffer
,
256
);
}
return
;
}
panic
(
"unknown hd-command"
);
}
static
void
do_hd_request
(
void
)
{
disable_irq
(
HD_IRQ
);
hd_request
();
enable_irq
(
HD_IRQ
);
}
static
int
hd_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
...
...
@@ -568,6 +813,53 @@ static int hd_ioctl(struct inode * inode, struct file * file,
case
BLKRRPART
:
/* Re-read partition tables */
return
revalidate_hddisk
(
inode
->
i_rdev
,
1
);
case
HDIO_SETUNMASKINTR
:
if
(
!
arg
)
return
-
EINVAL
;
err
=
verify_area
(
VERIFY_READ
,
(
long
*
)
arg
,
sizeof
(
long
));
if
(
err
)
return
err
;
unmask_intr
[
dev
]
=
get_fs_long
((
long
*
)
arg
);
return
0
;
case
HDIO_GETUNMASKINTR
:
if
(
!
arg
)
return
-
EINVAL
;
err
=
verify_area
(
VERIFY_WRITE
,
(
long
*
)
arg
,
sizeof
(
long
));
if
(
err
)
return
err
;
put_fs_long
(
unmask_intr
[
dev
],
(
long
*
)
arg
);
return
0
;
case
HDIO_GETMULTCOUNT
:
if
(
!
arg
)
return
-
EINVAL
;
err
=
verify_area
(
VERIFY_WRITE
,
(
long
*
)
arg
,
sizeof
(
long
));
if
(
err
)
return
err
;
put_fs_long
(
mult_count
[
dev
],
(
long
*
)
arg
);
return
0
;
case
HDIO_SETMULTCOUNT
:
{
unsigned
long
flags
;
if
(
!
arg
)
return
-
EINVAL
;
err
=
verify_area
(
VERIFY_READ
,
(
long
*
)
arg
,
sizeof
(
long
));
if
(
err
)
return
err
;
arg
=
get_fs_long
((
long
*
)
arg
);
save_flags
(
flags
);
cli
();
/* a prior request might still be in progress */
if
(
arg
>
max_mult
[
dev
])
err
=
-
EINVAL
;
/* out of range for device */
else
if
(
mult_req
[
dev
]
!=
mult_count
[
dev
])
err
=
-
EBUSY
;
/* busy, try again */
else
{
mult_req
[
dev
]
=
arg
;
err
=
0
;
}
restore_flags
(
flags
);
return
err
;
}
RO_IOCTLS
(
inode
->
i_rdev
,
arg
);
default:
return
-
EINVAL
;
...
...
drivers/char/console.c
View file @
8151e895
...
...
@@ -83,6 +83,7 @@ static struct termios *console_termios_locked[NR_CONSOLES];
int
set_selection
(
const
int
arg
);
int
paste_selection
(
struct
tty_struct
*
tty
);
static
void
clear_selection
(
void
);
static
void
highlight_pointer
(
const
int
currcons
,
const
int
where
);
/* Variables for selection control. */
#define SEL_BUFFER_SIZE 4096
...
...
@@ -1703,6 +1704,9 @@ void update_screen(int new_console)
return
;
lock
=
1
;
kbdsave
(
new_console
);
#ifdef CONFIG_SELECTION
highlight_pointer
(
fg_console
,
-
1
);
#endif
/* CONFIG_SELECTION */
get_scrmem
(
fg_console
);
fg_console
=
new_console
;
set_scrmem
(
fg_console
);
...
...
@@ -1778,8 +1782,49 @@ static void highlight(const int currcons, const int s, const int e)
*
p
=
(
*
p
&
0x88
)
|
((
*
p
<<
4
)
&
0x70
)
|
((
*
p
>>
4
)
&
0x07
);
}
/* is c in range [a-zA-Z0-9_]? */
static
inline
int
inword
(
const
char
c
)
{
return
(
isalnum
(
c
)
||
c
==
'_'
);
}
/* use complementary color to show the pointer */
static
void
highlight_pointer
(
const
int
currcons
,
const
int
where
)
{
unsigned
char
*
p
;
static
char
*
prev
=
NULL
;
if
(
where
==-
1
)
/* remove the pointer */
{
if
(
prev
)
{
*
prev
^=
0x77
;
prev
=
NULL
;
}
}
else
{
p
=
(
unsigned
char
*
)
origin
-
hwscroll_offset
+
where
+
1
;
*
p
^=
0x77
;
if
(
prev
)
*
prev
^=
0x77
;
/* remove the previous one */
prev
=
p
;
}
}
/*
* This function uses a 128-bit look up table
*/
static
unsigned
long
inwordLut
[
4
]
=
{
0x00000000
,
/* control chars */
0x03FF0000
,
/* digits */
0x87FFFFFE
,
/* uppercase and '_' */
0x07FFFFFE
/* lowercase */
};
static
inline
int
inword
(
const
char
c
)
{
return
(
inwordLut
[(
c
>>
5
)
&
3
]
>>
(
c
&
0x1F
)
)
&
1
;
}
/* set inwordLut conntents. Invoked by ioctl(). */
int
sel_loadlut
(
const
int
arg
)
{
memcpy_fromfs
(
inwordLut
,(
unsigned
long
*
)(
arg
+
4
),
16
);
return
0
;
}
/* does screen address p correspond to character at LH/RH edge of screen? */
static
inline
int
atedge
(
const
int
p
)
...
...
@@ -1828,7 +1873,6 @@ int set_selection(const int arg)
switch
(
sel_mode
)
{
case
0
:
/* character-by-character selection */
default:
new_sel_start
=
ps
;
new_sel_end
=
pe
;
break
;
...
...
@@ -1859,6 +1903,17 @@ int set_selection(const int arg)
new_sel_end
=
pe
+
video_size_row
-
pe
%
video_size_row
-
2
;
break
;
case
3
:
/* pointer highlight */
if
(
sel_cons
!=
currcons
)
{
highlight_pointer
(
sel_cons
,
-
1
);
clear_selection
();
sel_cons
=
currcons
;
}
highlight_pointer
(
sel_cons
,
pe
);
return
0
;
/* nothing more */
default:
return
-
EINVAL
;
}
/* select to end of line if on trailing space */
if
(
new_sel_end
>
new_sel_start
&&
...
...
@@ -1962,6 +2017,7 @@ int paste_selection(struct tty_struct *tty)
the selection. */
static
void
clear_selection
()
{
highlight_pointer
(
sel_cons
,
-
1
);
/* hide the pointer */
if
(
sel_start
!=
-
1
)
{
highlight
(
sel_cons
,
sel_start
,
sel_end
);
...
...
drivers/char/keyboard.c
View file @
8151e895
...
...
@@ -86,7 +86,12 @@ static unsigned long key_down[8] = { 0, };
static
int
want_console
=
-
1
;
static
int
last_console
=
0
;
/* last used VC */
static
int
dead_key_next
=
0
;
static
int
shift_state
=
0
;
/*
* In order to retrieve the shift_state (for the mouse server), either
* the variable must be global, or a new procedure must be create to
* return the value. I chose the former way.
*/
/*static*/
int
shift_state
=
0
;
static
int
npadch
=
-
1
;
/* -1 or number assembled on pad */
static
unsigned
char
diacr
=
0
;
static
char
rep
=
0
;
/* flag telling character repeat */
...
...
drivers/char/mem.c
View file @
8151e895
...
...
@@ -420,7 +420,7 @@ long chr_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_FTAPE
/* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
ftape_big_buffer
=
(
char
*
)
((
mem_start
+
0x7fff
)
&
~
0x7fff
);
printk
(
"ftape: allocated %d buffers al
l
igned at: %p
\n
"
,
printk
(
"ftape: allocated %d buffers aligned at: %p
\n
"
,
NR_FTAPE_BUFFERS
,
ftape_big_buffer
);
mem_start
=
(
long
)
ftape_big_buffer
+
NR_FTAPE_BUFFERS
*
0x8000
;
#endif
...
...
drivers/char/tty_io.c
View file @
8151e895
...
...
@@ -68,6 +68,8 @@
#ifdef CONFIG_SELECTION
extern
int
set_selection
(
const
int
arg
);
extern
int
paste_selection
(
struct
tty_struct
*
tty
);
extern
int
sel_loadlut
(
const
int
arg
);
extern
int
shift_state
;
#endif
/* CONFIG_SELECTION */
extern
int
do_screendump
(
int
arg
);
...
...
@@ -1385,6 +1387,11 @@ static int tty_ioctl(struct inode * inode, struct file * file,
case
4
:
unblank_screen
();
return
0
;
case
5
:
return
sel_loadlut
(
arg
);
case
6
:
put_fs_byte
(
shift_state
,
arg
);
return
0
;
#endif
/* CONFIG_SELECTION */
default:
return
-
EINVAL
;
...
...
drivers/net/Space.c
View file @
8151e895
...
...
@@ -54,7 +54,9 @@ extern int el16_probe(struct device *);
extern
int
elplus_probe
(
struct
device
*
);
extern
int
ac3200_probe
(
struct
device
*
);
extern
int
e2100_probe
(
struct
device
*
);
extern
int
SK_init
(
struct
device
*
dev
);
extern
int
ni52_probe
(
struct
device
*
);
extern
int
ni65_probe
(
struct
device
*
);
extern
int
SK_init
(
struct
device
*
);
/* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */
extern
int
atp_init
(
struct
device
*
);
...
...
@@ -129,6 +131,12 @@ ethif_probe(struct device *dev)
#endif
#if defined(CONFIG_SK_G16)
&&
SK_init
(
dev
)
#endif
#ifdef CONFIG_NI52
&&
ni52_probe
(
dev
)
#endif
#ifdef CONFIG_NI65
&&
ni65_probe
(
dev
)
#endif
&&
1
)
{
return
1
;
/* -ENODEV or -EAGAIN would be more accurate. */
...
...
drivers/net/ppp.c
View file @
8151e895
...
...
@@ -267,7 +267,6 @@ ppp_init(struct device *dev)
dev
->
mtu
=
PPP_MTU
;
dev
->
hard_start_xmit
=
ppp_xmit
;
dev
->
open
=
ppp_dev_open
;
dev
->
do_ioctl
=
ppp_dev_ioctl
;
dev
->
stop
=
ppp_dev_close
;
dev
->
get_stats
=
ppp_get_stats
;
dev
->
hard_header
=
ppp_header
;
...
...
@@ -280,6 +279,8 @@ ppp_init(struct device *dev)
#ifdef NET02D
dev
->
add_arp
=
ppp_add_arp
;
dev
->
queue_xmit
=
dev_queue_xmit
;
#else
dev
->
do_ioctl
=
ppp_dev_ioctl
;
#endif
for
(
i
=
0
;
i
<
DEV_NUMBUFFS
;
i
++
)
...
...
@@ -605,6 +606,7 @@ ppp_dev_close(struct device *dev)
return
0
;
}
#ifndef NET02D
static
int
ppp_dev_ioctl
(
struct
device
*
dev
,
struct
ifreq
*
ifr
)
{
struct
ppp
*
ppp
=
&
ppp_ctrl
[
dev
->
base_addr
];
...
...
@@ -630,6 +632,7 @@ static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr)
return
error
;
}
#endif
/*************************************************************
* TTY OUTPUT
...
...
@@ -650,7 +653,11 @@ ppp_output_done (void *ppp)
/* If the device is still up then enable the transmitter of the
next frame. */
if
(((
struct
ppp
*
)
ppp
)
->
dev
->
flags
&
IFF_UP
)
#ifndef NET02D
mark_bh
(
NET_BH
);
#else
dev_tint
(((
struct
ppp
*
)
ppp
)
->
dev
);
#endif
/* enable any blocked process pending transmission */
wake_up_interruptible
(
&
((
struct
ppp
*
)
ppp
)
->
write_wait
);
...
...
@@ -1124,9 +1131,7 @@ ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
}
/* receive the frame through the network software */
while
((
dev_rint
(
c
,
count
,
0
,
ppp
->
dev
)
&
~
1
)
!=
0
)
;
(
void
)
dev_rint
(
c
,
count
,
0
,
ppp
->
dev
);
return
1
;
}
...
...
drivers/sound/Makefile
View file @
8151e895
...
...
@@ -5,7 +5,7 @@
#
#
VERSION
=
2.90
VERSION
=
2.90
-2
TARGET_OS
=
linux
.c.s
:
...
...
drivers/sound/Readme
View file @
8151e895
...
...
@@ -12,8 +12,8 @@ VoxWare v2.90 release notes
there are some new features required by a popular
application. In addition there is also support
for the GUS MAX and the 16 bit sampling option of GUS.
Also the Windows Sound System stuff is there but may not
work yet (may work with some WSS compatible cards)
.
The MSS/WSS support works now. At least with SG NX Pro 16
.
********* IMPORTANT *****************************************
Linux 1.0 or later is required to by this driver version.
...
...
@@ -65,6 +65,7 @@ contributors. (I could have forgotten some names.)
Markus Aroharju and
Risto Kankkunen Major contributions to the mixer support
of GUS v3.7.
Hunyue Yau Mixer support for SG NX Pro.
Marc Hoffman PSS support.
Regards,
...
...
drivers/sound/ad1848.c
View file @
8151e895
...
...
@@ -903,16 +903,14 @@ ad1848_interrupt (int irq)
int
probe_ms_sound
(
struct
address_info
*
hw_config
)
{
int
config_port
=
hw_config
->
io_base
+
0
,
version_port
=
hw_config
->
io_base
+
3
;
if
((
INB
(
hw_config
->
io_base
+
3
)
&
0x04
)
==
0
)
return
0
;
/* WSS ID test failed */
if
(
hw_config
->
irq
>
11
)
return
;
return
0
;
if
(
hw_config
->
dma
>
3
||
hw_config
->
dma
==
2
)
return
;
if
(
hw_config
->
dma
!=
0
&&
hw_config
->
dma
!=
1
&&
hw_config
->
dma
!=
3
)
return
0
;
return
ad1848_detect
(
hw_config
->
io_base
+
4
);
}
...
...
@@ -920,10 +918,12 @@ probe_ms_sound (struct address_info *hw_config)
long
attach_ms_sound
(
long
mem_start
,
struct
address_info
*
hw_config
)
{
static
unsigned
char
interrupt_bits
[
1
1
]
=
static
unsigned
char
interrupt_bits
[
1
2
]
=
{
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
-
1
,
0x08
,
-
1
,
0x10
,
0x18
,
0x20
};
char
bits
;
static
unsigned
char
dma_bits
[
4
]
=
{
1
,
2
,
0
,
3
};
int
config_port
=
hw_config
->
io_base
+
0
,
version_port
=
hw_config
->
io_base
+
3
;
if
(
!
ad1848_detect
(
hw_config
->
io_base
+
4
))
...
...
@@ -941,7 +941,7 @@ attach_ms_sound (long mem_start, struct address_info *hw_config)
if
((
INB
(
version_port
)
&
0x40
)
==
0
)
printk
(
"[IRQ?]"
);
OUTB
(
bits
|
hw_config
->
dma
,
config_port
);
/* Write IRQ+DMA setup */
OUTB
(
bits
|
dma_bits
[
hw_config
->
dma
]
,
config_port
);
/* Write IRQ+DMA setup */
ad1848_init
(
"MS Sound System"
,
hw_config
->
io_base
+
4
,
hw_config
->
irq
,
...
...
drivers/sound/configure.c
View file @
8151e895
...
...
@@ -322,6 +322,13 @@ main (int argc, char *argv[])
}
}
if
(
selected_options
&
B
(
OPT_SBPRO
))
{
fprintf
(
stderr
,
"Do you want support for the mixer of SG NX Pro ? "
);
if
(
think_positively
(
0
))
printf
(
"#define __SGNXPRO__
\n
"
);
}
if
(
selected_options
&
B
(
OPT_SB16
))
selected_options
|=
B
(
OPT_SBPRO
);
...
...
@@ -333,7 +340,7 @@ main (int argc, char *argv[])
"if you wish to emulate the soundblaster and you have a DSPxxx.LD.
\n
"
"then you must include the LD in the kernel.
\n
"
"(do you wish to include a LD) ? "
);
if
(
think_positively
(
1
))
if
(
think_positively
(
0
))
{
char
path
[
512
];
...
...
drivers/sound/dev_table.h
View file @
8151e895
...
...
@@ -278,6 +278,9 @@ struct sound_timer_operations {
#endif
#ifndef EXCLUDE_MSS
{
SNDCARD_MSS
,
{
MSS_BASE
,
MSS_IRQ
,
MSS_DMA
},
SND_DEFAULT_ENABLE
},
# ifdef MSS2_BASE
{
SNDCARD_MSS
,
{
MSS2_BASE
,
MSS2_IRQ
,
MSS2_DMA
},
SND_DEFAULT_ENABLE
},
# endif
#endif
#if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
...
...
drivers/sound/dmabuf.c
View file @
8151e895
...
...
@@ -320,7 +320,7 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len)
if
(
!
(
dmap
->
flags
&
DMA_ALLOC_DONE
))
reorganize_buffers
(
dev
);
if
(
dmap
->
dma_mode
)
if
(
!
dmap
->
dma_mode
)
{
int
err
;
...
...
drivers/sound/sb_dsp.c
View file @
8151e895
/*
* sound/sb_dsp.c
*
* The low level driver for the SoundBlaster DSP chip.
* The low level driver for the SoundBlaster DSP chip
(SB1.0 to 2.1, SB Pro)
.
*
* Copyright by Hannu Savolainen 199
3
* Copyright by Hannu Savolainen 199
4
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
...
...
@@ -25,6 +25,10 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Modified:
* Hunyue Yau Jan 6 1994
* Added code to support Sound Galaxy NX Pro
*
*/
#include "sound_config.h"
...
...
@@ -756,6 +760,7 @@ long
sb_dsp_init
(
long
mem_start
,
struct
address_info
*
hw_config
)
{
int
i
;
int
mixer_type
=
0
;
sbc_major
=
sbc_minor
=
0
;
sb_dsp_command
(
0xe1
);
/*
...
...
@@ -786,7 +791,7 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
#ifndef EXCLUDE_SBPRO
if
(
sbc_major
>=
3
)
sb_mixer_init
(
sbc_major
);
mixer_type
=
sb_mixer_init
(
sbc_major
);
#endif
#ifndef EXCLUDE_YM8312
...
...
@@ -799,7 +804,16 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
if
(
sbc_major
>=
3
)
{
#ifndef SCO
sprintf
(
sb_dsp_operations
.
name
,
"SoundBlaster Pro %d.%d"
,
sbc_major
,
sbc_minor
);
# ifdef __SGNXPRO__
if
(
mixer_type
==
2
)
{
sprintf
(
sb_dsp_operations
.
name
,
"Sound Galaxy NX Pro %d.%d"
,
sbc_major
,
sbc_minor
);
}
else
# endif
{
sprintf
(
sb_dsp_operations
.
name
,
"SoundBlaster Pro %d.%d"
,
sbc_major
,
sbc_minor
);
}
#endif
}
else
...
...
drivers/sound/sb_mixer.c
View file @
8151e895
...
...
@@ -4,7 +4,7 @@
*
* The low level mixer driver for the SoundBlaster Pro and SB16 cards.
*
* Copyright by Hannu Savolainen 199
3
* Copyright by Hannu Savolainen 199
4
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
...
...
@@ -26,6 +26,10 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Modified:
* Hunyue Yau Jan 6 1994
* Added code to support the Sound Galaxy NX Pro mixer.
*
*/
#include "sound_config.h"
...
...
@@ -91,9 +95,21 @@ sb_mixer_set_stereo (int mode)
|
(
mode
?
STEREO_DAC
:
MONO_DAC
)));
}
/*
* Returns:
* 0 No mixer detected.
* 1 Only a plain Sound Blaster Pro style mixer detected.
* 2 The Sound Galaxy NX Pro mixer detected.
*/
static
int
detect_mixer
(
void
)
{
#ifdef __SGNXPRO__
int
oldbass
,
oldtreble
;
#endif
int
retcode
=
1
;
/*
* Detect the mixer by changing parameters of two volume channels. If the
* values read back match with the values written, the mixer is there (is
...
...
@@ -109,7 +125,30 @@ detect_mixer (void)
if
(
sb_getmixer
(
VOC_VOL
)
!=
0x33
)
return
0
;
return
1
;
#ifdef __SGNXPRO__
/* Attempt to detect the SG NX Pro by check for valid bass/treble
* registers.
*/
oldbass
=
sb_getmixer
(
BASS_LVL
);
oldtreble
=
sb_getmixer
(
TREBLE_LVL
);
sb_setmixer
(
BASS_LVL
,
0xaa
);
sb_setmixer
(
TREBLE_LVL
,
0x55
);
if
((
sb_getmixer
(
BASS_LVL
)
!=
0xaa
)
||
(
sb_getmixer
(
TREBLE_LVL
)
!=
0x55
))
{
retcode
=
1
;
/* 1 == Only SB Pro detected */
}
else
retcode
=
2
;
/* 2 == SG NX Pro detected */
/* Restore register in either case since SG NX Pro has EEPROM with
* 'preferred' values stored.
*/
sb_setmixer
(
BASS_LVL
,
oldbass
);
sb_setmixer
(
TREBLE_LVL
,
oldtreble
);
#endif
return
retcode
;
}
static
void
...
...
@@ -350,17 +389,23 @@ sb_mixer_reset (void)
set_recmask
(
SOUND_MASK_MIC
);
}
void
/*
* Returns a code depending on whether a SG NX Pro was detected.
* 1 == Plain SB Pro
* 2 == SG NX Pro detected.
* 3 == SB16
*
* Used to update message.
*/
int
sb_mixer_init
(
int
major_model
)
{
sb_setmixer
(
0x00
,
0
);
/*
* Reset mixer
*/
int
mixer_type
=
0
;
if
(
!
detect_mixer
())
return
;
/*
* No mixer. Why?
*/
sb_setmixer
(
0x00
,
0
);
/* Reset mixer */
if
(
!
(
mixer_type
=
detect_mixer
()))
return
0
;
/* No mixer. Why?
*/
mixer_initialized
=
1
;
mixer_model
=
major_model
;
...
...
@@ -369,9 +414,21 @@ sb_mixer_init (int major_model)
{
case
3
:
mixer_caps
=
SOUND_CAP_EXCL_INPUT
;
supported_devices
=
SBPRO_MIXER_DEVICES
;
supported_rec_devices
=
SBPRO_RECORDING_DEVICES
;
iomap
=
&
sbpro_mix
;
#ifdef __SGNXPRO__
if
(
mixer_type
==
2
)
/* A SGNXPRO was detected */
{
supported_devices
=
SGNXPRO_MIXER_DEVICES
;
supported_rec_devices
=
SGNXPRO_RECORDING_DEVICES
;
iomap
=
&
sgnxpro_mix
;
}
else
#endif
{
supported_devices
=
SBPRO_MIXER_DEVICES
;
supported_rec_devices
=
SBPRO_RECORDING_DEVICES
;
iomap
=
&
sbpro_mix
;
mixer_type
=
1
;
}
break
;
case
4
:
...
...
@@ -379,16 +436,18 @@ sb_mixer_init (int major_model)
supported_devices
=
SB16_MIXER_DEVICES
;
supported_rec_devices
=
SB16_RECORDING_DEVICES
;
iomap
=
&
sb16_mix
;
mixer_type
=
3
;
break
;
default:
printk
(
"SB Warning: Unsupported mixer type
\n
"
);
return
;
return
0
;
}
if
(
num_mixers
<
MAX_MIXER_DEV
)
mixer_devs
[
num_mixers
++
]
=
&
sb_mixer_operations
;
sb_mixer_reset
();
return
mixer_type
;
}
#endif
drivers/sound/sb_mixer.h
View file @
8151e895
...
...
@@ -24,13 +24,29 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Modified:
* Hunyue Yau Jan 6 1994
* Added defines for the Sound Galaxy NX Pro mixer.
*
*/
#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
/* Same as SB Pro, unless I find otherwise */
#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD | SOUND_MASK_VOLUME)
/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
* channel is the COVOX/DisneySoundSource emulation volume control
* on the mixer. It does NOT control speaker volume. Should have own
* mask eventually?
*/
#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
SOUND_MASK_CD)
...
...
@@ -62,6 +78,13 @@
#define IRQ_STAT 0x82
#define OPSW 0x3c
/*
* Additional registers on the SG NX Pro
*/
#define COVOX_VOL 0x42
#define TREBLE_LVL 0x44
#define BASS_LVL 0x46
#define FREQ_HI (1 << 3)
/* Use High-frequency ANFI filters */
#define FREQ_LOW 0
/* Use Low-frequency ANFI filters */
#define FILT_ON 0
/* Yes, 0 to turn it on, 1 for off */
...
...
@@ -108,6 +131,23 @@ MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
MIX_ENT
(
SOUND_MIXER_RECLEV
,
0x00
,
0
,
0
,
0x00
,
0
,
0
)
};
#ifdef __SGNXPRO__
mixer_tab
sgnxpro_mix
=
{
MIX_ENT
(
SOUND_MIXER_VOLUME
,
0x22
,
7
,
4
,
0x22
,
3
,
4
),
MIX_ENT
(
SOUND_MIXER_BASS
,
0x46
,
2
,
3
,
0x00
,
0
,
0
),
MIX_ENT
(
SOUND_MIXER_TREBLE
,
0x44
,
2
,
3
,
0x00
,
0
,
0
),
MIX_ENT
(
SOUND_MIXER_SYNTH
,
0x26
,
7
,
4
,
0x26
,
3
,
4
),
MIX_ENT
(
SOUND_MIXER_PCM
,
0x04
,
7
,
4
,
0x04
,
3
,
4
),
MIX_ENT
(
SOUND_MIXER_SPEAKER
,
0x42
,
2
,
3
,
0x00
,
0
,
0
),
MIX_ENT
(
SOUND_MIXER_LINE
,
0x2e
,
7
,
4
,
0x2e
,
3
,
4
),
MIX_ENT
(
SOUND_MIXER_MIC
,
0x0a
,
2
,
3
,
0x00
,
0
,
0
),
MIX_ENT
(
SOUND_MIXER_CD
,
0x28
,
7
,
4
,
0x28
,
3
,
4
),
MIX_ENT
(
SOUND_MIXER_IMIX
,
0x00
,
0
,
0
,
0x00
,
0
,
0
),
MIX_ENT
(
SOUND_MIXER_ALTPCM
,
0x00
,
0
,
0
,
0x00
,
0
,
0
),
MIX_ENT
(
SOUND_MIXER_RECLEV
,
0x00
,
0
,
0
,
0x00
,
0
,
0
)
};
#endif
mixer_tab
sb16_mix
=
{
MIX_ENT
(
SOUND_MIXER_VOLUME
,
0x30
,
7
,
5
,
0x31
,
7
,
5
),
MIX_ENT
(
SOUND_MIXER_BASS
,
0x46
,
7
,
4
,
0x47
,
7
,
4
),
...
...
drivers/sound/sound_calls.h
View file @
8151e895
...
...
@@ -140,7 +140,7 @@ void sb_midi_init(int model);
void
sb_setmixer
(
unsigned
int
port
,
unsigned
int
value
);
int
sb_getmixer
(
unsigned
int
port
);
void
sb_mixer_set_stereo
(
int
mode
);
void
sb_mixer_init
(
int
major_model
);
int
sb_mixer_init
(
int
major_model
);
/* From opl3.c */
int
opl3_detect
(
int
ioaddr
);
...
...
drivers/sound/sound_config.h
View file @
8151e895
...
...
@@ -180,7 +180,7 @@ If your card has nonstandard I/O address or IRQ number, change defines
* In v3.0 it's /dev/sndproc but this could be a temporary solution.
*/
#define SND_NDEVS
64
/* Number of supported devices */
#define SND_NDEVS
256
/* Number of supported devices */
#define SND_DEV_CTL 0
/* Control port /dev/mixer */
#define SND_DEV_SEQ 1
/* Sequencer output /dev/sequencer (FM
synthesizer and MIDI output) */
...
...
@@ -199,7 +199,7 @@ If your card has nonstandard I/O address or IRQ number, change defines
#define ON 1
#define OFF 0
#define MAX_AUDIO_DEV
4
#define MAX_AUDIO_DEV
5
#define MAX_MIXER_DEV 2
#define MAX_SYNTH_DEV 3
#define MAX_MIDI_DEV 6
...
...
include/linux/hdreg.h
View file @
8151e895
...
...
@@ -42,6 +42,12 @@
#define WIN_DIAGNOSE 0x90
#define WIN_SPECIFY 0x91
#define WIN_MULTREAD 0xC4
/* read multiple sectors */
#define WIN_MULTWRITE 0xC5
/* write multiple sectors */
#define WIN_SETMULT 0xC6
/* enable read multiple */
#define WIN_IDENTIFY 0xEC
/* ask drive to identify itself */
#define WIN_SETFEATURES 0xEF
/* set special drive features */
/* Bits for HD_ERROR */
#define MARK_ERR 0x01
/* Bad address mark */
#define TRK0_ERR 0x02
/* couldn't find track 0 */
...
...
@@ -61,4 +67,9 @@ struct hd_geometry {
unsigned
short
cylinders
;
unsigned
long
start
;
};
#define HDIO_GETUNMASKINTR 0x302
#define HDIO_SETUNMASKINTR 0x303
#define HDIO_GETMULTCOUNT 0x304
#define HDIO_SETMULTCOUNT 0x305
#define HDIO_SETFEATURE 0x306
#endif
include/linux/mm.h
View file @
8151e895
...
...
@@ -145,10 +145,10 @@ extern int unmap_page_range(unsigned long from, unsigned long size);
extern
int
remap_page_range
(
unsigned
long
from
,
unsigned
long
to
,
unsigned
long
size
,
int
mask
);
extern
int
zeromap_page_range
(
unsigned
long
from
,
unsigned
long
size
,
int
mask
);
extern
void
do_wp_page
(
unsigned
long
error_code
,
unsigned
long
address
,
struct
task_struct
*
tsk
);
extern
void
do_no_page
(
unsigned
long
error_code
,
unsigned
long
address
,
struct
task_struct
*
tsk
);
extern
void
do_wp_page
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
error_code
);
extern
void
do_no_page
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
error_code
);
extern
unsigned
long
paging_init
(
unsigned
long
start_mem
,
unsigned
long
end_mem
);
extern
void
mem_init
(
unsigned
long
low_start_mem
,
...
...
include/linux/wait.h
View file @
8151e895
...
...
@@ -6,6 +6,8 @@
#define __WCLONE 0x80000000
#ifdef __KERNEL__
struct
wait_queue
{
struct
task_struct
*
task
;
struct
wait_queue
*
next
;
...
...
@@ -31,4 +33,6 @@ typedef struct select_table_struct {
#define __MAX_SELECT_TABLE_ENTRIES (4096 / sizeof (struct select_table_entry))
#endif
/* __KERNEL__ */
#endif
kernel/ptrace.c
View file @
8151e895
...
...
@@ -81,24 +81,20 @@ static inline int put_stack_long(struct task_struct *task, int offset,
* tables. NOTE! You should check that the long isn't on a page boundary,
* and that it is in the task area before calling this: this routine does
* no checking.
*
* NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
* zero. This routine shouldn't have to change when we make a better mm.
*/
static
unsigned
long
get_long
(
struct
task_struct
*
tsk
,
unsigned
long
addr
)
static
unsigned
long
get_long
(
struct
vm_area_struct
*
vma
,
unsigned
long
addr
)
{
unsigned
long
page
;
repeat:
page
=
*
PAGE_DIR_OFFSET
(
tsk
->
tss
.
cr3
,
addr
);
page
=
*
PAGE_DIR_OFFSET
(
vma
->
vm_task
->
tss
.
cr3
,
addr
);
if
(
page
&
PAGE_PRESENT
)
{
page
&=
PAGE_MASK
;
page
+=
PAGE_PTR
(
addr
);
page
=
*
((
unsigned
long
*
)
page
);
}
if
(
!
(
page
&
PAGE_PRESENT
))
{
do_no_page
(
0
,
addr
,
tsk
);
do_no_page
(
vma
,
addr
,
0
);
goto
repeat
;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
...
...
@@ -118,14 +114,14 @@ static unsigned long get_long(struct task_struct * tsk,
* Now keeps R/W state of page so that a text page stays readonly
* even if a debugger scribbles breakpoints into it. -M.U-
*/
static
void
put_long
(
struct
task_struct
*
tsk
,
unsigned
long
addr
,
static
void
put_long
(
struct
vm_area_struct
*
vma
,
unsigned
long
addr
,
unsigned
long
data
)
{
unsigned
long
page
,
pte
=
0
;
int
readonly
=
0
;
repeat:
page
=
*
PAGE_DIR_OFFSET
(
tsk
->
tss
.
cr3
,
addr
);
page
=
*
PAGE_DIR_OFFSET
(
vma
->
vm_task
->
tss
.
cr3
,
addr
);
if
(
page
&
PAGE_PRESENT
)
{
page
&=
PAGE_MASK
;
page
+=
PAGE_PTR
(
addr
);
...
...
@@ -133,13 +129,13 @@ static void put_long(struct task_struct * tsk, unsigned long addr,
page
=
*
((
unsigned
long
*
)
page
);
}
if
(
!
(
page
&
PAGE_PRESENT
))
{
do_no_page
(
0
/* PAGE_RW */
,
addr
,
tsk
);
do_no_page
(
vma
,
addr
,
0
/* PAGE_RW */
);
goto
repeat
;
}
if
(
!
(
page
&
PAGE_RW
))
{
if
(
!
(
page
&
PAGE_COW
))
if
(
!
(
page
&
PAGE_COW
))
readonly
=
1
;
do_wp_page
(
PAGE_RW
|
PAGE_PRESENT
,
addr
,
tsk
);
do_wp_page
(
vma
,
addr
,
PAGE_RW
|
PAGE_PRESENT
);
goto
repeat
;
}
/* this is a hack for non-kernel-mapped video buffers and similar */
...
...
@@ -150,12 +146,34 @@ static void put_long(struct task_struct * tsk, unsigned long addr,
page
&=
PAGE_MASK
;
page
+=
addr
&
~
PAGE_MASK
;
*
(
unsigned
long
*
)
page
=
data
;
if
(
readonly
)
{
if
(
readonly
)
{
*
(
unsigned
long
*
)
pte
&=~
(
PAGE_RW
|
PAGE_COW
);
invalidate
();
}
}
static
struct
vm_area_struct
*
find_vma
(
struct
task_struct
*
tsk
,
unsigned
long
addr
)
{
struct
vm_area_struct
*
vma
;
addr
&=
PAGE_MASK
;
for
(
vma
=
current
->
mm
->
mmap
;
;
vma
=
vma
->
vm_next
)
{
if
(
!
vma
)
return
NULL
;
if
(
vma
->
vm_end
>
addr
)
break
;
}
if
(
vma
->
vm_start
<=
addr
)
return
vma
;
if
(
!
(
vma
->
vm_flags
&
VM_GROWSDOWN
))
return
NULL
;
if
(
vma
->
vm_end
-
addr
>
tsk
->
rlim
[
RLIMIT_STACK
].
rlim_cur
)
return
NULL
;
vma
->
vm_offset
-=
vma
->
vm_start
-
addr
;
vma
->
vm_start
=
addr
;
return
vma
;
}
/*
* This routine checks the page boundaries, and that the offset is
* within the task area. It then calls get_long() to read a long.
...
...
@@ -163,13 +181,21 @@ static void put_long(struct task_struct * tsk, unsigned long addr,
static
int
read_long
(
struct
task_struct
*
tsk
,
unsigned
long
addr
,
unsigned
long
*
result
)
{
unsigned
long
low
,
high
;
struct
vm_area_struct
*
vma
=
find_vma
(
tsk
,
addr
)
;
if
(
addr
>
TASK_SIZE
-
sizeof
(
long
)
)
if
(
!
vma
)
return
-
EIO
;
if
((
addr
&
~
PAGE_MASK
)
>
PAGE_SIZE
-
sizeof
(
long
))
{
low
=
get_long
(
tsk
,
addr
&
~
(
sizeof
(
long
)
-
1
));
high
=
get_long
(
tsk
,(
addr
+
sizeof
(
long
))
&
~
(
sizeof
(
long
)
-
1
));
unsigned
long
low
,
high
;
struct
vm_area_struct
*
vma_high
=
vma
;
if
(
addr
+
sizeof
(
long
)
>=
vma
->
vm_end
)
{
vma_high
=
vma
->
vm_next
;
if
(
!
vma_high
||
vma_high
->
vm_start
!=
vma
->
vm_end
)
return
-
EIO
;
}
low
=
get_long
(
vma
,
addr
&
~
(
sizeof
(
long
)
-
1
));
high
=
get_long
(
vma_high
,
(
addr
+
sizeof
(
long
))
&
~
(
sizeof
(
long
)
-
1
));
switch
(
addr
&
(
sizeof
(
long
)
-
1
))
{
case
1
:
low
>>=
8
;
...
...
@@ -186,7 +212,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
}
*
result
=
low
;
}
else
*
result
=
get_long
(
tsk
,
addr
);
*
result
=
get_long
(
vma
,
addr
);
return
0
;
}
...
...
@@ -197,13 +223,21 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
static
int
write_long
(
struct
task_struct
*
tsk
,
unsigned
long
addr
,
unsigned
long
data
)
{
unsigned
long
low
,
high
;
struct
vm_area_struct
*
vma
=
find_vma
(
tsk
,
addr
)
;
if
(
addr
>
TASK_SIZE
-
sizeof
(
long
)
)
if
(
!
vma
)
return
-
EIO
;
if
((
addr
&
~
PAGE_MASK
)
>
PAGE_SIZE
-
sizeof
(
long
))
{
low
=
get_long
(
tsk
,
addr
&
~
(
sizeof
(
long
)
-
1
));
high
=
get_long
(
tsk
,(
addr
+
sizeof
(
long
))
&
~
(
sizeof
(
long
)
-
1
));
unsigned
long
low
,
high
;
struct
vm_area_struct
*
vma_high
=
vma
;
if
(
addr
+
sizeof
(
long
)
>=
vma
->
vm_end
)
{
vma_high
=
vma
->
vm_next
;
if
(
!
vma_high
||
vma_high
->
vm_start
!=
vma
->
vm_end
)
return
-
EIO
;
}
low
=
get_long
(
vma
,
addr
&
~
(
sizeof
(
long
)
-
1
));
high
=
get_long
(
vma_high
,
(
addr
+
sizeof
(
long
))
&
~
(
sizeof
(
long
)
-
1
));
switch
(
addr
&
(
sizeof
(
long
)
-
1
))
{
case
0
:
/* shouldn't happen, but safety first */
low
=
data
;
...
...
@@ -227,10 +261,10 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
high
|=
data
>>
8
;
break
;
}
put_long
(
tsk
,
addr
&
~
(
sizeof
(
long
)
-
1
),
low
);
put_long
(
tsk
,
(
addr
+
sizeof
(
long
))
&
~
(
sizeof
(
long
)
-
1
),
high
);
put_long
(
vma
,
addr
&
~
(
sizeof
(
long
)
-
1
),
low
);
put_long
(
vma_high
,
(
addr
+
sizeof
(
long
))
&
~
(
sizeof
(
long
)
-
1
),
high
);
}
else
put_long
(
tsk
,
addr
,
data
);
put_long
(
vma
,
addr
,
data
);
return
0
;
}
...
...
kernel/sched.c
View file @
8151e895
...
...
@@ -148,7 +148,6 @@ asmlinkage void math_emulate(long arg)
unsigned
long
itimer_ticks
=
0
;
unsigned
long
itimer_next
=
~
0
;
static
unsigned
long
lost_ticks
=
0
;
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
...
...
@@ -361,54 +360,76 @@ void sleep_on(struct wait_queue **p)
__sleep_on
(
p
,
TASK_UNINTERRUPTIBLE
);
}
static
struct
timer_list
*
next_timer
=
NULL
;
/*
* The head for the timer-list has a "expires" field of MAX_UINT,
* and the sorting routine counts on this..
*/
static
struct
timer_list
timer_head
=
{
&
timer_head
,
&
timer_head
,
~
0
,
0
,
NULL
};
#define SLOW_BUT_DEBUGGING_TIMERS 1
void
add_timer
(
struct
timer_list
*
timer
)
{
unsigned
long
flags
;
struct
timer_list
*
*
p
;
struct
timer_list
*
p
;
if
(
!
timer
)
#if SLOW_BUT_DEBUGGING_TIMERS
if
(
timer
->
next
||
timer
->
prev
)
{
printk
(
"add_timer() called with non-zero list from %08lx
\n
"
,
((
unsigned
long
*
)
&
timer
)[
-
1
]);
return
;
timer
->
next
=
NULL
;
p
=
&
next_timer
;
}
#endif
p
=
&
timer_head
;
timer
->
expires
+=
jiffies
;
save_flags
(
flags
);
cli
();
while
(
*
p
)
{
if
((
*
p
)
->
expires
>
timer
->
expires
)
{
(
*
p
)
->
expires
-=
timer
->
expires
;
timer
->
next
=
*
p
;
break
;
}
timer
->
expires
-=
(
*
p
)
->
expires
;
p
=
&
(
*
p
)
->
next
;
}
*
p
=
timer
;
do
{
p
=
p
->
next
;
}
while
(
timer
->
expires
>
p
->
expires
);
timer
->
next
=
p
;
timer
->
prev
=
p
->
prev
;
p
->
prev
=
timer
;
timer
->
prev
->
next
=
timer
;
restore_flags
(
flags
);
}
int
del_timer
(
struct
timer_list
*
timer
)
{
unsigned
long
flags
;
unsigned
long
expires
=
0
;
struct
timer_list
*
*
p
;
#if SLOW_BUT_DEBUGGING_TIMERS
struct
timer_list
*
p
;
p
=
&
next_timer
;
p
=
&
timer_head
;
save_flags
(
flags
);
cli
();
while
(
*
p
)
{
if
(
*
p
==
timer
)
{
if
((
*
p
=
timer
->
next
)
!=
NULL
)
(
*
p
)
->
expires
+=
timer
->
expires
;
timer
->
expires
+=
expires
;
while
(
(
p
=
p
->
next
)
!=
&
timer_head
)
{
if
(
p
==
timer
)
{
timer
->
next
->
prev
=
timer
->
prev
;
timer
->
prev
->
next
=
timer
->
next
;
timer
->
next
=
timer
->
prev
=
NULL
;
restore_flags
(
flags
);
timer
->
expires
-=
jiffies
;
return
1
;
}
expires
+=
(
*
p
)
->
expires
;
p
=
&
(
*
p
)
->
next
;
}
if
(
p
->
next
||
p
->
prev
)
printk
(
"del_timer() called with timer not initialized
\n
"
);
restore_flags
(
flags
);
return
0
;
#else
save_flags
(
flags
);
cli
();
if
(
timer
->
next
)
{
timer
->
next
->
prev
=
timer
->
prev
;
timer
->
prev
->
next
=
timer
->
next
;
timer
->
next
=
timer
->
prev
=
NULL
;
restore_flags
(
flags
);
timer
->
expires
-=
jiffies
;
return
1
;
}
restore_flags
(
flags
);
return
0
;
#endif
}
unsigned
long
timer_active
=
0
;
...
...
@@ -528,12 +549,15 @@ static void timer_bh(void * unused)
{
unsigned
long
mask
;
struct
timer_struct
*
tp
;
struct
timer_list
*
timer
;
cli
();
while
(
next_timer
&&
next_timer
->
expires
==
0
)
{
void
(
*
fn
)(
unsigned
long
)
=
next_timer
->
function
;
unsigned
long
data
=
next_timer
->
data
;
next_timer
=
next_timer
->
next
;
while
((
timer
=
timer_head
.
next
)
!=
&
timer_head
&&
timer
->
expires
<
jiffies
)
{
void
(
*
fn
)(
unsigned
long
)
=
timer
->
function
;
unsigned
long
data
=
timer
->
data
;
timer
->
next
->
prev
=
timer
->
prev
;
timer
->
prev
->
next
=
timer
->
next
;
timer
->
next
=
timer
->
prev
=
NULL
;
sti
();
fn
(
data
);
cli
();
...
...
@@ -667,16 +691,8 @@ static void do_timer(struct pt_regs * regs)
itimer_ticks
++
;
if
(
itimer_ticks
>
itimer_next
)
need_resched
=
1
;
if
(
next_timer
)
{
if
(
next_timer
->
expires
)
{
next_timer
->
expires
--
;
if
(
!
next_timer
->
expires
)
mark_bh
(
TIMER_BH
);
}
else
{
lost_ticks
++
;
mark_bh
(
TIMER_BH
);
}
}
if
(
timer_head
.
next
->
expires
<
jiffies
)
mark_bh
(
TIMER_BH
);
if
(
tq_timer
!=
&
tq_last
)
mark_bh
(
TQUEUE_BH
);
sti
();
...
...
mm/memory.c
View file @
8151e895
...
...
@@ -554,20 +554,17 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
* to a shared page. It is done by copying the page to a new address
* and decrementing the shared-page counter for the old page.
*
* Note that we do many checks twice (look at do_wp_page()), as
* we have to be careful about race-conditions.
*
* Goto-purists beware: the only reason for goto's here is that it results
* in better assembly code.. The "default" path will see no jumps at all.
*/
static
void
__do_wp_page
(
unsigned
long
error_code
,
unsigned
long
address
,
struct
task_struct
*
tsk
)
void
do_wp_page
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
error_code
)
{
unsigned
long
*
pde
,
pte
,
old_page
,
prot
;
unsigned
long
new_page
;
new_page
=
__get_free_page
(
GFP_KERNEL
);
pde
=
PAGE_DIR_OFFSET
(
t
sk
->
tss
.
cr3
,
address
);
pde
=
PAGE_DIR_OFFSET
(
vma
->
vm_ta
sk
->
tss
.
cr3
,
address
);
pte
=
*
pde
;
if
(
!
(
pte
&
PAGE_PRESENT
))
goto
end_wp_page
;
...
...
@@ -582,13 +579,13 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
goto
bad_wp_page
;
if
(
old_page
&
PAGE_RW
)
goto
end_wp_page
;
t
sk
->
mm
->
min_flt
++
;
vma
->
vm_ta
sk
->
mm
->
min_flt
++
;
prot
=
(
old_page
&
~
PAGE_MASK
)
|
PAGE_RW
;
old_page
&=
PAGE_MASK
;
if
(
mem_map
[
MAP_NR
(
old_page
)]
!=
1
)
{
if
(
new_page
)
{
if
(
mem_map
[
MAP_NR
(
old_page
)]
&
MAP_PAGE_RESERVED
)
++
t
sk
->
mm
->
rss
;
++
vma
->
vm_ta
sk
->
mm
->
rss
;
copy_page
(
old_page
,
new_page
);
*
(
unsigned
long
*
)
pte
=
new_page
|
prot
;
free_page
(
old_page
);
...
...
@@ -596,7 +593,7 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
return
;
}
free_page
(
old_page
);
oom
(
t
sk
);
oom
(
vma
->
vm_ta
sk
);
*
(
unsigned
long
*
)
pte
=
BAD_PAGE
|
prot
;
invalidate
();
return
;
...
...
@@ -609,12 +606,12 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
bad_wp_page:
printk
(
"do_wp_page: bogus page at address %08lx (%08lx)
\n
"
,
address
,
old_page
);
*
(
unsigned
long
*
)
pte
=
BAD_PAGE
|
PAGE_SHARED
;
send_sig
(
SIGKILL
,
t
sk
,
1
);
send_sig
(
SIGKILL
,
vma
->
vm_ta
sk
,
1
);
goto
end_wp_page
;
bad_wp_pagetable:
printk
(
"do_wp_page: bogus page-table at address %08lx (%08lx)
\n
"
,
address
,
pte
);
*
pde
=
BAD_PAGETABLE
|
PAGE_TABLE
;
send_sig
(
SIGKILL
,
t
sk
,
1
);
send_sig
(
SIGKILL
,
vma
->
vm_ta
sk
,
1
);
end_wp_page:
if
(
new_page
)
free_page
(
new_page
);
...
...
@@ -622,63 +619,12 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
}
/*
* check that a page table change is actually needed, and call
* the low-level function only in that case..
* Ugly, ugly, but the goto's result in better assembly..
*/
void
do_wp_page
(
unsigned
long
error_code
,
unsigned
long
address
,
struct
task_struct
*
tsk
)
{
unsigned
long
page
;
unsigned
long
*
pg_table
;
pg_table
=
PAGE_DIR_OFFSET
(
tsk
->
tss
.
cr3
,
address
);
page
=
*
pg_table
;
if
(
!
page
)
return
;
if
((
page
&
PAGE_PRESENT
)
&&
page
<
high_memory
)
{
pg_table
=
(
unsigned
long
*
)
((
page
&
PAGE_MASK
)
+
PAGE_PTR
(
address
));
page
=
*
pg_table
;
if
(
!
(
page
&
PAGE_PRESENT
))
return
;
if
(
page
&
PAGE_RW
)
return
;
if
(
!
(
page
&
PAGE_COW
))
{
if
((
error_code
&
PAGE_USER
)
&&
tsk
==
current
)
{
current
->
tss
.
cr2
=
address
;
current
->
tss
.
error_code
=
error_code
;
current
->
tss
.
trap_no
=
14
;
send_sig
(
SIGSEGV
,
tsk
,
1
);
return
;
}
}
if
(
mem_map
[
MAP_NR
(
page
)]
==
1
)
{
*
pg_table
|=
PAGE_RW
|
PAGE_DIRTY
;
invalidate
();
return
;
}
__do_wp_page
(
error_code
,
address
,
tsk
);
return
;
}
printk
(
"bad page directory entry %08lx
\n
"
,
page
);
*
pg_table
=
0
;
}
static
int
__verify_write
(
unsigned
long
start
,
unsigned
long
size
)
{
size
--
;
size
+=
start
&
~
PAGE_MASK
;
size
>>=
PAGE_SHIFT
;
start
&=
PAGE_MASK
;
do
{
do_wp_page
(
1
,
start
,
current
);
start
+=
PAGE_SIZE
;
}
while
(
size
--
);
return
0
;
}
int
verify_area
(
int
type
,
const
void
*
addr
,
unsigned
long
size
)
{
struct
vm_area_struct
*
vma
;
unsigned
long
start
=
(
unsigned
long
)
addr
;
/* If the current user space is mapped to kernel space (for the
* case where we use a fake user buffer with get_fs/set_fs()) we
...
...
@@ -690,27 +636,52 @@ int verify_area(int type, const void * addr, unsigned long size)
for
(
vma
=
current
->
mm
->
mmap
;
;
vma
=
vma
->
vm_next
)
{
if
(
!
vma
)
goto
bad_area
;
if
(
vma
->
vm_end
>
(
unsigned
long
)
addr
)
if
(
vma
->
vm_end
>
start
)
break
;
}
if
(
vma
->
vm_start
<=
(
unsigned
long
)
addr
)
if
(
vma
->
vm_start
<=
start
)
goto
good_area
;
if
(
!
(
vma
->
vm_flags
&
VM_GROWSDOWN
))
goto
bad_area
;
if
(
vma
->
vm_end
-
(
unsigned
long
)
addr
>
current
->
rlim
[
RLIMIT_STACK
].
rlim_cur
)
if
(
vma
->
vm_end
-
start
>
current
->
rlim
[
RLIMIT_STACK
].
rlim_cur
)
goto
bad_area
;
good_area:
while
(
vma
->
vm_end
-
(
unsigned
long
)
addr
<
size
)
{
struct
vm_area_struct
*
next
=
vma
->
vm_next
;
if
(
!
next
)
if
(
!
wp_works_ok
&&
type
==
VERIFY_WRITE
)
goto
check_wp_fault_by_hand
;
for
(;;)
{
struct
vm_area_struct
*
next
;
if
(
type
!=
VERIFY_READ
&&
!
(
vma
->
vm_page_prot
&
(
PAGE_COW
|
PAGE_RW
)))
goto
bad_area
;
if
(
vma
->
vm_end
!=
next
->
vm_start
)
if
(
vma
->
vm_end
-
start
>=
size
)
return
0
;
next
=
vma
->
vm_next
;
if
(
!
next
||
vma
->
vm_end
!=
next
->
vm_start
)
goto
bad_area
;
vma
=
next
;
}
if
(
wp_works_ok
||
type
==
VERIFY_READ
||
!
size
)
return
0
;
return
__verify_write
((
unsigned
long
)
addr
,
size
);
check_wp_fault_by_hand:
size
--
;
size
+=
start
&
~
PAGE_MASK
;
size
>>=
PAGE_SHIFT
;
start
&=
PAGE_MASK
;
for
(;;)
{
if
(
!
(
vma
->
vm_page_prot
&
(
PAGE_COW
|
PAGE_RW
)))
goto
bad_area
;
do_wp_page
(
vma
,
start
,
PAGE_PRESENT
);
if
(
!
size
)
return
0
;
size
--
;
start
+=
PAGE_SIZE
;
if
(
start
<
vma
->
vm_end
)
continue
;
vma
=
vma
->
vm_next
;
if
(
!
vma
||
vma
->
vm_start
!=
start
)
break
;
}
bad_area:
return
-
EFAULT
;
}
...
...
@@ -885,12 +856,33 @@ static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned
return
0
;
}
static
void
handle_no_page
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
error_code
)
void
do_no_page
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
unsigned
long
error_code
)
{
unsigned
long
page
;
int
prot
;
unsigned
long
page
,
entry
,
prot
;
page
=
get_empty_pgtable
(
vma
->
vm_task
,
address
);
if
(
!
page
)
return
;
page
&=
PAGE_MASK
;
page
+=
PAGE_PTR
(
address
);
entry
=
*
(
unsigned
long
*
)
page
;
if
(
entry
&
PAGE_PRESENT
)
return
;
if
(
entry
)
{
++
vma
->
vm_task
->
mm
->
rss
;
++
vma
->
vm_task
->
mm
->
maj_flt
;
swap_in
((
unsigned
long
*
)
page
);
return
;
}
address
&=
PAGE_MASK
;
if
(
!
vma
->
vm_ops
||
!
vma
->
vm_ops
->
nopage
)
{
++
vma
->
vm_task
->
mm
->
rss
;
++
vma
->
vm_task
->
mm
->
min_flt
;
get_empty_page
(
vma
->
vm_task
,
address
);
return
;
}
page
=
get_free_page
(
GFP_KERNEL
);
if
(
share_page
(
vma
,
address
,
error_code
,
page
))
{
++
vma
->
vm_task
->
mm
->
min_flt
;
...
...
@@ -904,8 +896,10 @@ static void handle_no_page(struct vm_area_struct * vma,
++
vma
->
vm_task
->
mm
->
maj_flt
;
++
vma
->
vm_task
->
mm
->
rss
;
page
=
vma
->
vm_ops
->
nopage
(
vma
,
address
,
page
,
error_code
);
if
(
share_page
(
vma
,
address
,
error_code
,
0
))
if
(
share_page
(
vma
,
address
,
error_code
,
0
))
{
free_page
(
page
);
return
;
}
prot
=
vma
->
vm_page_prot
;
if
((
prot
&
PAGE_COW
)
&&
mem_map
[
MAP_NR
(
page
)]
>
1
)
prot
&=
~
PAGE_RW
;
...
...
@@ -915,28 +909,20 @@ static void handle_no_page(struct vm_area_struct * vma,
oom
(
current
);
}
void
do_no_page
(
unsigned
long
error_code
,
unsigned
long
address
,
struct
task_struct
*
tsk
)
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
*/
asmlinkage
void
do_page_fault
(
struct
pt_regs
*
regs
,
unsigned
long
error_code
)
{
unsigned
long
page
,
tmp
;
struct
vm_area_struct
*
vma
;
unsigned
long
address
;
unsigned
long
page
;
page
=
get_empty_pgtable
(
tsk
,
address
);
if
(
!
page
)
return
;
page
&=
PAGE_MASK
;
page
+=
PAGE_PTR
(
address
);
tmp
=
*
(
unsigned
long
*
)
page
;
if
(
tmp
&
PAGE_PRESENT
)
return
;
if
(
tmp
)
{
++
tsk
->
mm
->
rss
;
++
tsk
->
mm
->
maj_flt
;
swap_in
((
unsigned
long
*
)
page
);
return
;
}
address
&=
PAGE_MASK
;
for
(
vma
=
tsk
->
mm
->
mmap
;
;
vma
=
vma
->
vm_next
)
{
/* get the address */
__asm__
(
"movl %%cr2,%0"
:
"=r"
(
address
));
for
(
vma
=
current
->
mm
->
mmap
;
;
vma
=
vma
->
vm_next
)
{
if
(
!
vma
)
goto
bad_area
;
if
(
vma
->
vm_end
>
address
)
...
...
@@ -946,81 +932,63 @@ void do_no_page(unsigned long error_code, unsigned long address,
goto
good_area
;
if
(
!
(
vma
->
vm_flags
&
VM_GROWSDOWN
))
goto
bad_area
;
if
(
vma
->
vm_end
-
address
>
tsk
->
rlim
[
RLIMIT_STACK
].
rlim_cur
)
if
(
vma
->
vm_end
-
address
>
current
->
rlim
[
RLIMIT_STACK
].
rlim_cur
)
goto
bad_area
;
vma
->
vm_offset
-=
vma
->
vm_start
-
address
;
vma
->
vm_start
=
address
;
vma
->
vm_offset
-=
vma
->
vm_start
-
(
address
&
PAGE_MASK
);
vma
->
vm_start
=
(
address
&
PAGE_MASK
);
/*
* Ok, we have a good vm_area for this memory access, so
* we can handle it..
*/
good_area:
if
(
!
vma
->
vm_ops
||
!
vma
->
vm_ops
->
nopage
)
{
++
tsk
->
mm
->
rss
;
++
tsk
->
mm
->
min_flt
;
get_empty_page
(
tsk
,
address
);
if
(
regs
->
eflags
&
VM_MASK
)
{
unsigned
long
bit
=
(
address
-
0xA0000
)
>>
PAGE_SHIFT
;
if
(
bit
<
32
)
current
->
screen_bitmap
|=
1
<<
bit
;
}
if
(
error_code
&
PAGE_PRESENT
)
{
if
((
vma
->
vm_page_prot
&
(
PAGE_RW
|
PAGE_COW
|
PAGE_PRESENT
))
==
PAGE_PRESENT
)
goto
bad_area
;
#ifdef CONFIG_TEST_VERIFY_AREA
if
(
regs
->
cs
==
KERNEL_CS
)
printk
(
"WP fault at %08x
\n
"
,
regs
->
eip
);
#endif
do_wp_page
(
vma
,
address
,
error_code
);
return
;
}
handle_no_page
(
vma
,
address
,
error_code
);
if
(
!
(
vma
->
vm_page_prot
&
PAGE_PRESENT
))
goto
bad_area
;
do_no_page
(
vma
,
address
,
error_code
);
return
;
bad_area:
if
(
tsk
!=
current
)
goto
kernel_needs_bad_page
;
tsk
->
tss
.
cr2
=
address
;
tsk
->
tss
.
error_code
=
error_code
;
tsk
->
tss
.
trap_no
=
14
;
send_sig
(
SIGSEGV
,
tsk
,
1
);
if
(
error_code
&
4
)
/* user level access? */
return
;
kernel_needs_bad_page:
++
tsk
->
mm
->
rss
;
++
tsk
->
mm
->
min_flt
;
get_empty_page
(
tsk
,
address
);
}
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
* routines.
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
asmlinkage
void
do_page_fault
(
struct
pt_regs
*
regs
,
unsigned
long
error_code
)
{
unsigned
long
address
;
unsigned
long
page
;
unsigned
int
bit
;
/* get the address */
__asm__
(
"movl %%cr2,%0"
:
"=r"
(
address
));
if
(
address
<
TASK_SIZE
)
{
if
(
regs
->
eflags
&
VM_MASK
)
{
bit
=
(
address
-
0xA0000
)
>>
PAGE_SHIFT
;
if
(
bit
<
32
)
current
->
screen_bitmap
|=
1
<<
bit
;
}
if
(
error_code
&
PAGE_PRESENT
)
{
#ifdef CONFIG_TEST_VERIFY_AREA
if
(
regs
->
cs
==
KERNEL_CS
)
printk
(
"WP fault at %08x
\n
"
,
regs
->
eip
);
#endif
do_wp_page
(
error_code
,
address
,
current
);
}
else
{
do_no_page
(
error_code
,
address
,
current
);
}
bad_area:
if
(
error_code
&
PAGE_USER
)
{
current
->
tss
.
cr2
=
address
;
current
->
tss
.
error_code
=
error_code
;
current
->
tss
.
trap_no
=
14
;
send_sig
(
SIGSEGV
,
current
,
1
);
return
;
}
address
-=
TASK_SIZE
;
if
(
wp_works_ok
<
0
&&
address
==
0
&&
(
error_code
&
PAGE_PRESENT
))
{
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
if
(
wp_works_ok
<
0
&&
address
==
TASK_SIZE
&&
(
error_code
&
PAGE_PRESENT
))
{
wp_works_ok
=
1
;
pg0
[
0
]
=
PAGE_SHARED
;
printk
(
"This processor honours the WP bit even when in supervisor mode. Good.
\n
"
);
return
;
}
if
(
address
<
PAGE_SIZE
)
{
if
(
(
unsigned
long
)
(
address
-
TASK_SIZE
)
<
PAGE_SIZE
)
{
printk
(
KERN_ALERT
"Unable to handle kernel NULL pointer dereference"
);
pg0
[
0
]
=
PAGE_SHARED
;
}
else
printk
(
KERN_ALERT
"Unable to handle kernel paging request"
);
printk
(
" at kernel address %08lx
\n
"
,
address
);
address
+=
TASK_SIZE
;
printk
(
" at virtual address %08lx
\n
"
,
address
);
__asm__
(
"movl %%cr3,%0"
:
"=r"
(
page
));
printk
(
KERN_ALERT
"current->tss.cr3 = %08lx, %%cr3 = %08lx
\n
"
,
current
->
tss
.
cr3
,
page
);
...
...
net/inet/af_inet.c
View file @
8151e895
...
...
@@ -615,6 +615,7 @@ static int inet_create(struct socket *sock, int protocol)
sk
->
timeout
=
0
;
sk
->
broadcast
=
0
;
sk
->
localroute
=
0
;
sk
->
timer
.
next
=
sk
->
timer
.
prev
=
NULL
;
sk
->
timer
.
data
=
(
unsigned
long
)
sk
;
sk
->
timer
.
function
=
&
net_timer
;
skb_queue_head_init
(
&
sk
->
back_log
);
...
...
net/inet/arp.c
View file @
8151e895
...
...
@@ -752,7 +752,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
skb_queue_head_init
(
&
entry
->
skb
);
entry
->
next
=
arp_tables
[
hash
];
arp_tables
[
hash
]
=
entry
;
entry
->
timer
.
next
=
entry
->
timer
.
prev
=
NULL
;
sti
();
}
...
...
@@ -841,6 +841,7 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
entry
->
next
=
arp_tables
[
hash
];
entry
->
dev
=
dev
;
arp_tables
[
hash
]
=
entry
;
entry
->
timer
.
next
=
entry
->
timer
.
prev
=
NULL
;
entry
->
timer
.
function
=
arp_expire_request
;
entry
->
timer
.
data
=
(
unsigned
long
)
entry
;
entry
->
timer
.
expires
=
ARP_RES_TIME
;
...
...
@@ -1048,6 +1049,7 @@ static int arp_req_set(struct arpreq *req)
entry
->
hlen
=
hlen
;
entry
->
htype
=
htype
;
entry
->
next
=
arp_tables
[
hash
];
entry
->
timer
.
next
=
entry
->
timer
.
prev
=
NULL
;
arp_tables
[
hash
]
=
entry
;
skb_queue_head_init
(
&
entry
->
skb
);
}
...
...
net/inet/dev.c
View file @
8151e895
...
...
@@ -336,6 +336,8 @@ int dev_close(struct device *dev)
void
dev_queue_xmit
(
struct
sk_buff
*
skb
,
struct
device
*
dev
,
int
pri
)
{
unsigned
long
flags
;
int
nitcount
;
struct
packet_type
*
ptype
;
int
where
=
0
;
/* used to say if the packet should go */
/* at the front or the back of the */
/* queue - front is a retranmsit try */
...
...
@@ -419,6 +421,17 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
}
restore_flags
(
flags
);
/* copy outgoing packets to any sniffer packet handlers */
for
(
nitcount
=
dev_nit
,
ptype
=
ptype_base
;
nitcount
>
0
&&
ptype
!=
NULL
;
ptype
=
ptype
->
next
)
{
if
(
ptype
->
type
==
htons
(
ETH_P_ALL
))
{
struct
sk_buff
*
skb2
;
if
((
skb2
=
skb_clone
(
skb
,
GFP_ATOMIC
))
==
NULL
)
break
;
ptype
->
func
(
skb2
,
skb
->
dev
,
ptype
);
nitcount
--
;
}
}
if
(
dev
->
hard_start_xmit
(
skb
,
dev
)
==
0
)
{
/*
* Packet is now solely the responsibility of the driver
...
...
net/inet/tcp.c
View file @
8151e895
...
...
@@ -681,8 +681,7 @@ struct sk_buff * tcp_dequeue_partial(struct sock * sk)
save_flags
(
flags
);
cli
();
skb
=
sk
->
partial
;
if
(
skb
)
{
if
(
skb
)
{
sk
->
partial
=
NULL
;
del_timer
(
&
sk
->
partial_timer
);
}
...
...
@@ -711,6 +710,7 @@ void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk)
if
(
tmp
)
del_timer
(
&
sk
->
partial_timer
);
sk
->
partial
=
skb
;
sk
->
partial_timer
.
next
=
sk
->
partial_timer
.
prev
=
NULL
;
sk
->
partial_timer
.
expires
=
HZ
;
sk
->
partial_timer
.
function
=
(
void
(
*
)(
unsigned
long
))
tcp_send_partial
;
sk
->
partial_timer
.
data
=
(
unsigned
long
)
sk
;
...
...
@@ -1987,6 +1987,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk
->
urg_data
=
0
;
newsk
->
retransmits
=
0
;
newsk
->
destroy
=
0
;
newsk
->
timer
.
next
=
newsk
->
timer
.
prev
=
NULL
;
newsk
->
timer
.
data
=
(
unsigned
long
)
newsk
;
newsk
->
timer
.
function
=
&
net_timer
;
newsk
->
dummy_th
.
source
=
skb
->
h
.
th
->
dest
;
...
...
@@ -2217,6 +2218,15 @@ static void tcp_close(struct sock *sk, int timeout)
* XXX if retransmit count reaches limit, is tcp_close()
* called with timeout == 1 ? if not, we need to fix that.
*/
if
(
!
timeout
)
{
int
timer_active
;
timer_active
=
del_timer
(
&
sk
->
timer
);
if
(
timer_active
)
add_timer
(
&
sk
->
timer
);
else
reset_timer
(
sk
,
TIME_CLOSE
,
4
*
sk
->
rto
);
}
#ifdef NOTDEF
/*
* Start a timer.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment