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
Kirill Smelkov
linux
Commits
55415e93
Commit
55415e93
authored
Nov 23, 2007
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import 1.1.91
parent
40820e9a
Changes
55
Hide whitespace changes
Inline
Side-by-side
Showing
55 changed files
with
2881 additions
and
764 deletions
+2881
-764
CREDITS
CREDITS
+5
-0
Makefile
Makefile
+1
-1
arch/alpha/kernel/process.c
arch/alpha/kernel/process.c
+0
-9
arch/i386/config.in
arch/i386/config.in
+4
-4
arch/i386/kernel/process.c
arch/i386/kernel/process.c
+0
-11
drivers/block/Makefile
drivers/block/Makefile
+5
-0
drivers/block/README.fd
drivers/block/README.fd
+1
-1
drivers/block/README.sonycd535
drivers/block/README.sonycd535
+110
-0
drivers/block/blk.h
drivers/block/blk.h
+12
-0
drivers/block/floppy.c
drivers/block/floppy.c
+2
-2
drivers/block/ll_rw_blk.c
drivers/block/ll_rw_blk.c
+18
-0
drivers/block/sonycd535.c
drivers/block/sonycd535.c
+1548
-0
drivers/char/keyboard.c
drivers/char/keyboard.c
+4
-3
drivers/net/CONFIG
drivers/net/CONFIG
+2
-0
drivers/net/Makefile
drivers/net/Makefile
+5
-3
drivers/net/README.de4x5
drivers/net/README.de4x5
+10
-0
drivers/net/Space.c
drivers/net/Space.c
+1
-1
drivers/net/apricot.c
drivers/net/apricot.c
+2
-1
drivers/net/de4x5.c
drivers/net/de4x5.c
+388
-290
drivers/net/depca.c
drivers/net/depca.c
+47
-87
drivers/net/plip.c
drivers/net/plip.c
+90
-62
drivers/scsi/eata.c
drivers/scsi/eata.c
+21
-7
drivers/scsi/eata.h
drivers/scsi/eata.h
+1
-1
drivers/scsi/hosts.c
drivers/scsi/hosts.c
+1
-0
drivers/scsi/hosts.h
drivers/scsi/hosts.h
+1
-0
drivers/scsi/scsi.c
drivers/scsi/scsi.c
+3
-6
drivers/scsi/sg.c
drivers/scsi/sg.c
+1
-1
drivers/scsi/u14-34f.c
drivers/scsi/u14-34f.c
+6
-3
drivers/scsi/u14-34f.h
drivers/scsi/u14-34f.h
+1
-1
drivers/sound/Readme
drivers/sound/Readme
+1
-1
fs/proc/inode.c
fs/proc/inode.c
+6
-6
fs/proc/net.c
fs/proc/net.c
+10
-21
include/asm-alpha/bitops.h
include/asm-alpha/bitops.h
+3
-3
include/asm-alpha/pgtable.h
include/asm-alpha/pgtable.h
+13
-0
include/asm-alpha/processor.h
include/asm-alpha/processor.h
+9
-0
include/asm-alpha/ptrace.h
include/asm-alpha/ptrace.h
+1
-1
include/asm-i386/pgtable.h
include/asm-i386/pgtable.h
+36
-3
include/asm-i386/processor.h
include/asm-i386/processor.h
+9
-1
include/asm-mips/processor.h
include/asm-mips/processor.h
+1
-1
include/asm-sparc/processor.h
include/asm-sparc/processor.h
+1
-1
include/linux/if_plip.h
include/linux/if_plip.h
+0
-1
include/linux/proc_fs.h
include/linux/proc_fs.h
+0
-3
include/linux/sched.h
include/linux/sched.h
+0
-1
include/linux/sonycd535.h
include/linux/sonycd535.h
+183
-0
init/main.c
init/main.c
+6
-0
kernel/ksyms.c
kernel/ksyms.c
+2
-0
mm/memory.c
mm/memory.c
+277
-196
mm/mprotect.c
mm/mprotect.c
+1
-0
mm/vmalloc.c
mm/vmalloc.c
+3
-2
net/inet/af_inet.c
net/inet/af_inet.c
+3
-1
net/inet/arp.c
net/inet/arp.c
+1
-1
net/inet/igmp.c
net/inet/igmp.c
+2
-2
net/inet/ip_fw.c
net/inet/ip_fw.c
+6
-21
net/inet/ipx.c
net/inet/ipx.c
+15
-3
net/inet/route.c
net/inet/route.c
+2
-1
No files found.
CREDITS
View file @
55415e93
...
...
@@ -682,6 +682,11 @@ S: Stresemannstr. 62
S: 10963 Berlin
S: Germany
N: Ken Pizzini
E: ken@halcyon.com
D: CDROM driver "sonycd535" (Sony CDU-535/531)
S:
N: Stefan Probst
E: snprobst@immd4.informatik.uni-erlangen.de
D: The Linux Support Team Erlangen
...
...
Makefile
View file @
55415e93
VERSION
=
1
PATCHLEVEL
=
1
SUBLEVEL
=
9
0
SUBLEVEL
=
9
1
ARCH
=
i386
...
...
arch/alpha/kernel/process.c
View file @
55415e93
...
...
@@ -46,15 +46,6 @@ void show_regs(struct pt_regs * regs)
printk
(
"
\n
PS: %04lx PC: %016lx
\n
"
,
regs
->
ps
,
regs
->
pc
);
}
/*
* Do necessary setup to start up a newly executed thread.
*/
void
start_thread
(
struct
pt_regs
*
regs
,
unsigned
long
pc
,
unsigned
long
sp
)
{
regs
->
pc
=
pc
;
wrusp
(
sp
);
}
/*
* Free current thread data structures etc..
*/
...
...
arch/i386/config.in
View file @
55415e93
...
...
@@ -43,7 +43,7 @@ comment 'Networking options'
bool 'TCP/IP networking' CONFIG_INET y
if [ "$CONFIG_INET" = "y" ]; then
bool 'IP forwarding/gatewaying' CONFIG_IP_FORWARD n
bool 'IP multicasting
(ALPHA)
' CONFIG_IP_MULTICAST n
bool 'IP multicasting' CONFIG_IP_MULTICAST n
bool 'IP firewalling' CONFIG_IP_FIREWALL n
bool 'IP accounting' CONFIG_IP_ACCT n
comment '(it is safe to leave these untouched)'
...
...
@@ -119,7 +119,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 '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
if [ "$CONFIG_NET_VENDOR_SMC" = "y" ]; then
...
...
@@ -162,7 +161,7 @@ if [ "$CONFIG_NET_EISA" = "y" ]; then
bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
fi
bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
bool 'DE425, DE434, DE435 support' CONFIG_DE4
x
5 n
bool 'DE425, DE434, DE435 support' CONFIG_DE4
X
5 n
# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
...
...
@@ -195,6 +194,7 @@ if [ "$CONFIG_SBPCD" = "y" ]; then
fi
fi
bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n
bool 'Sony CDU535 CDROM driver support' CONFIG_CDU535 n
comment 'Filesystems'
...
...
@@ -210,7 +210,7 @@ bool '/proc filesystem support' CONFIG_PROC_FS y
if [ "$CONFIG_INET" = "y" ]; then
bool 'NFS filesystem support' CONFIG_NFS_FS y
fi
if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" ]; then
if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y"
-o "$CONFIG_CDU535" = "y"
]; then
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
else
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
...
...
arch/i386/kernel/process.c
View file @
55415e93
...
...
@@ -113,17 +113,6 @@ void show_regs(struct pt_regs * regs)
0xffff
&
regs
->
fs
,
0xffff
&
regs
->
gs
);
}
/*
* Do necessary setup to start up a newly executed thread.
*/
void
start_thread
(
struct
pt_regs
*
regs
,
unsigned
long
eip
,
unsigned
long
esp
)
{
regs
->
cs
=
USER_CS
;
regs
->
ds
=
regs
->
es
=
regs
->
ss
=
regs
->
fs
=
regs
->
gs
=
USER_DS
;
regs
->
eip
=
eip
;
regs
->
esp
=
esp
;
}
/*
* Free current thread data structures etc..
*/
...
...
drivers/block/Makefile
View file @
55415e93
...
...
@@ -79,6 +79,11 @@ OBJS := $(OBJS) xd.o
SRCS
:=
$(SRCS)
xd.c
endif
ifdef
CONFIG_CDU535
OBJS
:=
$(OBJS)
sonycd535.o
SRCS
:=
$(SRCS)
sonycd535.c
endif
all
:
block.a
block.a
:
$(OBJS)
...
...
drivers/block/README.fd
View file @
55415e93
...
...
@@ -71,7 +71,7 @@ restore the default behaviour.
Tells the floppy driver that you don't have a Thinkpad.
floppy=<drive>,<type>,cmos
Sets the cmos type of <drive> to <type>. Addition
na
ly, this drive is
Sets the cmos type of <drive> to <type>. Addition
al
ly, this drive is
allowed in the bitmask. This is useful if you have more than two
floppy drives (only two can be described in the physical cmos), or if
your BIOS uses non-standard CMOS types. The CMOS types are:
...
...
drivers/block/README.sonycd535
0 → 100644
View file @
55415e93
README FOR LINUX SONY CDU-535/531 DRIVER
========================================
This is the the Sony CDU-535 (and 531) driver version 0.7 for Linux.
I do not think I have the documentation to add features like DMA support
so if anyone else wants to pursue it or help me with it, please do.
(I need to see what was done for the CDU-31A driver -- perhaps I can
steal some of that code.)
This is a Linux device driver for the Sony CDU-535 CDROM drive. This is
one of the older Sony drives with its own interface card (Sony bus).
The DOS driver for this drive is named SONY_CDU.SYS - when you boot DOS
your drive should be identified as a SONY CDU-535. The driver works
with a CDU-531 also. One user reported that the driver worked on drives
OEM'ed by Procomm, drive and interface board were labelled Procomm.
The Linux driver is based on Corey Minyard's sonycd 0.3 driver for
the CDU-31A. Ron Jeppesen just changed the commands that were sent
to the drive to correspond to the CDU-535 commands and registers.
There were enough changes to let bugs creep in but it seems to be stable.
Ron was able to tar an entire CDROM (should read all blocks) and built
ghostview and xfig off Walnut Creek's X11R5/GNU CDROM. xcdplayer and
workman work with the driver. Others have used the driver without
problems except those dealing with wait loops (fixed in third release).
Like Minyard's original driver this one uses a polled interface (this
is also the default setup for the DOS driver). It has not been tried
with interrupts or DMA enabled on the board.
REQUIREMENTS
============
- Sony CDU-535 drive, preferably without interrupts and DMA
enabled on the card.
- Drive must be set up as unit 1. Only the first unit will be
recognized
- you must enter your interface address into
/usr/src/linux/include/linux/sonycd535.h and build the
appropriate kernel or use the "kernel command line" parameter
sonycd535=0x320
with the correct interface address.
NOTES:
======
1) The drive MUST be turned on when booting or it will not be recognized!
(but see comments on modulized version below)
2) when the cdrom device is opened the eject button is disabled to keep the
user from ejecting a mounted disk and replacing it with another.
Unfortunately xcdplayer and workman also open the cdrom device so you
have to use the eject button in the software. Keep this in mind if your
cdrom player refuses to give up its disk -- exit workman or xcdplayer, or
umount the drive if it has been mounted.
THANKS
======
Many thanks to Ron Jeppesen (ronj.an@site007.saic.com) for getting
this project off the ground. He wrote the initial release and
the first two patches to this driver (0.1, 0.2, and 0.3).
(aknowlegements from Ron Jeppesen in the 0.3 release:)
Thanks to Corey Minyard who wrote the original CDU-31A driver on which
this driver is based. Thanks to Ken Pizzini and Bob Blair who provided
patches and feedback on the first release of this driver.
Ken Pizzini
ken@halcyon.com
------------------------------------------------------------------------------
(The following is from Joel Katz <Stimpson@Panix.COM>.)
To build a version of sony535.o that can be installed as a module,
use the following command:
gcc -c -D__KERNEL__ -DMODULE -O2 sonycd535.c -o sonycd535.o
To install the module, simply type:
insmod sony535.o
And to remove it:
rmmod sony535
The code checks to see if MODULE is defined and behaves as it used
to if MODULE is not defined. That means your patched file should behave
exactly as it used to if compiled into the kernel.
I have an externel drive, and I usually leave it powered off. I used
to have to reboot if I needed to use the CDROM drive. Now I don't.
Even if you have an internal drive, why waste the 268K of memory
(unswappable) that the driver uses if you use your CD-ROM drive infrequently?
This driver will not install (whether compiled in or loaded as a
module) if the CDROM drive is not available during its initialization. This
means that you can have the driver compiled into the kernel and still load
the module later (assuming the driver doesn't install itself during
power-on). This only wastes 12K when you boot with the CDROM drive off.
This is what I usually do; I leave the driver compiled into the
kernel, but load it as a module if I powered the system up with the drive
off and then later decided to use the CDROM drive.
Since the driver only uses a single page to point to the chunks,
attempting to set the buffer cache to more than 2 Megabytes would be very
bad; don't do that.
drivers/block/blk.h
View file @
55415e93
...
...
@@ -47,6 +47,9 @@ extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end);
#ifdef CONFIG_AZTCD
extern
unsigned
long
aztcd_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
);
#endif
#ifdef CONFIG_CDU535
extern
unsigned
long
sony535_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
);
#endif
#ifdef CONFIG_BLK_DEV_HD
extern
unsigned
long
hd_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
);
#endif
...
...
@@ -181,6 +184,15 @@ static void floppy_off(unsigned int nr);
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#elif (MAJOR_NR == CDU535_CDROM_MAJOR)
#define DEVICE_NAME "SONY-CDU535"
#define DEVICE_INTR do_cdu535
#define DEVICE_REQUEST do_cdu535_request
#define DEVICE_NR(device) (MINOR(device))
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR)
#define DEVICE_NAME "Matsushita CD-ROM controller #1"
...
...
drivers/block/floppy.c
View file @
55415e93
...
...
@@ -91,7 +91,7 @@
#include <linux/config.h>
/* do print messages for unexpected interupts */
/* do print messages for unexpected inter
r
upts */
static
int
print_unex
=
1
;
#ifndef FD_MODULE
...
...
@@ -3205,7 +3205,7 @@ static char get_fdc_version(void)
/* we make the invert_dcl function global. One day, somebody might
want to centralize all thinkpad related options into one lilo option,
there are just so many thinpad related quirks! */
there are just so many thin
k
pad related quirks! */
void
floppy_invert_dcl
(
int
*
ints
,
int
param
)
{
int
i
;
...
...
drivers/block/ll_rw_blk.c
View file @
55415e93
...
...
@@ -399,6 +399,9 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
int
correct_size
;
struct
blk_dev_struct
*
dev
;
int
i
;
#if defined(CONFIG_CDU535) && defined(CONFIG_CDU31A)
int
sonycd_save_mem_start
;
#endif
/* Make sure that the first block contains something reasonable */
while
(
!*
bh
)
{
...
...
@@ -542,9 +545,24 @@ long blk_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_BLK_DEV_XD
mem_start
=
xd_init
(
mem_start
,
mem_end
);
#endif
#if defined(CONFIG_CDU535) && defined(CONFIG_CDU31A)
{
/* since controllers for 535 and 31A can be at same location
* we have to be careful.
*/
sonycd_save_mem_start
=
mem_start
;
mem_start
=
cdu31a_init
(
mem_start
,
mem_end
);
if
(
mem_start
==
sonycd_save_mem_start
)
{
/* CDU31A not found */
mem_start
=
sony535_init
(
mem_start
,
mem_end
);
}
}
#else
#ifdef CONFIG_CDU31A
mem_start
=
cdu31a_init
(
mem_start
,
mem_end
);
#endif
#ifdef CONFIG_CDU535
mem_start
=
sony535_init
(
mem_start
,
mem_end
);
#endif
#endif
/* CONFIG_CDU31A && CONFIG_CDU535 */
#ifdef CONFIG_MCD
mem_start
=
mcd_init
(
mem_start
,
mem_end
);
#endif
...
...
drivers/block/sonycd535.c
0 → 100644
View file @
55415e93
/*
* Sony CDU-535 interface device driver
*
* 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
* commands with the CDU-531 commands. This was complicated by a different
* interface protocol with the drive. The driver is still polled.
*
* Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec.
* I tried polling without the sony_sleep during the data transfers but
* it did not speed things up any.
*
* 5/23/93 (rgj) changed the major number to 21 to get rid of conflict
* with CDU-31A driver. This is the also the number from the Linux
* Device Driver Registry for the Sony Drive. Hope nobody else is using it.
*
* 8/29/93 (rgj) remove the configuring of the interface board address
* from the top level configuration, you have to modify it in this file.
*
* 1/26/95 Made module-capable (Joel Katz <Stimpson@Panix.COM>)
*
* Things to do:
* - handle errors and status better, put everything into a single word
* - use interrupts, DMA
*
* Known Bugs:
* -
*
* 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)
*
* Colossians 3:17
*
* The Sony interface device driver handles Sony interface CDROM
* drives and provides a complete block-level interface as well as an
* ioctl() interface compatible with the Sun (as specified in
* include/linux/cdrom.h). With this interface, CDROMs can be
* accessed and standard audio CDs can be played back normally.
*
* This interface is (unfortunatly) a polled interface. This is
* because most Sony interfaces are set up with DMA and interrupts
* disables. Some (like mine) do not even have the capability to
* handle interrupts or DMA. For this reason you will see a lot of
* the following:
*
* retry_count = jiffies+ SONY_JIFFIES_TIMEOUT;
* while ((retry_count > jiffies) && (! <some condition to wait for))
* {
* while (handle_sony_cd_attention())
* ;
*
* sony_sleep();
* }
* if (the condition not met)
* {
* return an error;
* }
*
* This ugly hack waits for something to happen, sleeping a little
* between every try. it also handles attentions, which are
* asyncronous events from the drive informing the driver that a disk
* has been inserted, removed, etc.
*
* One thing about these drives: They talk in MSF (Minute Second Frame) format.
* There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a
* disk. The funny thing is that these are sent to the drive in BCD, but the
* interface wants to see them in decimal. A lot of conversion goes on.
*
* Copyright (C) 1993 Corey Minyard
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/config.h>
#ifdef CONFIG_CDU535
#ifdef MODULE
# include <linux/module.h>
# include <linux/version.h>
#endif
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/mm.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
#include <asm/io.h>
#include <asm/segment.h>
#include <linux/cdrom.h>
#include <linux/sonycd535.h>
#define MAJOR_NR CDU535_CDROM_MAJOR
#ifdef MODULE
# include "/usr/src/linux/drivers/block/blk.h"
#else
# include "blk.h"
# define MOD_INC_USE_COUNT
# define MOD_DEC_USE_COUNT
#endif
/*
* this is the base address of the interface card for the Sony CDU535
* CDROM drive. If your jumpers are set for an address other than
* this one (the default), change the following line to the
* proper address.
*/
#ifndef CDU535_ADDRESS
#define CDU535_ADDRESS (0x340)
#endif
#define DEBUG 1
/*
* SONY535_BUFFER_SIZE determines the size of internal buffer used
* by the drive. It must be at least 2K and the larger the buffer
* the better the transfer rate. It does however take system memory.
* On my system I get the following transfer rates using dd to read
* 10 Mb off /dev/cdrom.
*
* 8K buffer 43 Kb/sec
* 16K buffer 66 Kb/sec
* 32K buffer 91 Kb/sec
* 64K buffer 111 Kb/sec
* 128K buffer 123 Kb/sec
* 512K buffer 123 Kb/sec
*/
#define SONY535_BUFFER_SIZE (64*1024)
/*
* if LOCK_DOORS is defined then the eject button is disabled while
* the device is open.
*/
#define LOCK_DOORS
static
int
read_subcode
(
void
);
static
void
sony_get_toc
(
void
);
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
);
/* 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
;
/*
* The following are I/O addresses of the various registers for the drive. The
* comment for the base address also applies here.
*/
static
unsigned
short
select_unit_reg
;
static
unsigned
short
result_reg
;
static
unsigned
short
command_reg
;
static
unsigned
short
read_status_reg
;
static
unsigned
short
data_reg
;
static
int
initialized
=
0
;
/* Has the drive been initialized? */
static
int
sony_disc_changed
=
1
;
/* Has the disk been changed
since the last check? */
static
int
sony_toc_read
=
0
;
/* Has the table of contents been
read? */
static
unsigned
int
sony_buffer_size
;
/* Size in bytes of the read-ahead
buffer. */
static
unsigned
int
sony_buffer_sectors
;
/* Size (in 2048 byte records) of
the read-ahead buffer. */
static
unsigned
int
sony_usage
=
0
;
/* How many processes have the
drive open. */
static
int
sony_first_block
=
-
1
;
/* First OS block (512 byte) in
the read-ahead buffer */
static
int
sony_last_block
=
-
1
;
/* Last OS block (512 byte) in
the read-ahead buffer */
static
struct
s535_sony_toc
*
sony_toc
;
/* Points to the table of
contents. */
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 */
#else
static
unsigned
char
**
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 */
/*
* The audio status uses the values from read subchannel data as specified
* in include/linux/cdrom.h.
*/
static
int
sony_audio_status
=
CDROM_AUDIO_NO_STATUS
;
/*
* The following are a hack for pausing and resuming audio play. The drive
* does not work as I would expect it, if you stop it then start it again,
* the drive seeks back to the beginning and starts over. This holds the
* position during a pause so a resume can restart it. It uses the
* audio status variable above to tell if it is paused.
* 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
};
/*
* This routine returns 1 if the disk has been changed since the last
* check or 0 if it hasn't. Setting flag to 0 resets the changed flag.
*/
static
int
cdu535_check_media_change
(
dev_t
full_dev
)
{
int
retval
;
if
(
MINOR
(
full_dev
)
!=
0
)
{
printk
(
"Sony CD-ROM request error: invalid device.
\n
"
);
return
0
;
}
/* if driver is not initialized, always return 0 */
retval
=
initialized
?
sony_disc_changed
:
0
;
sony_disc_changed
=
0
;
return
retval
;
}
/*
* 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).
*/
static
inline
void
sony_sleep
(
void
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
current
->
timeout
=
jiffies
;
schedule
();
}
/*------------------start of SONY CDU535 very specific ---------------------*/
/****************************************************************************
* void select_unit( int unit_no )
*
* Select the specified unit (0-3) so that subsequent commands reference it
****************************************************************************/
static
void
select_unit
(
int
unit_no
)
{
unsigned
int
select_mask
=
~
(
1
<<
unit_no
);
outb
(
select_mask
,
select_unit_reg
);
}
/***************************************************************************
* int read_result_reg( unsigned char *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
)
{
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
);
#endif
*
data_ptr
=
inb
(
result_reg
);
return
0
;
}
else
{
sony_sleep
();
}
}
printk
(
" Sony CDROM 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.
* Handles reading second status word if available. Returns 0 on success,
* TIME_OUT on failure.
****************************************************************************/
static
int
read_exec_status
(
Byte
status
[
2
])
{
status
[
1
]
=
0
;
if
(
read_result_reg
(
&
(
status
[
0
]))
!=
0
)
return
TIME_OUT
;
if
((
status
[
0
]
&
0x80
)
!=
0
)
{
/* byte two follows */
if
(
read_result_reg
(
&
(
status
[
1
]))
!=
0
)
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
"
);
#endif
return
0
;
}
/****************************************************************************
* int check_drive_status( void )
*
* Check the current drive status. Using this before executing a command
* takes care of the problem of unsolicited drive status-2 messages.
* Add a check of the audio status if we think the disk is playing.
****************************************************************************/
static
int
check_drive_status
(
void
)
{
Byte
status
,
e_status
[
2
];
int
CDD
,
ATN
;
unsigned
char
cmd
;
select_unit
(
0
);
if
(
sony_audio_status
==
CDROM_AUDIO_PLAY
)
{
/* check status */
outb
(
SONY535_REQUEST_AUDIO_STATUS
,
command_reg
);
if
(
read_result_reg
(
&
status
)
==
0
)
{
switch
(
status
)
{
case
0x0
:
break
;
/* play in progress */
case
0x1
:
break
;
/* paused */
case
0x3
:
/* audio play completed */
case
0x5
:
/* play not requested */
sony_audio_status
=
CDROM_AUDIO_COMPLETED
;
read_subcode
();
break
;
case
0x4
:
/* error during play */
sony_audio_status
=
CDROM_AUDIO_ERROR
;
break
;
}
}
}
/* now check drive status */
outb
(
SONY535_REQUEST_DRIVE_STATUS_2
,
command_reg
);
if
(
read_result_reg
(
&
status
)
!=
0
)
return
TIME_OUT
;
#if DEBUG > 1
printk
(
"--check_drive_status() got 0x%x
\n
"
,
status
);
#endif
if
(
status
==
0
)
return
0
;
ATN
=
status
&
0xf
;
CDD
=
(
status
>>
4
)
&
0xf
;
switch
(
ATN
)
{
case
0x0
:
break
;
/* go on to CDD stuff */
case
SONY535_ATN_BUSY
:
if
(
initialized
)
printk
(
"Sony CDROM error, drive busy
\n
"
);
return
CD_BUSY
;
case
SONY535_ATN_EJECT_IN_PROGRESS
:
printk
(
"Sony CDROM 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
"
);
#endif
sony_disc_changed
=
1
;
sony_toc_read
=
0
;
sony_audio_status
=
CDROM_AUDIO_NO_STATUS
;
sony_first_block
=
-
1
;
sony_last_block
=
-
1
;
if
(
initialized
)
{
cmd
=
SONY535_SPIN_UP
;
do_sony_cmd
(
&
cmd
,
1
,
e_status
,
NULL
,
0
,
0
);
sony_get_toc
();
}
return
0
;
default:
printk
(
"Sony CDROM 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 */
case
0x2
:
case
0xa
:
break
;
/* no error */
case
0xc
:
printk
(
"check_drive_status(): CDD = 0xc! Not properly handled!
\n
"
);
return
CD_BUSY
;
/* ? */
default:
return
CD_BUSY
;
}
return
0
;
}
/* check_drive_status() */
/*****************************************************************************
* 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 nReponse. 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 recieved back, then we return 0,
* else we return TIME_OUT. You still have to check the status yourself.
* You should call check_drive_status() before calling this routine
* so that you do not lose notifications of disk changes, etc.
****************************************************************************/
static
int
do_sony_cmd
(
Byte
*
cmd
,
int
n_cmd
,
Byte
status
[
2
],
Byte
*
response
,
int
n_response
,
int
ignore_status_bit7
)
{
int
i
;
/* write out the command */
for
(
i
=
0
;
i
<
n_cmd
;
i
++
)
outb
(
cmd
[
i
],
command_reg
);
/* read back the status */
if
(
read_result_reg
(
status
)
!=
0
)
return
TIME_OUT
;
if
(
!
ignore_status_bit7
&&
((
status
[
0
]
&
0x80
)
!=
0
))
{
/* get second status byte */
if
(
read_result_reg
(
status
+
1
)
!=
0
)
return
TIME_OUT
;
}
else
{
status
[
1
]
=
0
;
}
#if DEBUG > 2
printk
(
"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 */
if
((
status
[
0
]
&
((
ignore_status_bit7
?
0x7f
:
0xff
)
&
0x8f
))
!=
0
)
return
0
;
/* else, read in rest of data */
for
(
i
=
0
;
0
<
n_response
;
n_response
--
,
i
++
)
if
(
read_result_reg
(
response
+
i
)
!=
0
)
return
TIME_OUT
;
return
0
;
}
/* do_sony_cmd() */
/**************************************************************************
* int set_drive_mode( int mode, Byte status[2] )
*
* Set the drive mode to the specified value (mode=0 is audio, mode=e0
* is mode-1 CDROM
**************************************************************************/
static
int
set_drive_mode
(
int
mode
,
Byte
status
[
2
])
{
Byte
cmd_buff
[
2
],
ret_buff
[
1
];
cmd_buff
[
0
]
=
SONY535_SET_DRIVE_MODE
;
cmd_buff
[
1
]
=
mode
;
return
do_sony_cmd
(
cmd_buff
,
2
,
status
,
ret_buff
,
1
,
1
);
}
/***************************************************************************
* 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],
* number of blocks in stored in params[3:5] -- both these are already
* int bcd format.
* Transfer the data into the buffer pointed at by data_buff. buff_size
* gives the number of bytes available in the buffer.
* The routine returns number of bytes read in if successful, otherwise
* it returns one of the standard error returns.
***************************************************************************/
static
int
#ifndef MODULE
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
)
#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
;
#else
Byte
*
start_pos
=
data_buff
;
#endif
if
(
buf_size
<
((
long
)
block_size
)
*
n_blocks
)
return
NO_ROOM
;
set_drive_mode
(
SONY535_CDROM_DRIVE_MODE
,
status
);
/* send command to read the data */
cmd_buff
[
0
]
=
SONY535_SEEK_AND_READ_N_BLOCKS_1
;
for
(
i
=
0
;
i
<
6
;
i
++
)
cmd_buff
[
i
+
1
]
=
params
[
i
];
for
(
i
=
0
;
i
<
7
;
i
++
)
outb
(
cmd_buff
[
i
],
command_reg
);
/* read back the data one block at a time */
while
(
0
<
n_blocks
--
)
{
/* wait for data to be ready */
retry_count
=
jiffies
+
SONY_JIFFIES_TIMEOUT
;
while
(
jiffies
<
retry_count
)
{
read_status
=
inb
(
read_status_reg
);
if
((
read_status
&
SONY535_RESULT_NOT_READY_BIT
)
==
0
)
{
read_exec_status
(
status
);
return
BAD_STATUS
;
}
if
((
read_status
&
SONY535_DATA_NOT_READY_BIT
)
==
0
)
{
/* data is ready, read it */
#ifdef MODULE
data_buff
=
buff
[
sector_count
++
];
#endif
for
(
i
=
0
;
i
<
block_size
;
i
++
)
*
data_buff
++
=
inb
(
data_reg
);
/* unrolling this loop does not seem to help */
break
;
/* exit the timeout loop */
}
sony_sleep
();
/* data not ready, sleep a while */
}
if
(
retry_count
<=
jiffies
)
return
TIME_OUT
;
/* if we reach this stage */
}
/* read all the data, now read the status */
if
((
i
=
read_exec_status
(
status
))
!=
0
)
return
i
;
#ifndef MODULE
return
data_buff
-
start_pos
;
#else
return
block_size
*
sector_count
;
#endif
}
/* seek_and_read_N_blocks() */
/****************************************************************************
* int request_toc_data( Byte status[2], struct s535_sony_toc *toc )
*
* Read in the table of contents data. Converts all the bcd data
* into integers in the toc structure.
****************************************************************************/
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
;
/* read the fixed portion of the table of contents */
if
((
to_status
=
do_sony_cmd
(
&
cmd_no
,
1
,
status
,
(
Byte
*
)
toc
,
15
,
1
))
!=
0
)
return
to_status
;
/* convert the data into integers so we can use them */
first_track_num
=
bcd_to_int
(
toc
->
first_track_num
);
last_track_num
=
bcd_to_int
(
toc
->
last_track_num
);
n_tracks
=
last_track_num
-
first_track_num
+
1
;
/* read each of the track address descriptors */
for
(
i
=
0
;
i
<
n_tracks
;
i
++
)
{
/* read the descriptor into a temporary buffer */
for
(
j
=
0
;
j
<
5
;
j
++
)
{
if
(
read_result_reg
(
track_address_buffer
+
j
)
!=
0
)
return
TIME_OUT
;
if
(
j
==
1
)
/* need to convert from bcd */
track_no
=
bcd_to_int
(
track_address_buffer
[
j
]);
}
/* copy the descriptor to proper location - sonycd.c just fills */
memcpy
(
toc
->
tracks
+
i
,
track_address_buffer
,
5
);
}
return
0
;
}
/* request_toc_data() */
/***************************************************************************
* int spin_up_drive( Byte status[2] )
*
* Spin up the drive (unless it is already spinning).
***************************************************************************/
static
int
spin_up_drive
(
Byte
status
[
2
])
{
Byte
cmd_buff
[
1
];
/* 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
)
return
TIME_OUT
;
if
((
status
[
0
]
&
SONY535_STATUS1_NOT_SPINNING
)
==
0
)
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() */
/*--------------------end of SONY CDU535 very specific ---------------------*/
/* Convert from an integer 0-99 to BCD */
static
inline
unsigned
int
int_to_bcd
(
unsigned
int
val
)
{
int
retval
;
retval
=
(
val
/
10
)
<<
4
;
retval
=
retval
|
val
%
10
;
return
retval
;
}
/* Convert from BCD to an integer from 0-99 */
static
unsigned
int
bcd_to_int
(
unsigned
int
bcd
)
{
return
(((
bcd
>>
4
)
&
0x0f
)
*
10
)
+
(
bcd
&
0x0f
);
}
/*
* Convert a logical sector value (like the OS would want to use for
* a block device) to an MSF format.
*/
static
void
log_to_msf
(
unsigned
int
log
,
unsigned
char
*
msf
)
{
log
=
log
+
LOG_START_OFFSET
;
msf
[
0
]
=
int_to_bcd
(
log
/
4500
);
log
=
log
%
4500
;
msf
[
1
]
=
int_to_bcd
(
log
/
75
);
msf
[
2
]
=
int_to_bcd
(
log
%
75
);
}
/*
* Convert an MSF format to a logical sector.
*/
static
unsigned
int
msf_to_log
(
unsigned
char
*
msf
)
{
unsigned
int
log
;
log
=
bcd_to_int
(
msf
[
2
]);
log
+=
bcd_to_int
(
msf
[
1
])
*
75
;
log
+=
bcd_to_int
(
msf
[
0
])
*
4500
;
log
=
log
-
LOG_START_OFFSET
;
return
log
;
}
/*
* Take in integer size value and put it into a buffer like
* the drive would want to see a number-of-sector value.
*/
static
void
size_to_buf
(
unsigned
int
size
,
unsigned
char
*
buf
)
{
buf
[
0
]
=
size
/
65536
;
size
=
size
%
65536
;
buf
[
1
]
=
size
/
256
;
buf
[
2
]
=
size
%
256
;
}
/*
* The OS calls this to perform a read or write operation to the drive.
* Write obviously fail. Reads to a read ahead of sony_buffer_size
* bytes to help speed operations. This especially helps since the OS
* uses 1024 byte blocks and the drive uses 2048 byte blocks. Since most
* data access on a CD is done sequentially, this saves a lot of operations.
*/
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
];
if
(
!
sony_inuse
)
{
cdu_open
(
NULL
,
NULL
);
}
while
(
1
)
{
/*
* The beginning here is stolen from the hard disk driver. I hope
* its right.
*/
if
(
!
(
CURRENT
)
||
CURRENT
->
dev
<
0
)
{
return
;
}
INIT_REQUEST
;
dev
=
MINOR
(
CURRENT
->
dev
);
block
=
CURRENT
->
sector
;
nsect
=
CURRENT
->
nr_sectors
;
if
(
dev
!=
0
)
{
end_request
(
0
);
continue
;
}
switch
(
CURRENT
->
cmd
)
{
case
READ
:
/*
* If the block address is invalid or the request goes beyond the end of
* the media, return an error.
*/
if
(
sony_toc
->
lead_out_start_lba
<=
(
block
/
4
))
{
end_request
(
0
);
return
;
}
if
(
sony_toc
->
lead_out_start_lba
<=
((
block
+
nsect
)
/
4
))
{
end_request
(
0
);
return
;
}
while
(
0
<
nsect
)
{
/*
* If the requested sector is not currently in the read-ahead buffer,
* it must be read in.
*/
if
((
block
<
sony_first_block
)
||
(
sony_last_block
<
block
))
{
sony_first_block
=
(
block
/
4
)
*
4
;
log_to_msf
(
block
/
4
,
params
);
/*
* If the full read-ahead would go beyond the end of the media, trim
* it back to read just till the end of the media.
*/
if
(
sony_toc
->
lead_out_start_lba
<=
((
block
/
4
)
+
sony_buffer_sectors
))
{
sony_last_block
=
(
sony_toc
->
lead_out_start_lba
*
4
)
-
1
;
read_size
=
sony_toc
->
lead_out_start_lba
-
(
block
/
4
);
}
else
{
sony_last_block
=
sony_first_block
+
(
sony_buffer_sectors
*
4
)
-
1
;
read_size
=
sony_buffer_sectors
;
}
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.
*/
spin_up_retry
=
0
;
try_read_again:
#if DEBUG > 1
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
;
}
printk
(
"Sony CDROM Read error: 0x%.2x
\n
"
,
status
[
0
]);
sony_first_block
=
-
1
;
sony_last_block
=
-
1
;
end_request
(
0
);
return
;
}
}
/*
* The data is in memory now, copy it to the buffer and advance to the
* next block to read.
*/
#ifndef MODULE
copyoff
=
(
block
-
sony_first_block
)
*
512
;
memcpy
(
CURRENT
->
buffer
,
sony_buffer
+
copyoff
,
512
);
#else
copyoff
=
block
-
sony_first_block
;
memcpy
(
CURRENT
->
buffer
,
sony_buffer
[
copyoff
/
4
]
+
512
*
(
copyoff
%
4
),
512
);
#endif
block
+=
1
;
nsect
-=
1
;
CURRENT
->
buffer
+=
512
;
}
end_request
(
1
);
break
;
case
WRITE
:
end_request
(
0
);
break
;
default:
panic
(
"Unkown SONY CD cmd"
);
}
}
}
/*
* Read the table of contents from the drive and set sony_toc_read if
* successful.
*/
static
void
sony_get_toc
(
void
)
{
unsigned
char
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
)
return
;
sony_toc
->
lead_out_start_lba
=
msf_to_log
(
sony_toc
->
lead_out_start_msf
);
sony_toc_read
=
1
;
}
}
/*
* Search for a specific track in the table of contents. track is
* passed in bcd format
*/
static
int
find_track
(
int
track
)
{
int
i
;
int
num_tracks
;
num_tracks
=
bcd_to_int
(
sony_toc
->
last_track_num
)
-
bcd_to_int
(
sony_toc
->
first_track_num
)
+
1
;
for
(
i
=
0
;
i
<
num_tracks
;
i
++
)
{
if
(
sony_toc
->
tracks
[
i
].
track
==
track
)
{
return
i
;
}
}
return
-
1
;
}
/*
* Read the subcode and put it int last_sony_subcode for future use.
*/
static
int
read_subcode
(
void
)
{
Byte
cmd
=
SONY535_REQUEST_SUB_Q_DATA
,
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
);
return
-
EIO
;
}
return
0
;
}
/*
* Get the subchannel info like the CDROMSUBCHNL command wants to see it. If
* the drive is playing, the subchannel needs to be read (since it would be
* changing). If the drive is paused or completed, the subcode information has
* already been stored, just use that. The ioctl call wants things in decimal
* (not BCD), so all the conversions are done.
*/
static
int
sony_get_subchnl_info
(
long
arg
)
{
struct
cdrom_subchnl
schi
;
/* Get attention stuff */
if
(
check_drive_status
()
!=
0
)
return
-
EIO
;
sony_get_toc
();
if
(
!
sony_toc_read
)
{
return
-
EIO
;
}
verify_area
(
VERIFY_WRITE
/* and read */
,
(
char
*
)
arg
,
sizeof
(
schi
));
memcpy_fromfs
(
&
schi
,
(
char
*
)
arg
,
sizeof
(
schi
));
switch
(
sony_audio_status
)
{
case
CDROM_AUDIO_PLAY
:
if
(
read_subcode
()
<
0
)
{
return
-
EIO
;
}
break
;
case
CDROM_AUDIO_PAUSED
:
case
CDROM_AUDIO_COMPLETED
:
break
;
case
CDROM_AUDIO_NO_STATUS
:
schi
.
cdsc_audiostatus
=
sony_audio_status
;
memcpy_tofs
((
char
*
)
arg
,
&
schi
,
sizeof
(
schi
));
return
0
;
break
;
case
CDROM_AUDIO_INVALID
:
case
CDROM_AUDIO_ERROR
:
default:
return
-
EIO
;
}
schi
.
cdsc_audiostatus
=
sony_audio_status
;
schi
.
cdsc_adr
=
last_sony_subcode
->
address
;
schi
.
cdsc_ctrl
=
last_sony_subcode
->
control
;
schi
.
cdsc_trk
=
bcd_to_int
(
last_sony_subcode
->
track_num
);
schi
.
cdsc_ind
=
bcd_to_int
(
last_sony_subcode
->
index_num
);
if
(
schi
.
cdsc_format
==
CDROM_MSF
)
{
schi
.
cdsc_absaddr
.
msf
.
minute
=
bcd_to_int
(
last_sony_subcode
->
abs_msf
[
0
]);
schi
.
cdsc_absaddr
.
msf
.
second
=
bcd_to_int
(
last_sony_subcode
->
abs_msf
[
1
]);
schi
.
cdsc_absaddr
.
msf
.
frame
=
bcd_to_int
(
last_sony_subcode
->
abs_msf
[
2
]);
schi
.
cdsc_reladdr
.
msf
.
minute
=
bcd_to_int
(
last_sony_subcode
->
rel_msf
[
0
]);
schi
.
cdsc_reladdr
.
msf
.
second
=
bcd_to_int
(
last_sony_subcode
->
rel_msf
[
1
]);
schi
.
cdsc_reladdr
.
msf
.
frame
=
bcd_to_int
(
last_sony_subcode
->
rel_msf
[
2
]);
}
else
if
(
schi
.
cdsc_format
==
CDROM_LBA
)
{
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
));
return
0
;
}
/*
* The big ugly ioctl handler.
*/
static
int
cdu_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
unsigned
int
dev
;
unsigned
char
status
[
2
];
unsigned
char
cmd_buff
[
10
],
params
[
10
];
int
i
,
dsc_status
;
if
(
!
inode
)
{
return
-
EINVAL
;
}
dev
=
MINOR
(
inode
->
i_rdev
)
>>
6
;
if
(
dev
!=
0
)
{
return
-
EINVAL
;
}
if
(
check_drive_status
()
!=
0
)
return
-
EIO
;
switch
(
cmd
)
{
case
CDROMSTART
:
/* Spin up the drive */
if
(
spin_up_drive
(
status
)
<
0
)
{
printk
(
"Sony CDROM error 0x%.2x (CDROMSTART)
\n
"
,
status
[
0
]);
return
-
EIO
;
}
return
0
;
break
;
case
CDROMSTOP
:
/* Spin down the drive */
cmd_buff
[
0
]
=
SONY535_HOLD
;
do_sony_cmd
(
cmd_buff
,
1
,
status
,
NULL
,
0
,
0
);
/*
* Spin the drive down, ignoring the error if the disk was
* already not spinning.
*/
sony_audio_status
=
CDROM_AUDIO_NO_STATUS
;
cmd_buff
[
0
]
=
SONY535_SPIN_DOWN
;
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
]);
return
-
EIO
;
}
return
0
;
break
;
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
]);
return
-
EIO
;
}
/* Get the current position and save it for resuming */
if
(
read_subcode
()
<
0
)
{
return
-
EIO
;
}
cur_pos_msf
[
0
]
=
last_sony_subcode
->
abs_msf
[
0
];
cur_pos_msf
[
1
]
=
last_sony_subcode
->
abs_msf
[
1
];
cur_pos_msf
[
2
]
=
last_sony_subcode
->
abs_msf
[
2
];
sony_audio_status
=
CDROM_AUDIO_PAUSED
;
return
0
;
break
;
case
CDROMRESUME
:
/* Start the drive after being paused */
set_drive_mode
(
SONY535_AUDIO_DRIVE_MODE
,
status
);
if
(
sony_audio_status
!=
CDROM_AUDIO_PAUSED
)
{
return
-
EINVAL
;
}
spin_up_drive
(
status
);
/* Start the drive at the saved position. */
cmd_buff
[
0
]
=
SONY535_PLAY_AUDIO
;
cmd_buff
[
1
]
=
0
;
/* play back starting at this address */
cmd_buff
[
2
]
=
cur_pos_msf
[
0
];
cmd_buff
[
3
]
=
cur_pos_msf
[
1
];
cmd_buff
[
4
]
=
cur_pos_msf
[
2
];
cmd_buff
[
5
]
=
SONY535_PLAY_AUDIO
;
cmd_buff
[
6
]
=
2
;
/* set ending address */
cmd_buff
[
7
]
=
final_pos_msf
[
0
];
cmd_buff
[
8
]
=
final_pos_msf
[
1
];
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
]);
return
-
EIO
;
}
sony_audio_status
=
CDROM_AUDIO_PLAY
;
return
0
;
break
;
case
CDROMPLAYMSF
:
/* Play starting at the given MSF address. */
verify_area
(
VERIFY_READ
,
(
char
*
)
arg
,
6
);
spin_up_drive
(
status
);
set_drive_mode
(
SONY535_AUDIO_DRIVE_MODE
,
status
);
memcpy_fromfs
(
params
,
(
void
*
)
arg
,
6
);
/* The parameters are given in int, must be converted */
for
(
i
=
0
;
i
<
3
;
i
++
)
{
cmd_buff
[
2
+
i
]
=
int_to_bcd
(
params
[
i
]);
cmd_buff
[
7
+
i
]
=
int_to_bcd
(
params
[
i
+
3
]);
}
cmd_buff
[
0
]
=
SONY535_PLAY_AUDIO
;
cmd_buff
[
1
]
=
0
;
/* play back starting at this address */
/* cmd_buff[2-4] are filled in for loop above */
cmd_buff
[
5
]
=
SONY535_PLAY_AUDIO
;
cmd_buff
[
6
]
=
2
;
/* set ending address */
/* 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
]);
return
-
EIO
;
}
/* Save the final position for pauses and resumes */
final_pos_msf
[
0
]
=
cmd_buff
[
7
];
final_pos_msf
[
1
]
=
cmd_buff
[
8
];
final_pos_msf
[
2
]
=
cmd_buff
[
9
];
sony_audio_status
=
CDROM_AUDIO_PLAY
;
return
0
;
break
;
case
CDROMREADTOCHDR
:
/* Read the table of contents header */
{
struct
cdrom_tochdr
*
hdr
;
struct
cdrom_tochdr
loc_hdr
;
sony_get_toc
();
if
(
!
sony_toc_read
)
return
-
EIO
;
hdr
=
(
struct
cdrom_tochdr
*
)
arg
;
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
));
}
return
0
;
break
;
case
CDROMREADTOCENTRY
:
/* Read a given table of contents entry */
{
struct
cdrom_tocentry
*
entry
;
struct
cdrom_tocentry
loc_entry
;
int
track_idx
;
unsigned
char
*
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
));
memcpy_fromfs
(
&
loc_entry
,
entry
,
sizeof
(
loc_entry
));
/* Lead out is handled separately since it is special. */
if
(
loc_entry
.
cdte_track
==
CDROM_LEADOUT
)
{
loc_entry
.
cdte_adr
=
0
/*sony_toc->address2 */
;
loc_entry
.
cdte_ctrl
=
sony_toc
->
control2
;
msf_val
=
sony_toc
->
lead_out_start_msf
;
}
else
{
track_idx
=
find_track
(
int_to_bcd
(
loc_entry
.
cdte_track
));
if
(
track_idx
<
0
)
return
-
EINVAL
;
loc_entry
.
cdte_adr
=
0
/*sony_toc->tracks[track_idx].address */
;
loc_entry
.
cdte_ctrl
=
sony_toc
->
tracks
[
track_idx
].
control
;
msf_val
=
sony_toc
->
tracks
[
track_idx
].
track_start_msf
;
}
/* Logical buffer address or MSF format requested? */
if
(
loc_entry
.
cdte_format
==
CDROM_LBA
)
{
loc_entry
.
cdte_addr
.
lba
=
msf_to_log
(
msf_val
);
}
else
if
(
loc_entry
.
cdte_format
==
CDROM_MSF
)
{
loc_entry
.
cdte_addr
.
msf
.
minute
=
bcd_to_int
(
*
msf_val
);
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
));
}
return
0
;
break
;
case
CDROMPLAYTRKIND
:
/* Play a track. This currently ignores index. */
{
struct
cdrom_ti
ti
;
int
track_idx
;
sony_get_toc
();
if
(
!
sony_toc_read
)
return
-
EIO
;
verify_area
(
VERIFY_READ
,
(
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
))
{
return
-
EINVAL
;
}
track_idx
=
find_track
(
int_to_bcd
(
ti
.
cdti_trk0
));
if
(
track_idx
<
0
)
return
-
EINVAL
;
params
[
1
]
=
sony_toc
->
tracks
[
track_idx
].
track_start_msf
[
0
];
params
[
2
]
=
sony_toc
->
tracks
[
track_idx
].
track_start_msf
[
1
];
params
[
3
]
=
sony_toc
->
tracks
[
track_idx
].
track_start_msf
[
2
];
/*
* If we want to stop after the last track, use the lead-out
* MSF to do that.
*/
if
(
bcd_to_int
(
sony_toc
->
last_track_num
)
<=
ti
.
cdti_trk1
)
{
log_to_msf
(
msf_to_log
(
sony_toc
->
lead_out_start_msf
)
-
1
,
&
(
params
[
4
]));
}
else
{
track_idx
=
find_track
(
int_to_bcd
(
ti
.
cdti_trk1
+
1
));
if
(
track_idx
<
0
)
return
-
EINVAL
;
log_to_msf
(
msf_to_log
(
sony_toc
->
tracks
[
track_idx
].
track_start_msf
)
-
1
,
&
(
params
[
4
]));
}
params
[
0
]
=
0x03
;
spin_up_drive
(
status
);
set_drive_mode
(
SONY535_AUDIO_DRIVE_MODE
,
status
);
/* Start the drive at the saved position. */
cmd_buff
[
0
]
=
SONY535_PLAY_AUDIO
;
cmd_buff
[
1
]
=
0
;
/* play back starting at this address */
cmd_buff
[
2
]
=
params
[
1
];
cmd_buff
[
3
]
=
params
[
2
];
cmd_buff
[
4
]
=
params
[
3
];
cmd_buff
[
5
]
=
SONY535_PLAY_AUDIO
;
cmd_buff
[
6
]
=
2
;
/* set ending address */
cmd_buff
[
7
]
=
params
[
4
];
cmd_buff
[
8
]
=
params
[
5
];
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
]);
return
-
EIO
;
}
/* Save the final position for pauses and resumes */
final_pos_msf
[
0
]
=
params
[
4
];
final_pos_msf
[
1
]
=
params
[
5
];
final_pos_msf
[
2
]
=
params
[
6
];
sony_audio_status
=
CDROM_AUDIO_PLAY
;
return
0
;
}
case
CDROMSUBCHNL
:
/* Get subchannel info */
return
sony_get_subchnl_info
(
arg
);
case
CDROMVOLCTRL
:
/* Volume control. What volume does this change, anyway? */
{
struct
cdrom_volctrl
volctrl
;
verify_area
(
VERIFY_READ
,
(
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
]);
return
-
EIO
;
}
}
return
0
;
case
CDROMEJECT
:
/* Eject the drive */
cmd_buff
[
0
]
=
SONY535_STOP
;
do_sony_cmd
(
cmd_buff
,
1
,
status
,
NULL
,
0
,
0
);
cmd_buff
[
0
]
=
SONY535_SPIN_DOWN
;
do_sony_cmd
(
cmd_buff
,
1
,
status
,
NULL
,
0
,
0
);
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
]);
return
-
EIO
;
}
return
0
;
break
;
default:
return
-
EINVAL
;
}
}
/*
* Open the drive for operations. Spin the drive up and read the table of
* contents if these have not already been done.
*/
static
int
cdu_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
unsigned
char
status
[
2
],
cmd_buff
[
2
];
if
(
sony_inuse
)
return
-
EBUSY
;
if
(
check_drive_status
()
!=
0
)
return
-
EIO
;
sony_inuse
=
1
;
MOD_INC_USE_COUNT
;
if
(
spin_up_drive
(
status
)
!=
0
)
{
printk
(
"Sony CDROM error 0x%.2x (cdu_open, spin up)
\n
"
,
status
[
0
]);
sony_inuse
=
0
;
MOD_DEC_USE_COUNT
;
return
-
EIO
;
}
sony_get_toc
();
if
(
!
sony_toc_read
)
{
cmd_buff
[
0
]
=
SONY535_SPIN_DOWN
;
do_sony_cmd
(
cmd_buff
,
1
,
status
,
NULL
,
0
,
0
);
sony_inuse
=
0
;
MOD_DEC_USE_COUNT
;
return
-
EIO
;
}
if
(
inode
)
{
check_disk_change
(
inode
->
i_rdev
);
}
sony_usage
++
;
#ifdef LOCK_DOORS
/* disable the eject button while mounted */
cmd_buff
[
0
]
=
SONY535_DISABLE_EJECT_BUTTON
;
do_sony_cmd
(
cmd_buff
,
1
,
status
,
NULL
,
0
,
0
);
#endif
return
0
;
}
/*
* Close the drive. Spin it down if no task is using it. The spin
* down will fail if playing audio, so audio play is OK.
*/
static
void
cdu_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
unsigned
char
status
[
2
],
cmd_no
;
sony_inuse
=
0
;
MOD_DEC_USE_COUNT
;
if
(
0
<
sony_usage
)
{
sony_usage
--
;
}
if
(
sony_usage
==
0
)
{
sync_dev
(
inode
->
i_rdev
);
check_drive_status
();
if
(
sony_audio_status
!=
CDROM_AUDIO_PLAY
)
{
cmd_no
=
SONY535_SPIN_DOWN
;
do_sony_cmd
(
&
cmd_no
,
1
,
status
,
NULL
,
0
,
0
);
}
#ifdef LOCK_DOORS
/* enable the eject button after umount */
cmd_no
=
SONY535_ENABLE_EJECT_BUTTON
;
do_sony_cmd
(
&
cmd_no
,
1
,
status
,
NULL
,
0
,
0
);
#endif
}
}
static
struct
file_operations
cdu_fops
=
{
NULL
,
/* lseek - default */
block_read
,
/* read - general block-dev read */
block_write
,
/* write - general block-dev write */
NULL
,
/* readdir - bad */
NULL
,
/* select */
cdu_ioctl
,
/* ioctl */
NULL
,
/* mmap */
cdu_open
,
/* open */
cdu_release
,
/* release */
NULL
,
/* fsync */
NULL
,
/* fasync */
cdu535_check_media_change
,
/* check media change */
NULL
/* revalidate */
};
/*
* Initialize the driver.
*/
#ifndef MODULE
unsigned
long
sony535_init
(
unsigned
long
mem_start
,
unsigned
long
mem_end
)
#else
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
;
#ifdef MODULE
int
i
;
#endif
/* 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
"
);
#ifndef MODULE
return
mem_start
;
#else
return
-
EIO
;
#endif
}
/* look for the CD-ROM, follows the procedure in the DOS driver */
inb
(
select_unit_reg
);
retry_count
=
jiffies
+
2
*
HZ
;
while
(
jiffies
<
retry_count
)
sony_sleep
();
/* wait for 40 18 Hz ticks (from DOS driver) */
inb
(
result_reg
);
outb
(
0
,
read_status_reg
);
/* does a reset? */
retry_count
=
jiffies
+
SONY_JIFFIES_TIMEOUT
;
while
(
jiffies
<
retry_count
)
{
select_unit
(
0
);
if
(
inb
(
result_reg
)
!=
0xff
)
break
;
sony_sleep
();
/* about 1-2 ms on my machine */
}
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 DEBUG > 0
if
(
(
status
[
0
]
&
0x7f
)
!=
0
)
printk
(
"Inquiry command returned status = 0x%x
\n
"
,
status
[
0
]);
#endif
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
)
{
/* set the drive mode successful, we are set! */
sony_buffer_size
=
SONY535_BUFFER_SIZE
;
sony_buffer_sectors
=
sony_buffer_size
/
2048
;
printk
(
"Sony 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
);
if
(
register_blkdev
(
MAJOR_NR
,
"cdu-535"
,
&
cdu_fops
))
{
printk
(
"Unable to get major %d for sony CDU-535 cd
\n
"
,
MAJOR_NR
);
#ifndef MODULE
return
mem_start
;
#else
return
-
EIO
;
#endif
}
blk_dev
[
MAJOR_NR
].
request_fn
=
DEVICE_REQUEST
;
read_ahead
[
MAJOR_NR
]
=
8
;
/* 8 sector (4kB) read-ahead */
#ifndef MODULE
sony_toc
=
(
struct
s535_sony_toc
*
)
mem_start
;
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
+=
sony_buffer_size
;
#else
/* MODULE */
sony_toc
=
(
struct
s535_sony_toc
*
)
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
(
4
*
sony_buffer_sectors
,
GFP_KERNEL
);
for
(
i
=
0
;
i
<
sony_buffer_sectors
;
i
++
)
sony_buffer
[
i
]
=
(
unsigned
char
*
)
kmalloc
(
2048
,
GFP_KERNEL
);
#endif
/* MODULE */
initialized
=
1
;
}
}
}
#ifndef MODULE
if
(
!
initialized
)
printk
(
"Did not find a Sony CDU-535 drive
\n
"
);
else
snarf_region
(
sony_cd_base_io
,
4
);
return
mem_start
;
#else
if
(
!
initialized
)
{
printk
(
"Did not find a Sony CDU-535 drive
\n
"
);
return
-
EIO
;
}
else
{
snarf_region
(
sony_cd_base_io
,
4
);
}
return
0
;
#endif
}
#ifndef MODULE
/*
* accept "kernel command line" parameters
* (added by emoenke@gwdg.de)
*
* use: tell LILO:
* sonycd535=0x320
*
* the address value has to be the existing CDROM port address.
*/
void
sonycd535_setup
(
char
*
strings
,
int
*
ints
)
{
if
(
ints
[
0
]
>
0
)
sony_cd_base_io
=
ints
[
1
];
#if 0 /* placeholder for future use */
if (ints[0] > 1)
irq_used = ints[2];
#endif
if
((
strings
!=
NULL
)
&&
(
*
strings
!=
'\0'
))
printk
(
"Sony CDU-535: Warning: Unknown interface type: %s
\n
"
,
strings
);
}
#else
/* MODULE */
void
cleanup_module
(
void
)
{
int
i
;
if
(
MOD_IN_USE
)
{
printk
(
"Sony 535 module in use, cannot remove
\n
"
);
return
;
}
if
(
unregister_blkdev
(
MAJOR_NR
,
"cdu-535"
)
==
(
-
EINVAL
))
{
printk
(
"Uh oh, couldn't unregister cdu-535
\n
"
);
return
;
}
kfree_s
(
sony_toc
,
sizeof
(
*
sony_toc
));
kfree_s
(
last_sony_subcode
,
sizeof
(
*
last_sony_subcode
));
for
(
i
=
0
;
i
<
sony_buffer_sectors
;
i
++
)
kfree_s
(
sony_buffer
[
i
],
2048
);
kfree_s
(
sony_buffer
,
4
*
sony_buffer_sectors
);
printk
(
"cdu-535 module released
\n
"
);
}
#endif
/* MODULE */
#endif
/* CONFIG_CDU535 */
drivers/char/keyboard.c
View file @
55415e93
...
...
@@ -91,7 +91,8 @@ unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
/* shift state counters.. */
static
unsigned
char
k_down
[
NR_SHIFT
]
=
{
0
,
};
/* keyboard key bitmap */
static
unsigned
long
key_down
[
8
]
=
{
0
,
};
#define BITS_PER_LONG (8*sizeof(unsigned long))
static
unsigned
long
key_down
[
256
/
BITS_PER_LONG
]
=
{
0
,
};
extern
int
last_console
;
static
int
want_console
=
-
1
;
...
...
@@ -954,8 +955,8 @@ void compute_shiftstate(void)
for
(
i
=
0
;
i
<
SIZE
(
key_down
);
i
++
)
if
(
key_down
[
i
])
{
/* skip this word if not a single bit on */
k
=
(
i
<<
5
)
;
for
(
j
=
0
;
j
<
32
;
j
++
,
k
++
)
k
=
i
*
BITS_PER_LONG
;
for
(
j
=
0
;
j
<
BITS_PER_LONG
;
j
++
,
k
++
)
if
(
test_bit
(
k
,
key_down
))
{
sym
=
U
(
plain_map
[
k
]);
if
(
KTYP
(
sym
)
==
KT_SHIFT
)
{
...
...
drivers/net/CONFIG
View file @
55415e93
...
...
@@ -42,6 +42,8 @@
# DE4x5 The DIGITAL series of PCI/EISA Ethernet Cards,
# DE425, DE434 and DE435
# DE4x5_DEBUG Set the desired debug level
# IS_ZYNX May allow driver to work with Zynx cards -
# see linux/drivers/net/README.de4x5
#
# The following options exist, but cannot be set in this file.
...
...
drivers/net/Makefile
View file @
55415e93
...
...
@@ -194,11 +194,13 @@ ifdef CONFIG_ATP
NETDRV_OBJS
:=
$(NETDRV_OBJS)
atp.o
endif
ifdef
CONFIG_DE4
x
5
ifdef
CONFIG_DE4
X
5
NETDRV_OBJS
:=
$(NETDRV_OBJS)
de4x5.o
else
MODULES
:=
$(MODULES)
de4x5.o
endif
de4x5.o
:
de4x5.c CONFIG
$(CC)
$(CPPFLAGS)
$(CFLAGS)
$(DE4x5_OPTS)
-c
$<
endif
ifdef
CONFIG_NI52
NETDRV_OBJS
:=
$(NETDRV_OBJS)
ni52.o
...
...
@@ -252,7 +254,7 @@ endif
net.a
:
$(NETDRV_OBJS)
rm
-f
net.a
ar
rcs net.a
$(NETDRV_OBJS)
$(AR)
rcs net.a
$(NETDRV_OBJS)
clean
:
rm
-f
core
*
.o
*
.a
*
.s
...
...
drivers/net/README.de4x5
View file @
55415e93
...
...
@@ -21,6 +21,16 @@ theoretical ethernet rate.
The cause is under investigation.
************************************************************************
ZYNX cards, which use the PCI DECchip DC21040, are not specifically
supported in this driver because
a) I have no information on them.
b) I cannot test them with the driver.
c) Donald Becker's 'tulip.c' driver works with them....well one person says
they do and another doesn't, so take your pick!
This driver can be made to work with the ZYNX (and may be the SMC) card by
setting a compile time flag in linux/drivers/net/CONFIG
Enjoy!
...
...
drivers/net/Space.c
View file @
55415e93
...
...
@@ -115,7 +115,7 @@ ethif_probe(struct device *dev)
#ifdef CONFIG_EWRK3
/* DEC EtherWORKS 3 */
&&
ewrk3_probe
(
dev
)
#endif
#ifdef CONFIG_DE4
x
5
/* DEC DE425, DE434, DE435 adapters */
#ifdef CONFIG_DE4
X
5
/* DEC DE425, DE434, DE435 adapters */
&&
de4x5_probe
(
dev
)
#endif
#ifdef CONFIG_APRICOT
/* Apricot I82596 */
...
...
drivers/net/apricot.c
View file @
55415e93
...
...
@@ -547,7 +547,7 @@ i596_open(struct device *dev)
irq2dev_map
[
dev
->
irq
]
=
dev
;
i
=
init_rx_bufs
(
dev
,
RX_RING_SIZE
);
i
=
init_rx_bufs
(
dev
,
RX_RING_SIZE
);
if
((
i
=
init_rx_bufs
(
dev
,
RX_RING_SIZE
))
<
RX_RING_SIZE
)
printk
(
"%s: only able to allocate %d receive buffers
\n
"
,
dev
->
name
,
i
);
...
...
@@ -743,6 +743,7 @@ int apricot_probe(struct device *dev)
dev
->
priv
=
(
void
*
)((
dev
->
mem_start
+
0xf
)
&
0xfffffff0
);
lp
=
(
struct
i596_private
*
)
dev
->
priv
;
memset
((
void
*
)
lp
,
0
,
sizeof
(
struct
i596_private
));
lp
->
scb
.
command
=
0
;
lp
->
scb
.
cmd
=
(
struct
i596_cmd
*
)
I596_NULL
;
lp
->
scb
.
rfd
=
(
struct
i596_rfd
*
)
I596_NULL
;
...
...
drivers/net/de4x5.c
View file @
55415e93
...
...
@@ -41,12 +41,24 @@
differences in the EISA and PCI CSR address offsets from the base
address.
The ability to load this driver as a loadable module has been included
and used extensively during the driver development (to save those long
reboot sequences). I don't recommend using loadable drivers with PCI
however, since the PCI BIOS allocates the I/O and memory addresses
dynamically at boot time. To utilise this ability, you have to do 8
things:
The ability to load this driver as a loadable module has been included
and used extensively during the driver development (to save those long
reboot sequences). Loadable module support under PCI has been achieved
by letting any I/O address less than 0x1000 be assigned as:
0xghh
where g is the bus number (usually 0 until the BIOS's get fixed)
hh is the device number (max is 32 per bus).
Essentially, the I/O address and IRQ information are ignored and filled
in later by the PCI BIOS during the PCI probe. Note that the board
should be in the system at boot time so that its I/O address and IRQ are
allocated by the PCI BIOS automatically. The special case of device 0 on
bus 0 is not allowed as the probe will think you're autoprobing a
module.
To utilise this ability, you have to do 8 things:
0) have a copy of the loadable modules code installed on your system.
1) copy de4x5.c from the /linux/drivers/net directory to your favourite
...
...
@@ -76,10 +88,19 @@
pause whilst the driver figures out where its media went). My tests
using ping showed that it appears to work....
A compile time switch to allow Zynx recognition has been added. This
"feature" is in no way supported nor tested in this driver and the user
may use it at his/her sole discretion. I have had 2 conflicting reports
that my driver will or won't work with Zynx. Try Donald Becker's
'tulip.c' if this driver doesn't work for you. I will not be supporting
Zynx cards since I have no information on them and can't test them in a
system.
TO DO:
------
1. Improve the timing loops to be accurate across different CPUs
and speeds.
1. Add DC21041 Nway/Autosense support
2. Add DC21140 Autosense support
3. Add timer support
Revision History
...
...
@@ -90,22 +111,34 @@
0.1 17-Nov-94 Initial writing. ALPHA code release.
0.2 13-Jan-95 Added PCI support for DE435's
0.21 19-Jan-95 Added auto media detection
0.22 10-Feb-95 Fix interrupt handler call <chris@cosy.sbg.ac.at>
Fix recognition bug reported by <bkm@star.rl.ac.uk>
Add request/release_region code
Add loadable modules support for PCI
Clean up loadable modules support
=========================================================================
*/
static
char
*
version
=
"de4x5.c:v0.2
1 1/19
/95 davies@wanton.lkg.dec.com
\n
"
;
static
char
*
version
=
"de4x5.c:v0.2
2 2/10
/95 davies@wanton.lkg.dec.com
\n
"
;
#include <stdarg.h>
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
/* MODULE */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <asm/bitops.h>
#include <asm/io.h>
...
...
@@ -120,11 +153,6 @@ static char *version = "de4x5.c:v0.21 1/19/95 davies@wanton.lkg.dec.com\n";
#include <linux/types.h>
#include <linux/unistd.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#endif
/* MODULE */
#include "de4x5.h"
#ifdef DE4X5_DEBUG
...
...
@@ -133,32 +161,60 @@ static int de4x5_debug = DE4X5_DEBUG;
static
int
de4x5_debug
=
1
;
#endif
#ifndef PROBE_LENGTH
/*
** Ethernet PROM defines
*/
#define PROBE_LENGTH 32
#
endif
#
define ETH_PROM_SIG 0xAA5500FFUL
#define ETH_PROM_SIG "FF0055AAFF0055AA"
/*
** Ethernet Info
*/
#define PKT_BUF_SZ 1544
/* Buffer size for each Tx/Rx buffer */
#define MAX_PKT_SZ 1514
/* Maximum ethernet packet length */
#define MAX_DAT_SZ 1500
/* Maximum ethernet data length */
#define MIN_DAT_SZ 1
/* Minimum ethernet data length */
#define PKT_HDR_LEN 14
/* Addresses and data length info */
#define
DE4X5_SIGNATURE {"DE425",""}
#define
DE4X5_NAME_LENGTH 8
#define
CRC_POLYNOMIAL_BE 0x04c11db7UL
/* Ethernet CRC, big endian */
#define
CRC_POLYNOMIAL_LE 0xedb88320UL
/* Ethernet CRC, little endian */
#define DE4X5_EISA_IO_PORTS 0x0c00
/* I/O port base address, slot 0 */
/*
** EISA bus defines
*/
#define DE4X5_EISA_IO_PORTS 0x0c00
/* I/O port base address, slot 0 */
#define DE4X5_EISA_TOTAL_SIZE 0xfff
/* I/O address extent */
#define MAX_EISA_SLOTS 16
#define EISA_SLOT_INC 0x1000
#define DE4X5_EISA_SEARCH 0x00000001
/* probe search mask */
static
u_long
eisa_slots_full
=
DE4X5_EISA_SEARCH
;
/* holds which EISA slots hold */
/* DE425s, for multi-DE425 case */
#define DE4X5_SIGNATURE {"DE425",""}
#define DE4X5_NAME_LENGTH 8
/*
** PCI Bus defines
*/
#define PCI_MAX_BUS_NUM 8
static
u_long
pci_slots_full
[
PCI_MAX_BUS_NUM
];
/* Which PCI slots used */
/* on up to PCI_MAX_BUS_NUM buses */
#define DE4X5_PCI_TOTAL_SIZE 0x80
/* I/O address extent */
#define CRC_POLYNOMIAL_BE 0x04c11db7UL
/* Ethernet CRC, big endian */
#define CRC_POLYNOMIAL_LE 0xedb88320UL
/* Ethernet CRC, little endian */
/*
** Timer defines
*/
#define TIMER_WIDTH 16
#define TIMER_PORT 0x43
#define TIMER_LATCH 0x06
#define TIMER_READ 0x40
#define TIMER_TICK 419
/*ns*/
#define DELAY_QUANT 5
/*us*/
#define LWPAD ((long)(sizeof(long) - 1))
/* for longword alignment */
#ifndef IS_ZYNX
/* See README.de4x5 for using this */
static
int
is_zynx
=
0
;
#else
static
int
is_zynx
=
1
;
#endif
/*
** DE4X5 IRQ ENABLE/DISABLE
*/
...
...
@@ -167,52 +223,43 @@ static u_long irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
static
u_long
irq_en
=
IMR_NIM
|
IMR_AIM
;
#define ENABLE_IRQs \
imr |= irq_en;\
outl(imr, DE4X5_IMR)
/* Enable the IRQs */
imr |= irq_en;\
outl(imr, DE4X5_IMR)
/* Enable the IRQs */
#define DISABLE_IRQs \
imr = inl(DE4X5_IMR);\
imr &= ~irq_en;\
outl(imr, DE4X5_IMR)
/* Disable the IRQs */
imr = inl(DE4X5_IMR);\
imr &= ~irq_en;\
outl(imr, DE4X5_IMR)
/* Disable the IRQs */
#define UNMASK_IRQs \
imr |= irq_mask;\
outl(imr, DE4X5_IMR)
/* Unmask the IRQs */
imr |= irq_mask;\
outl(imr, DE4X5_IMR)
/* Unmask the IRQs */
#define MASK_IRQs \
imr = inl(DE4X5_IMR);\
imr &= ~irq_mask;\
outl(imr, DE4X5_IMR)
/* Mask the IRQs */
imr = inl(DE4X5_IMR);\
imr &= ~irq_mask;\
outl(imr, DE4X5_IMR)
/* Mask the IRQs */
/*
** DE4X5 START/STOP
*/
#define START_DE4X5 \
omr = inl(DE4X5_OMR);\
omr |= OMR_ST | OMR_SR;\
outl(omr, DE4X5_OMR)
/* Enable the TX and/or RX */
omr = inl(DE4X5_OMR);\
omr |= OMR_ST | OMR_SR;\
outl(omr, DE4X5_OMR)
/* Enable the TX and/or RX */
#define STOP_DE4X5 \
omr = inl(DE4X5_OMR);\
omr &= ~(OMR_ST|OMR_SR);\
outl(omr, DE4X5_OMR)
/* Disable the TX and/or RX */
omr = inl(DE4X5_OMR);\
omr &= ~(OMR_ST|OMR_SR);\
outl(omr, DE4X5_OMR)
/* Disable the TX and/or RX */
/*
** DE4X5 SIA RESET
*/
#define RESET_SIA \
outl(SICR_RESET, DE4X5_SICR);
/* Reset SIA connectivity regs */
\
outl(STRR_RESET, DE4X5_STRR);
/* Write reset values */
\
outl(SIGR_RESET, DE4X5_SIGR)
/* Write reset values */
/*
** Ethernet Packet Info
*/
#define PKT_BUF_SZ 1544
/* Buffer size for each Tx/Rx buffer */
#define MAX_PKT_SZ 1514
/* Maximum ethernet packet length */
#define MAX_DAT_SZ 1500
/* Maximum ethernet data length */
#define MIN_DAT_SZ 1
/* Minimum ethernet data length */
#define PKT_HDR_LEN 14
/* Addresses and data length info */
outl(SICR_RESET, DE4X5_SICR);
/* Reset SIA connectivity regs */
\
outl(STRR_RESET, DE4X5_STRR);
/* Write reset values */
\
outl(SIGR_RESET, DE4X5_SIGR)
/* Write reset values */
/*
** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
...
...
@@ -231,7 +278,7 @@ struct de4x5_desc {
u_long
des1
;
char
*
buf
;
char
*
next
;
};
};
/*
** The DE4X5 private structure
...
...
@@ -241,6 +288,7 @@ struct de4x5_desc {
increase DE4X5_PKT_STAT_SZ */
struct
de4x5_private
{
char
adapter_name
[
80
];
/* Adapter name */
struct
de4x5_desc
rx_ring
[
NUM_RX_DESC
];
/* RX descriptor ring */
struct
de4x5_desc
tx_ring
[
NUM_TX_DESC
];
/* TX descriptor ring */
struct
sk_buff
*
skb
[
NUM_TX_DESC
];
/* TX skb for freeing when sent */
...
...
@@ -249,13 +297,13 @@ struct de4x5_private {
char
setup_frame
[
SETUP_FRAME_LEN
];
/* Holds MCA and PA info. */
struct
enet_statistics
stats
;
/* Public stats */
struct
{
unsigned
long
bins
[
DE4X5_PKT_STAT_SZ
];
/* Private stats counters */
unsigned
long
unicast
;
unsigned
long
multicast
;
unsigned
long
broadcast
;
unsigned
long
excessive_collisions
;
unsigned
long
tx_underruns
;
unsigned
long
excessive_underruns
;
unsigned
long
bins
[
DE4X5_PKT_STAT_SZ
];
/* Private stats counters */
unsigned
long
unicast
;
unsigned
long
multicast
;
unsigned
long
broadcast
;
unsigned
long
excessive_collisions
;
unsigned
long
tx_underruns
;
unsigned
long
excessive_underruns
;
}
pktStats
;
char
rxRingSize
;
char
txRingSize
;
...
...
@@ -273,7 +321,7 @@ struct de4x5_private {
*/
static
int
de4x5_open
(
struct
device
*
dev
);
static
int
de4x5_queue_pkt
(
struct
sk_buff
*
skb
,
struct
device
*
dev
);
static
void
de4x5_interrupt
(
int
reg_ptr
);
static
void
de4x5_interrupt
(
int
irq
,
struct
pt_regs
*
regs
);
static
int
de4x5_close
(
struct
device
*
dev
);
static
struct
enet_statistics
*
de4x5_get_stats
(
struct
device
*
dev
);
static
void
set_multicast_list
(
struct
device
*
dev
,
int
num_addrs
,
void
*
addrs
);
...
...
@@ -289,6 +337,9 @@ static int de4x5_tx(struct device *dev);
static
int
autoconf_media
(
struct
device
*
dev
);
static
void
create_packet
(
struct
device
*
dev
,
char
*
frame
,
int
len
);
static
u_short
dce_get_ticks
(
void
);
static
void
dce_us_delay
(
u_long
usec
);
static
void
dce_ms_delay
(
u_long
msec
);
static
void
load_packet
(
struct
device
*
dev
,
char
*
buf
,
u_long
flags
,
struct
sk_buff
*
skb
);
static
void
EISA_signature
(
char
*
name
,
short
iobase
);
static
int
DevicePresent
(
short
iobase
);
...
...
@@ -303,11 +354,14 @@ static struct device *alloc_device(struct device *dev, int iobase);
#ifdef MODULE
int
init_module
(
void
);
void
cleanup_module
(
void
);
static
int
autoprobed
=
1
,
loading_module
=
1
;
# else
static
unsigned
char
de4x5_irq
[]
=
{
5
,
9
,
10
,
11
};
static
int
autoprobed
=
0
,
loading_module
=
0
;
#endif
/* MODULE */
static
int
num_de4x5s
=
0
,
num_eth
=
0
,
autoprobed
=
0
;
static
char
name
[
DE4X5_NAME_LENGTH
+
1
];
static
int
num_de4x5s
=
0
,
num_eth
=
0
;
/*
** Kludge to get around the fact that the CSR addresses have different
...
...
@@ -315,8 +369,8 @@ static int num_de4x5s = 0, num_eth = 0, autoprobed = 0;
** PROM is accessed differently.
*/
static
struct
bus_type
{
int
bus
;
int
device
;
int
bus
;
int
device
;
}
bus
;
/*
...
...
@@ -338,22 +392,17 @@ int de4x5_probe(struct device *dev)
int
tmp
=
num_de4x5s
,
iobase
=
dev
->
base_addr
;
int
status
=
-
ENODEV
;
if
((
iobase
>
0
)
&&
(
iobase
<
0x100
))
{
/* Don't probe at all. */
status
=
-
ENXIO
;
#ifdef MODULE
}
else
if
(
iobase
==
0
){
if
((
iobase
==
0
)
&&
loading_module
){
printk
(
"Autoprobing is not supported when loading a module based driver.
\n
"
);
status
=
-
EIO
;
#endif
}
else
{
/* First probe for the Ethernet */
/* Address PROM pattern */
}
else
{
/* First probe for the Ethernet */
/* Address PROM pattern */
eisa_probe
(
dev
,
iobase
);
pci_probe
(
dev
,
iobase
);
if
((
tmp
==
num_de4x5s
)
&&
(
iobase
!=
0
))
{
printk
(
"%s: de4x5_probe() cannot find device at 0x%04x.
\n
"
,
dev
->
name
,
iobase
);
printk
(
"%s: de4x5_probe() cannot find device at 0x%04x.
\n
"
,
dev
->
name
,
iobase
);
}
/*
...
...
@@ -374,27 +423,29 @@ de4x5_hw_init(struct device *dev, short iobase)
{
struct
bus_type
*
lp
=
&
bus
;
int
tmpbus
,
i
,
j
,
status
=
0
;
char
*
tmp
,
name
[
DE4X5_NAME_LENGTH
+
1
]
;
char
*
tmp
;
u_long
nicsr
;
/*
** First, RESET the board.
*/
RESET_DE4X5
;
if
(((
nicsr
=
inl
(
DE4X5_STS
))
&
(
STS_TS
|
STS_RS
))
==
0
)
{
/* Really stopped */
if
(((
nicsr
=
inl
(
DE4X5_STS
))
&
(
STS_TS
|
STS_RS
))
==
0
)
{
/*
** Now find out what kind of DC21040/DC21140 board we have.
** Now find out what kind of DC21040/DC21
041/DC21
140 board we have.
*/
if
(
lp
->
bus
==
PCI
)
{
strcpy
(
name
,
"DE435"
);
if
(
!
is_zynx
)
{
strcpy
(
name
,
"DE435"
);
}
else
{
strcpy
(
name
,
"ZYNX"
);
}
}
else
{
EISA_signature
(
name
,
EISA_ID0
);
}
if
(
*
name
!=
'\0'
)
{
/* found a board signature */
dev
->
base_addr
=
iobase
;
request_region
(
iobase
,
(
lp
->
bus
==
PCI
?
DE4X5_PCI_TOTAL_SIZE
:
DE4X5_EISA_TOTAL_SIZE
),
name
);
if
(
lp
->
bus
==
EISA
)
{
printk
(
"%s: %s at %#3x (EISA slot %d)"
,
...
...
@@ -405,7 +456,7 @@ de4x5_hw_init(struct device *dev, short iobase)
printk
(
", h/w address "
);
status
=
aprom_crc
(
dev
);
for
(
i
=
0
;
i
<
ETH_ALEN
-
1
;
i
++
)
{
/* get the ethernet addr. */
for
(
i
=
0
;
i
<
ETH_ALEN
-
1
;
i
++
)
{
/* get the ethernet addr. */
printk
(
"%2.2x:"
,
dev
->
dev_addr
[
i
]);
}
printk
(
"%2.2x,
\n
"
,
dev
->
dev_addr
[
i
]);
...
...
@@ -428,6 +479,7 @@ de4x5_hw_init(struct device *dev, short iobase)
lp
=
(
struct
de4x5_private
*
)
dev
->
priv
;
memset
(
dev
->
priv
,
0
,
sizeof
(
struct
de4x5_private
));
lp
->
bus
=
tmpbus
;
strcpy
(
lp
->
adapter_name
,
name
);
/*
** Allocate contiguous receive buffers, long word aligned.
...
...
@@ -488,7 +540,8 @@ de4x5_hw_init(struct device *dev, short iobase)
}
outl
(
0
,
DE4X5_IMR
);
/* Re-mask RUM interrupt */
#endif
/* MODULE */
#endif
/* MODULE */
}
else
{
printk
(
" and requires IRQ%d (not probed).
\n
"
,
dev
->
irq
);
}
...
...
@@ -500,7 +553,10 @@ de4x5_hw_init(struct device *dev, short iobase)
}
else
{
printk
(
" which has an Ethernet PROM CRC error.
\n
"
);
status
=
-
ENXIO
;
}
}
if
(
status
)
release_region
(
iobase
,
(
lp
->
bus
==
PCI
?
DE4X5_PCI_TOTAL_SIZE
:
DE4X5_EISA_TOTAL_SIZE
));
}
else
{
status
=
-
ENXIO
;
}
...
...
@@ -530,7 +586,7 @@ de4x5_hw_init(struct device *dev, short iobase)
}
else
{
/* Incorrectly initialised hardware */
struct
de4x5_private
*
lp
=
(
struct
de4x5_private
*
)
dev
->
priv
;
if
(
lp
)
{
kfree_s
(
lp
->
rx_ring
,
RX_BUFF_SZ
*
NUM_RX_DESC
+
LWPAD
);
kfree_s
(
lp
->
rx_ring
[
0
].
buf
,
RX_BUFF_SZ
*
NUM_RX_DESC
+
LWPAD
);
}
if
(
dev
->
priv
)
{
kfree_s
(
dev
->
priv
,
sizeof
(
struct
de4x5_private
)
+
LWPAD
);
...
...
@@ -555,7 +611,7 @@ de4x5_open(struct device *dev)
*/
STOP_DE4X5
;
if
(
request_irq
(
dev
->
irq
,
(
void
*
)
de4x5_interrupt
,
0
,
"de4x5"
))
{
if
(
request_irq
(
dev
->
irq
,
(
void
*
)
de4x5_interrupt
,
0
,
lp
->
adapter_name
))
{
printk
(
"de4x5_open(): Requested IRQ%d is busy
\n
"
,
dev
->
irq
);
status
=
-
EAGAIN
;
}
else
{
...
...
@@ -573,7 +629,6 @@ de4x5_open(struct device *dev)
printk
(
"%2.2x:"
,(
short
)
dev
->
dev_addr
[
i
]);
}
printk
(
"
\n
"
);
printk
(
"
\t
checked memory: 0x%08lx
\n
"
,
eisa_slots_full
);
printk
(
"Descriptor head addresses:
\n
"
);
printk
(
"
\t
0x%8.8lx 0x%8.8lx
\n
"
,(
long
)
lp
->
rx_ring
,(
long
)
lp
->
tx_ring
);
printk
(
"Descriptor addresses:
\n
RX: "
);
...
...
@@ -642,9 +697,7 @@ de4x5_open(struct device *dev)
}
}
#ifdef MODULE
MOD_INC_USE_COUNT
;
#endif
MOD_INC_USE_COUNT
;
return
status
;
}
...
...
@@ -829,9 +882,8 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
** The DE4X5 interrupt handler.
*/
static
void
de4x5_interrupt
(
int
reg_ptr
)
de4x5_interrupt
(
int
irq
,
struct
pt_regs
*
regs
)
{
int
irq
=
-
(((
struct
pt_regs
*
)
reg_ptr
)
->
orig_eax
+
2
);
struct
device
*
dev
=
(
struct
device
*
)(
irq2dev_map
[
irq
]);
struct
de4x5_private
*
lp
;
int
iobase
;
...
...
@@ -1046,9 +1098,7 @@ de4x5_close(struct device *dev)
free_irq
(
dev
->
irq
);
irq2dev_map
[
dev
->
irq
]
=
0
;
#ifdef MODULE
MOD_DEC_USE_COUNT
;
#endif
return
0
;
}
...
...
@@ -1179,7 +1229,8 @@ static void eisa_probe(struct device *dev, short ioaddr)
u_short
iobase
;
struct
bus_type
*
lp
=
&
bus
;
if
(
!
ioaddr
&&
autoprobed
)
return
;
/* Been here before ! */
if
(
!
ioaddr
&&
autoprobed
)
return
;
/* Been here before ! */
if
((
ioaddr
<
0x1000
)
&&
(
ioaddr
>
0
))
return
;
/* PCI MODULE special */
lp
->
bus
=
EISA
;
...
...
@@ -1194,18 +1245,17 @@ static void eisa_probe(struct device *dev, short ioaddr)
}
for
(
status
=
-
ENODEV
;
i
<
maxSlots
&&
dev
!=
NULL
;
i
++
,
iobase
+=
EISA_SLOT_INC
)
{
if
(((
eisa_slots_full
>>
i
)
&
0x01
)
==
0
)
{
if
(
DevicePresent
(
EISA_APROM
)
==
0
)
{
eisa_slots_full
|=
(
0x01
<<
i
);
if
((
DevicePresent
(
EISA_APROM
)
==
0
)
||
is_zynx
)
{
if
(
check_region
(
iobase
,
DE4X5_EISA_TOTAL_SIZE
)
==
0
)
{
if
((
dev
=
alloc_device
(
dev
,
iobase
))
!=
NULL
)
{
if
((
status
=
de4x5_hw_init
(
dev
,
iobase
))
==
0
)
{
num_de4x5s
++
;
}
num_eth
++
;
}
}
else
if
(
autoprobed
)
{
printk
(
"%s: region already allocated at 0x%04x.
\n
"
,
dev
->
name
,
iobase
);
}
}
else
{
printk
(
"%s: EISA device already allocated at 0x%04x.
\n
"
,
dev
->
name
,
iobase
);
}
}
...
...
@@ -1215,55 +1265,60 @@ static void eisa_probe(struct device *dev, short ioaddr)
/*
** PCI bus I/O device probe
*/
#define PCI_DEVICE (dev_num << 3)
#define PCI_DEVICE (dev_num << 3)
#define PCI_LAST_DEV 32
static
void
pci_probe
(
struct
device
*
dev
,
short
ioaddr
)
{
u_char
irq
;
u_short
pb
,
dev_num
;
u_short
i
,
vendor
,
device
,
status
;
u_short
pb
,
dev_num
,
dev_last
;
u_short
vendor
,
device
,
status
;
u_long
class
,
iobase
;
struct
bus_type
*
lp
=
&
bus
;
static
char
pci_init
=
0
;
if
(
!
ioaddr
&&
autoprobed
)
return
;
/* Been here before ! */
if
(
!
pci_init
)
{
for
(
i
=
0
;
i
<
PCI_MAX_BUS_NUM
;
i
++
)
{
pci_slots_full
[
i
]
=
0
;
pci_init
=
1
;
}
}
if
(
pcibios_present
())
{
lp
->
bus
=
PCI
;
for
(
pb
=
0
,
dev_num
=
0
;
dev_num
<
32
&&
dev
!=
NULL
;
dev_num
++
)
{
if
(
ioaddr
<
0x1000
)
{
pb
=
(
u_short
)(
ioaddr
>>
8
);
dev_num
=
(
u_short
)(
ioaddr
&
0xff
);
}
else
{
pb
=
0
;
dev_num
=
0
;
}
if
(
ioaddr
>
0
)
{
dev_last
=
(
dev_num
<
PCI_LAST_DEV
)
?
dev_num
+
1
:
PCI_LAST_DEV
;
}
else
{
dev_last
=
PCI_LAST_DEV
;
}
for
(;
dev_num
<
dev_last
&&
dev
!=
NULL
;
dev_num
++
)
{
pcibios_read_config_dword
(
pb
,
PCI_DEVICE
,
PCI_CLASS_REVISION
,
&
class
);
if
(
class
!=
0xffffffff
)
{
if
(((
pci_slots_full
[
pb
]
>>
dev_num
)
&
0x01
)
==
0
)
{
pcibios_read_config_word
(
pb
,
PCI_DEVICE
,
PCI_VENDOR_ID
,
&
vendor
);
pcibios_read_config_word
(
pb
,
PCI_DEVICE
,
PCI_DEVICE_ID
,
&
device
);
if
((
vendor
==
DC21040_VID
)
&&
(
device
==
DC21040_DID
))
{
/* Set the device number information */
lp
->
device
=
dev_num
;
/* Get the board I/O address */
pcibios_read_config_dword
(
pb
,
PCI_DEVICE
,
PCI_BASE_ADDRESS_0
,
&
iobase
);
iobase
&=
CBIO_MASK
;
/* Fetch the IRQ to be used */
pcibios_read_config_byte
(
pb
,
PCI_DEVICE
,
PCI_INTERRUPT_LINE
,
&
irq
);
/* Enable I/O Accesses and Bus Mastering */
pcibios_read_config_word
(
pb
,
PCI_DEVICE
,
PCI_COMMAND
,
&
status
);
status
|=
PCI_COMMAND_IO
|
PCI_COMMAND_MASTER
;
pcibios_write_config_word
(
pb
,
PCI_DEVICE
,
PCI_COMMAND
,
status
);
/* If a device is present, initialise it */
if
(
DevicePresent
(
DE4X5_APROM
)
==
0
)
{
pci_slots_full
[
pb
]
|=
(
0x01
<<
dev_num
);
pcibios_read_config_word
(
pb
,
PCI_DEVICE
,
PCI_VENDOR_ID
,
&
vendor
);
pcibios_read_config_word
(
pb
,
PCI_DEVICE
,
PCI_DEVICE_ID
,
&
device
);
if
((
vendor
==
DC21040_VID
)
&&
(
device
==
DC21040_DID
))
{
/* Set the device number information */
lp
->
device
=
dev_num
;
/* Get the board I/O address */
pcibios_read_config_dword
(
pb
,
PCI_DEVICE
,
PCI_BASE_ADDRESS_0
,
&
iobase
);
iobase
&=
CBIO_MASK
;
/* Fetch the IRQ to be used */
pcibios_read_config_byte
(
pb
,
PCI_DEVICE
,
PCI_INTERRUPT_LINE
,
&
irq
);
/* Enable I/O Accesses and Bus Mastering */
pcibios_read_config_word
(
pb
,
PCI_DEVICE
,
PCI_COMMAND
,
&
status
);
status
|=
PCI_COMMAND_IO
|
PCI_COMMAND_MASTER
;
pcibios_write_config_word
(
pb
,
PCI_DEVICE
,
PCI_COMMAND
,
status
);
/* If there is a device and I/O region is open, initialise dev. */
if
((
DevicePresent
(
DE4X5_APROM
)
==
0
)
||
is_zynx
)
{
if
(
check_region
(
iobase
,
DE4X5_PCI_TOTAL_SIZE
)
==
0
)
{
if
((
dev
=
alloc_device
(
dev
,
iobase
))
!=
NULL
)
{
dev
->
irq
=
irq
;
if
((
status
=
de4x5_hw_init
(
dev
,
iobase
))
==
0
)
{
...
...
@@ -1271,10 +1326,10 @@ static void pci_probe(struct device *dev, short ioaddr)
}
num_eth
++
;
}
}
else
if
(
autoprobed
)
{
printk
(
"%s: region already allocated at 0x%04x.
\n
"
,
dev
->
name
,
(
u_short
)
iobase
);
}
}
}
else
{
printk
(
"%s: PCI device already allocated at slot %d.
\n
"
,
dev
->
name
,
dev_num
);
}
}
}
...
...
@@ -1296,94 +1351,98 @@ static struct device *alloc_device(struct device *dev, int iobase)
/*
** Check the device structures for an end of list or unused device
*/
while
(
dev
->
next
!=
NULL
)
{
if
((
dev
->
base_addr
==
0xffe0
)
||
(
dev
->
base_addr
==
0
))
break
;
dev
=
dev
->
next
;
/* walk through eth device list */
num_eth
++
;
/* increment eth device number */
}
/*
** If an autoprobe is requested for another device, we must re-insert
** the request later in the list. Remember the current position first.
*/
if
((
dev
->
base_addr
==
0
)
&&
(
num_de4x5s
>
0
))
{
addAutoProbe
++
;
tmp
=
dev
->
next
;
/* point to the next device */
init
=
dev
->
init
;
/* remember the probe function */
}
if
(
!
loading_module
)
{
while
(
dev
->
next
!=
NULL
)
{
if
((
dev
->
base_addr
==
0xffe0
)
||
(
dev
->
base_addr
==
0
))
break
;
dev
=
dev
->
next
;
/* walk through eth device list */
num_eth
++
;
/* increment eth device number */
}
/*
** If at end of list and can't use current entry, malloc one up.
** If memory could not be allocated, print an error message.
*/
if
((
dev
->
next
==
NULL
)
&&
!
((
dev
->
base_addr
==
0xffe0
)
||
(
dev
->
base_addr
==
0
))){
dev
->
next
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
/*
** If an autoprobe is requested for another device, we must re-insert
** the request later in the list. Remember the current position first.
*/
if
((
dev
->
base_addr
==
0
)
&&
(
num_de4x5s
>
0
))
{
addAutoProbe
++
;
tmp
=
dev
->
next
;
/* point to the next device */
init
=
dev
->
init
;
/* remember the probe function */
}
dev
=
dev
->
next
;
/* point to the new device */
if
(
dev
==
NULL
)
{
printk
(
"eth%d: Device not initialised, insufficient memory
\n
"
,
num_eth
);
}
else
{
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
dev
->
name
=
(
char
*
)(
dev
+
sizeof
(
struct
device
));
if
(
num_eth
>
9999
)
{
sprintf
(
dev
->
name
,
"eth????"
);
/* New device name */
/*
** If at end of list and can't use current entry, malloc one up.
** If memory could not be allocated, print an error message.
*/
if
((
dev
->
next
==
NULL
)
&&
!
((
dev
->
base_addr
==
0xffe0
)
||
(
dev
->
base_addr
==
0
))){
dev
->
next
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
dev
=
dev
->
next
;
/* point to the new device
*/
if
(
dev
==
NULL
)
{
printk
(
"eth%d: Device not initialised, insufficient memory
\n
"
,
num_eth
);
}
else
{
sprintf
(
dev
->
name
,
"eth%d"
,
num_eth
);
/* New device name */
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
dev
->
name
=
(
char
*
)(
dev
+
sizeof
(
struct
device
));
if
(
num_eth
>
9999
)
{
sprintf
(
dev
->
name
,
"eth????"
);
/* New device name */
}
else
{
sprintf
(
dev
->
name
,
"eth%d"
,
num_eth
);
/* New device name */
}
dev
->
base_addr
=
iobase
;
/* assign the io address */
dev
->
next
=
NULL
;
/* mark the end of list */
dev
->
init
=
&
de4x5_probe
;
/* initialisation routine */
num_de4x5s
++
;
}
dev
->
base_addr
=
iobase
;
/* assign the io address */
dev
->
next
=
NULL
;
/* mark the end of list */
dev
->
init
=
&
de4x5_probe
;
/* initialisation routine */
num_de4x5s
++
;
}
}
ret
=
dev
;
/* return current struct, or NULL */
ret
=
dev
;
/* return current struct, or NULL */
/*
** Now figure out what to do with the autoprobe that has to be inserted.
** Firstly, search the (possibly altered) list for an empty space.
*/
if
(
ret
!=
NULL
)
{
if
(
addAutoProbe
)
{
for
(;
(
tmp
->
next
!=
NULL
)
&&
(
tmp
->
base_addr
!=
0xffe0
);
tmp
=
tmp
->
next
);
/*
** Now figure out what to do with the autoprobe that has to be inserted.
** Firstly, search the (possibly altered) list for an empty space.
*/
if
(
ret
!=
NULL
)
{
if
(
addAutoProbe
)
{
for
(;
(
tmp
->
next
!=
NULL
)
&&
(
tmp
->
base_addr
!=
0xffe0
);
tmp
=
tmp
->
next
);
/*
** If no more device structures and can't use the current one, malloc
** one up. If memory could not be allocated, print an error message.
*/
if
((
tmp
->
next
==
NULL
)
&&
!
(
tmp
->
base_addr
==
0xffe0
))
{
tmp
->
next
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
tmp
=
tmp
->
next
;
/* point to the new device */
if
(
tmp
==
NULL
)
{
printk
(
"%s: Insufficient memory to extend the device list.
\n
"
,
dev
->
name
);
}
else
{
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
tmp
->
name
=
(
char
*
)(
tmp
+
sizeof
(
struct
device
));
if
(
num_eth
>
9999
)
{
sprintf
(
tmp
->
name
,
"eth????"
);
/* New device name */
/*
** If no more device structures and can't use the current one, malloc
** one up. If memory could not be allocated, print an error message.
*/
if
((
tmp
->
next
==
NULL
)
&&
!
(
tmp
->
base_addr
==
0xffe0
))
{
tmp
->
next
=
(
struct
device
*
)
kmalloc
(
sizeof
(
struct
device
)
+
8
,
GFP_KERNEL
);
tmp
=
tmp
->
next
;
/* point to the new device */
if
(
tmp
==
NULL
)
{
printk
(
"%s: Insufficient memory to extend the device list.
\n
"
,
dev
->
name
);
}
else
{
sprintf
(
tmp
->
name
,
"eth%d"
,
num_eth
);
/* New device name */
/*
** If the memory was allocated, point to the new memory area
** and initialize it (name, I/O address, next device (NULL) and
** initialisation probe routine).
*/
tmp
->
name
=
(
char
*
)(
tmp
+
sizeof
(
struct
device
));
if
(
num_eth
>
9999
)
{
sprintf
(
tmp
->
name
,
"eth????"
);
/* New device name */
}
else
{
sprintf
(
tmp
->
name
,
"eth%d"
,
num_eth
);
/* New device name */
}
tmp
->
base_addr
=
0
;
/* re-insert the io address */
tmp
->
next
=
NULL
;
/* mark the end of list */
tmp
->
init
=
init
;
/* initialisation routine */
}
tmp
->
base_addr
=
0
;
/* re-insert the io address */
tmp
->
next
=
NULL
;
/* mark the end of list */
tmp
->
init
=
init
;
/* initialisation routine */
}
else
{
/* structure already exists */
tmp
->
base_addr
=
0
;
/* re-insert the io address */
}
}
else
{
/* structure already exists */
tmp
->
base_addr
=
0
;
/* re-insert the io address */
}
}
}
else
{
ret
=
dev
;
}
return
ret
;
...
...
@@ -1401,7 +1460,7 @@ static int autoconf_media(struct device *dev)
int
media
,
entry
,
iobase
=
dev
->
base_addr
;
char
frame
[
64
];
u_long
i
,
omr
,
sisr
,
linkBad
;
u_long
t_330ms
=
920000
;
/* u_long t_330ms = 920000;*/
u_long
t_3s
=
8000000
;
/* Set up for TP port, with LEDs */
...
...
@@ -1425,10 +1484,11 @@ static int autoconf_media(struct device *dev)
SICR_AUI
|
SICR_SRL
,
DE4X5_SICR
);
/* Wait 330ms */
for
(
i
=
0
;
i
<
t_330ms
;
i
++
)
{
dce_ms_delay
(
330
);
/* for (i=0; i<t_330ms; i++) {
sisr = inl(DE4X5_SISR);
}
*/
/* Make up a dummy packet with CRC error */
create_packet
(
dev
,
frame
,
sizeof
(
frame
));
...
...
@@ -1462,11 +1522,14 @@ static int autoconf_media(struct device *dev)
outl
(
SIGR_JCK
|
SIGR_HUJ
,
DE4X5_SIGR
);
outl
(
STRR_CLD
|
STRR_CSQ
|
STRR_RSQ
|
STRR_DREN
|
STRR_ECEN
,
DE4X5_STRR
);
outl
(
SICR_OE57
|
SICR_SEL
|
SICR_AUI
|
SICR_SRL
,
DE4X5_SICR
);
/* Wait 330ms */
dce_ms_delay
(
330
);
/* Setup the packet descriptor */
entry
=
lp
->
tx_new
;
/* Remember the ring position */
load_packet
(
dev
,
frame
,
TD_LS
|
TD_FS
|
TD_AC
|
sizeof
(
frame
),
NULL
);
/* Start the TX process */
omr
=
inl
(
DE4X5_OMR
);
outl
(
omr
|
OMR_ST
,
DE4X5_OMR
);
...
...
@@ -1535,6 +1598,60 @@ static void create_packet(struct device *dev, char *frame, int len)
return
;
}
/*
** Get the timer ticks from the PIT
*/
static
u_short
dce_get_ticks
(
void
)
{
u_short
ticks
=
0
;
/* Command 8254 to latch T0's count */
outb
(
TIMER_PORT
,
TIMER_LATCH
);
/* Read the counter */
ticks
=
inb
(
TIMER_READ
);
ticks
|=
(
inb
(
TIMER_READ
)
<<
8
);
return
ticks
;
}
/*
** Known delay in microseconds
*/
static
void
dce_us_delay
(
u_long
usec
)
{
u_long
i
,
start
,
now
,
quant
=
(
DELAY_QUANT
*
1000
)
/
TIMER_TICK
+
1
;
for
(
i
=
0
;
i
<
usec
/
DELAY_QUANT
;
i
++
)
{
start
=
dce_get_ticks
();
for
(
now
=
start
;
(
start
-
now
)
<
quant
;)
{
now
=
dce_get_ticks
();
if
(
now
>
start
)
{
/* Wrapped counter counting down */
quant
-=
start
;
start
=
(
1
<<
TIMER_WIDTH
);
}
}
}
return
;
}
/*
** Known delay in milliseconds
*/
static
void
dce_ms_delay
(
u_long
msec
)
{
u_long
i
;
for
(
i
=
0
;
i
<
msec
;
i
++
)
{
dce_us_delay
(
1000
);
}
return
;
}
/*
** Look for a particular board name in the EISA configuration space
*/
...
...
@@ -1563,72 +1680,61 @@ static void EISA_signature(char *name, short iobase)
strcpy
(
name
,
ManCode
);
}
}
return
;
/* return the device name string */
}
/*
** Look for a special sequence in the Ethernet station address PROM that
** is common across all DIGITAL network adapter products.
**
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the (length_of_the_signature - 1).
** Stop the search IMMEDIATELY after the signature is found so that the
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
static
int
DevicePresent
(
short
aprom_addr
)
{
static
short
fp
=
1
,
sigLength
=
0
;
static
char
devSig
[]
=
ETH_PROM_SIG
;
union
{
struct
{
u_long
a
;
u_long
b
;
}
llsig
;
char
Sig
[
sizeof
(
long
)
<<
1
];
}
dev
;
char
data
;
long
i
,
j
;
long
i
,
j
,
tmp
;
short
sigLength
;
int
status
=
0
;
struct
bus_type
*
lp
=
&
bus
;
static
char
asc2hex
(
char
value
);
/*
** Convert the ascii signature to a hex equivalent & pack in place
*/
if
(
fp
)
{
/* only do this once!... */
for
(
i
=
0
,
j
=
0
;
devSig
[
i
]
!=
'\0'
&&
!
status
;
i
+=
2
,
j
++
)
{
if
((
devSig
[
i
]
=
asc2hex
(
devSig
[
i
]))
>=
0
)
{
devSig
[
i
]
<<=
4
;
if
((
devSig
[
i
+
1
]
=
asc2hex
(
devSig
[
i
+
1
]))
>=
0
){
devSig
[
j
]
=
devSig
[
i
]
+
devSig
[
i
+
1
];
}
else
{
status
=
-
1
;
}
}
else
{
status
=
-
1
;
}
}
sigLength
=
j
;
fp
=
0
;
}
dev
.
llsig
.
a
=
ETH_PROM_SIG
;
dev
.
llsig
.
b
=
ETH_PROM_SIG
;
sigLength
=
sizeof
(
long
)
<<
1
;
/*
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the (length_of_the_signature - 1).
** Stop the search IMMEDIATELY after the signature is found so that the
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
if
(
!
status
)
{
long
tmp
;
for
(
i
=
0
,
j
=
0
;
j
<
sigLength
&&
i
<
PROBE_LENGTH
+
sigLength
-
1
;
i
++
)
{
if
(
lp
->
bus
==
PCI
)
{
while
((
tmp
=
inl
(
aprom_addr
))
<
0
);
data
=
(
char
)
tmp
;
for
(
i
=
0
,
j
=
0
;
j
<
sigLength
&&
i
<
PROBE_LENGTH
+
sigLength
-
1
;
i
++
)
{
if
(
lp
->
bus
==
PCI
)
{
while
((
tmp
=
inl
(
aprom_addr
))
<
0
);
data
=
(
char
)
tmp
;
}
else
{
data
=
inb
(
aprom_addr
);
}
if
(
dev
.
Sig
[
j
]
==
data
)
{
/* track signature */
j
++
;
}
else
{
/* lost signature; begin search again */
if
(
data
==
dev
.
Sig
[
0
])
{
j
=
1
;
}
else
{
data
=
inb
(
aprom_addr
);
}
if
(
devSig
[
j
]
==
data
)
{
/* track signature */
j
++
;
}
else
{
/* lost signature; begin search again */
j
=
0
;
}
}
}
if
(
j
!=
sigLength
)
{
status
=
-
ENODEV
;
/* search failed */
}
if
(
j
!=
sigLength
)
{
status
=
-
ENODEV
;
/* search failed */
}
return
status
;
...
...
@@ -1690,7 +1796,7 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
int
i
,
j
,
iobase
=
dev
->
base_addr
,
status
=
0
;
u_long
omr
;
union
{
unsigned
char
addr
[
HASH_TABLE_LEN
*
ETH_ALEN
];
unsigned
char
addr
[
(
HASH_TABLE_LEN
*
ETH_ALEN
)
];
unsigned
short
sval
[(
HASH_TABLE_LEN
*
ETH_ALEN
)
>>
1
];
unsigned
long
lval
[(
HASH_TABLE_LEN
*
ETH_ALEN
)
>>
2
];
}
tmp
;
...
...
@@ -1851,7 +1957,6 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
tmp
.
addr
[
j
++
]
=
dev
->
dev_addr
[
i
];
}
tmp
.
addr
[
j
++
]
=
lp
->
rxRingSize
;
tmp
.
lval
[
j
>>
2
]
=
eisa_slots_full
;
j
+=
4
;
tmp
.
lval
[
j
>>
2
]
=
(
long
)
lp
->
rx_ring
;
j
+=
4
;
tmp
.
lval
[
j
>>
2
]
=
(
long
)
lp
->
tx_ring
;
j
+=
4
;
...
...
@@ -1911,23 +2016,6 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd)
return
status
;
}
static
char
asc2hex
(
char
value
)
{
value
-=
0x30
;
/* normalise to 0..9 range */
if
(
value
>=
0
)
{
if
(
value
>
9
)
{
/* but may not be 10..15 */
value
&=
0x1f
;
/* make A..F & a..f be the same */
value
-=
0x07
;
/* normalise to 10..15 range */
if
((
value
<
0x0a
)
||
(
value
>
0x0f
))
{
/* if outside range then... */
value
=
-
1
;
/* ...signal error */
}
}
}
else
{
/* outside 0..9 range... */
value
=
-
1
;
/* ...signal error */
}
return
value
;
/* return hex char or error */
}
#ifdef MODULE
char
kernel_version
[]
=
UTS_RELEASE
;
static
struct
device
thisDE4X5
=
{
...
...
@@ -1936,7 +2024,7 @@ static struct device thisDE4X5 = {
0x2000
,
10
,
/* I/O address, IRQ */
0
,
0
,
0
,
NULL
,
de4x5_probe
};
int
io
=
0x
2000
;
/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
int
io
=
0x
000b
;
/* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
int
irq
=
10
;
/* or use the insmod io= irq= options */
int
...
...
@@ -1952,9 +2040,20 @@ init_module(void)
void
cleanup_module
(
void
)
{
struct
de4x5_private
*
lp
=
(
struct
de4x5_private
*
)
thisDE4X5
.
priv
;
if
(
MOD_IN_USE
)
{
printk
(
"%s: device busy, remove delayed
\n
"
,
thisDE4X5
.
name
);
}
else
{
release_region
(
thisDE4X5
.
base_addr
,
(
lp
->
bus
==
PCI
?
DE4X5_PCI_TOTAL_SIZE
:
DE4X5_EISA_TOTAL_SIZE
));
if
(
lp
)
{
kfree_s
(
lp
->
rx_ring
[
0
].
buf
,
RX_BUFF_SZ
*
NUM_RX_DESC
+
LWPAD
);
}
kfree_s
(
thisDE4X5
.
priv
,
sizeof
(
struct
de4x5_private
)
+
LWPAD
);
thisDE4X5
.
priv
=
NULL
;
unregister_netdev
(
&
thisDE4X5
);
}
}
...
...
@@ -1970,4 +2069,3 @@ cleanup_module(void)
*/
drivers/net/depca.c
View file @
55415e93
...
...
@@ -137,7 +137,7 @@
To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod depca'.
[Alan Cox: Changed to split off the module values as ints for insmod
you can now do insmod depca.c irq=7 io=0x200 ]
...
...
@@ -168,20 +168,24 @@
0.37 22-jul-94 Added MODULE support
0.38 15-aug-94 Added DBR ROM switch in depca_close().
Multi DEPCA bug fix.
0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0
0.381 12-dec-94 Added DE101 recognition, fix multicast bug
0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0.
0.381 12-dec-94 Added DE101 recognition, fix multicast bug.
0.382 9-feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
=========================================================================
*/
static
char
*
version
=
"depca.c:v0.38
1 12/12
/94 davies@wanton.lkg.dec.com
\n
"
;
static
char
*
version
=
"depca.c:v0.38
2 2/9
/94 davies@wanton.lkg.dec.com
\n
"
;
#include <linux/config.h>
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#endif
/* MODULE */
#include <stdarg.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
...
...
@@ -210,9 +214,7 @@ static int depca_debug = 1;
#define PROBE_LENGTH 32
#endif
#ifndef PROBE_SEQUENCE
#define PROBE_SEQUENCE "FF0055AAFF0055AA"
#endif
#define ETH_PROM_SIG 0xAA5500FFUL
#ifndef DEPCA_SIGNATURE
#define DEPCA_SIGNATURE {"DEPCA",\
...
...
@@ -274,13 +276,13 @@ static short mem_chkd = 0; /* holds which base addrs have been */
** The DEPCA Rx and Tx ring descriptors.
*/
struct
depca_rx_head
{
long
base
;
volatile
long
base
;
short
buf_length
;
/* This length is negative 2's complement! */
short
msg_length
;
/* This length is "normal". */
};
struct
depca_tx_head
{
long
base
;
volatile
long
base
;
short
length
;
/* This length is negative 2's complement! */
short
misc
;
/* Errors and TDR info */
};
...
...
@@ -479,9 +481,7 @@ depca_probe1(struct device *dev, short ioaddr)
j
=
inb
(
DEPCA_PROM
);
}
#ifdef HAVE_PORTRESERVE
request_region
(
ioaddr
,
DEPCA_TOTAL_SIZE
,
"depca"
);
#endif
request_region
(
ioaddr
,
DEPCA_TOTAL_SIZE
,
dev
->
name
);
/*
** Set up the maximum amount of network RAM(kB)
...
...
@@ -762,9 +762,7 @@ depca_open(struct device *dev)
printk
(
"nicsr: 0x%02x
\n
"
,
inb
(
DEPCA_NICSR
));
}
#ifdef MODULE
MOD_INC_USE_COUNT
;
#endif
MOD_INC_USE_COUNT
;
return
0
;
/* Always succeed */
}
...
...
@@ -1176,9 +1174,7 @@ depca_close(struct device *dev)
irq2dev_map
[
dev
->
irq
]
=
0
;
#ifdef MODULE
MOD_DEC_USE_COUNT
;
#endif
return
0
;
}
...
...
@@ -1452,98 +1448,61 @@ static char *DepcaSignature(unsigned long mem_addr)
** its ROM address counter to be initialized and enabled. Only enable
** if the first address octet is a 0x08 - this minimises the chances of
** messing around with some other hardware, but it assumes that this DEPCA
** card initialized itself correctly. It also assumes that all past and
** future DEPCA/EtherWORKS cards will have ethernet addresses beginning with
** a 0x08.
** card initialized itself correctly.
**
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the (length_of_the_signature - 1).
** Stop the search IMMEDIATELY after the signature is found so that the
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
static
int
DevicePresent
(
short
ioaddr
)
{
static
short
fp
=
1
,
sigLength
=
0
;
static
char
devSig
[]
=
PROBE_SEQUENCE
;
union
{
struct
{
u_long
a
;
u_long
b
;
}
llsig
;
char
Sig
[
sizeof
(
long
)
<<
1
];
}
dev
;
short
sigLength
=
0
;
char
data
;
int
i
,
j
,
nicsr
,
status
=
0
;
static
char
asc2hex
(
char
value
);
/*
** Initialize the counter on a DEPCA card. Two reads to ensure DEPCA ethernet
** address counter is a) cleared and b) the correct data read.
*/
data
=
inb
(
DEPCA_PROM
);
/* clear counter */
data
=
inb
(
DEPCA_PROM
);
/* clear counter on DEPCA */
data
=
inb
(
DEPCA_PROM
);
/* read data */
/*
** Enable counter
*/
if
(
data
==
0x08
)
{
if
(
data
==
0x08
)
{
/* Enable counter on DEPCA */
nicsr
=
inb
(
DEPCA_NICSR
);
nicsr
|=
AAC
;
outb
(
nicsr
,
DEPCA_NICSR
);
}
/*
** Convert the ascii signature to a hex equivalent & pack in place
*/
if
(
fp
)
{
/* only do this once!... */
for
(
i
=
0
,
j
=
0
;
devSig
[
i
]
!=
'\0'
&&
!
status
;
i
+=
2
,
j
++
)
{
if
((
devSig
[
i
]
=
asc2hex
(
devSig
[
i
]))
>=
0
)
{
devSig
[
i
]
<<=
4
;
if
((
devSig
[
i
+
1
]
=
asc2hex
(
devSig
[
i
+
1
]))
>=
0
){
devSig
[
j
]
=
devSig
[
i
]
+
devSig
[
i
+
1
];
}
else
{
status
=
-
1
;
}
dev
.
llsig
.
a
=
ETH_PROM_SIG
;
dev
.
llsig
.
b
=
ETH_PROM_SIG
;
sigLength
=
sizeof
(
long
)
<<
1
;
for
(
i
=
0
,
j
=
0
;
j
<
sigLength
&&
i
<
PROBE_LENGTH
+
sigLength
-
1
;
i
++
)
{
data
=
inb
(
DEPCA_PROM
);
if
(
dev
.
Sig
[
j
]
==
data
)
{
/* track signature */
j
++
;
}
else
{
/* lost signature; begin search again */
if
(
data
==
dev
.
Sig
[
0
])
{
/* rare case.... */
j
=
1
;
}
else
{
status
=
-
1
;
}
}
sigLength
=
j
;
fp
=
0
;
}
/*
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the (length_of_the_signature - 1).
** Stop the search IMMEDIATELY after the signature is found so that the
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
if
(
!
status
)
{
for
(
i
=
0
,
j
=
0
;
j
<
sigLength
&&
i
<
PROBE_LENGTH
+
sigLength
-
1
;
i
++
)
{
data
=
inb
(
DEPCA_PROM
);
if
(
devSig
[
j
]
==
data
)
{
/* track signature */
j
++
;
}
else
{
/* lost signature; begin search again */
j
=
0
;
}
}
}
if
(
j
!=
sigLength
)
{
status
=
-
ENODEV
;
/* search failed */
}
if
(
j
!=
sigLength
)
{
status
=
-
ENODEV
;
/* search failed */
}
return
status
;
}
static
char
asc2hex
(
char
value
)
{
value
-=
0x30
;
/* normalise to 0..9 range */
if
(
value
>=
0
)
{
if
(
value
>
9
)
{
/* but may not be 10..15 */
value
&=
0x1f
;
/* make A..F & a..f be the same */
value
-=
0x07
;
/* normalise to 10..15 range */
if
((
value
<
0x0a
)
||
(
value
>
0x0f
))
{
/* if outside range then... */
value
=
-
1
;
/* ...signal error */
}
}
}
else
{
/* outside 0..9 range... */
value
=
-
1
;
/* ...signal error */
}
return
value
;
/* return hex char or error */
}
#ifdef MODULE
char
kernel_version
[]
=
UTS_RELEASE
;
static
struct
device
thisDepca
=
{
...
...
@@ -1576,6 +1535,7 @@ cleanup_module(void)
if
(
MOD_IN_USE
)
{
printk
(
"%s: device busy, remove delayed
\n
"
,
thisDepca
.
name
);
}
else
{
release_region
(
thisDepca
.
base_addr
,
DEPCA_TOTAL_SIZE
);
unregister_netdev
(
&
thisDepca
);
}
}
...
...
drivers/net/plip.c
View file @
55415e93
/* $Id: plip.c,v 1.1
0 1995/02/08 05:47:12
gniibe Exp $ */
/* $Id: plip.c,v 1.1
2 1995/02/11 10:26:05
gniibe Exp $ */
/* PLIP: A parallel port "network" driver for Linux. */
/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
/*
...
...
@@ -163,7 +163,29 @@ enum plip_nibble_state {
struct
plip_local
{
enum
plip_packet_state
state
;
enum
plip_nibble_state
nibble
;
unsigned
short
length
;
union
{
struct
{
#if defined(__i386__)
unsigned
char
lsb
;
unsigned
char
msb
;
#elif defined(__mc68000__)
unsigned
char
msb
;
unsigned
char
lsb
;
#elif defined(__MIPSEL__)
unsigned
char
lsb
;
unsigned
char
msb
;
#elif defined(__MIPSEB__)
unsigned
char
msb
;
unsigned
char
lsb
;
#elif defined(__alpha__)
unsigned
char
lsb
;
unsigned
char
msb
;
#else
#error "Adjust this structure to match your CPU"
#endif
}
b
;
unsigned
short
h
;
}
length
;
unsigned
short
byte
;
unsigned
char
checksum
;
unsigned
char
data
;
...
...
@@ -178,10 +200,11 @@ struct net_local {
struct
plip_local
rcv_data
;
unsigned
long
trigger
;
unsigned
long
nibble
;
unsigned
long
unit
;
enum
plip_connection_state
connection
;
unsigned
short
timeout_count
;
char
is_deferred
;
int
(
*
orig_rebuild_header
)(
void
*
eth
,
struct
device
*
dev
,
unsigned
long
raddr
,
struct
sk_buff
*
skb
);
};
/* Entry point of PLIP driver.
...
...
@@ -235,24 +258,27 @@ plip_init(struct device *dev)
ether_setup
(
dev
);
/* Then, override parts of it */
dev
->
rebuild_header
=
plip_rebuild_header
;
dev
->
hard_start_xmit
=
plip_tx_packet
;
dev
->
open
=
plip_open
;
dev
->
stop
=
plip_close
;
dev
->
get_stats
=
plip_get_stats
;
dev
->
set_config
=
plip_config
;
dev
->
do_ioctl
=
plip_ioctl
;
dev
->
flags
=
IFF_POINTOPOINT
;
dev
->
flags
=
IFF_POINTOPOINT
|
IFF_NOARP
;
/* Set the private structure */
dev
->
priv
=
kmalloc
(
sizeof
(
struct
net_local
),
GFP_KERNEL
);
if
(
dev
->
priv
==
NULL
)
return
EAGAIN
;
memset
(
dev
->
priv
,
0
,
sizeof
(
struct
net_local
));
nl
=
(
struct
net_local
*
)
dev
->
priv
;
nl
->
orig_rebuild_header
=
dev
->
rebuild_header
;
dev
->
rebuild_header
=
plip_rebuild_header
;
/* Initialize constants */
nl
->
trigger
=
PLIP_TRIGGER_WAIT
;
nl
->
nibble
=
PLIP_NIBBLE_WAIT
;
nl
->
unit
=
PLIP_DELAY_UNIT
;
/* Initialize task queue structures */
nl
->
immediate
.
next
=
&
tq_last
;
...
...
@@ -407,8 +433,7 @@ plip_none(struct device *dev, struct net_local *nl,
/* PLIP_RECEIVE --- receive a byte(two nibbles)
Returns OK on success, TIMEOUT on timeout */
inline
static
int
plip_receive
(
unsigned
short
nibble_timeout
,
unsigned
short
unit
,
unsigned
short
status_addr
,
unsigned
short
data_addr
,
plip_receive
(
unsigned
short
nibble_timeout
,
unsigned
short
status_addr
,
enum
plip_nibble_state
*
ns_p
,
unsigned
char
*
data_p
)
{
unsigned
char
c0
,
c1
;
...
...
@@ -419,7 +444,7 @@ plip_receive(unsigned short nibble_timeout, unsigned short unit,
cx
=
nibble_timeout
;
while
(
1
)
{
c0
=
inb
(
status_addr
);
udelay
(
unit
);
udelay
(
PLIP_DELAY_UNIT
);
if
((
c0
&
0x80
)
==
0
)
{
c1
=
inb
(
status_addr
);
if
(
c0
==
c1
)
...
...
@@ -429,14 +454,15 @@ plip_receive(unsigned short nibble_timeout, unsigned short unit,
return
TIMEOUT
;
}
*
data_p
=
(
c0
>>
3
)
&
0x0f
;
outb
(
0x10
,
data_addr
);
/* send ACK */
outb
(
0x10
,
--
status_addr
);
/* send ACK */
status_addr
++
;
*
ns_p
=
PLIP_NB_1
;
case
PLIP_NB_1
:
cx
=
nibble_timeout
;
while
(
1
)
{
c0
=
inb
(
status_addr
);
udelay
(
unit
);
udelay
(
PLIP_DELAY_UNIT
);
if
(
c0
&
0x80
)
{
c1
=
inb
(
status_addr
);
if
(
c0
==
c1
)
...
...
@@ -446,7 +472,8 @@ plip_receive(unsigned short nibble_timeout, unsigned short unit,
return
TIMEOUT
;
}
*
data_p
|=
(
c0
<<
1
)
&
0xf0
;
outb
(
0x00
,
data_addr
);
/* send ACK */
outb
(
0x00
,
--
status_addr
);
/* send ACK */
status_addr
++
;
*
ns_p
=
PLIP_NB_BEGIN
;
return
OK
;
...
...
@@ -459,9 +486,8 @@ static int
plip_receive_packet
(
struct
device
*
dev
,
struct
net_local
*
nl
,
struct
plip_local
*
snd
,
struct
plip_local
*
rcv
)
{
unsigned
short
data_addr
=
PAR_DATA
(
dev
),
status_addr
=
PAR_STATUS
(
dev
);
unsigned
short
nibble_timeout
=
nl
->
nibble
,
unit
=
nl
->
unit
;
unsigned
short
status_addr
=
PAR_STATUS
(
dev
);
unsigned
short
nibble_timeout
=
nl
->
nibble
;
unsigned
char
*
lbuf
;
switch
(
rcv
->
state
)
{
...
...
@@ -477,9 +503,8 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
case
PLIP_PK_LENGTH_LSB
:
if
(
snd
->
state
!=
PLIP_PK_DONE
)
{
if
(
plip_receive
(
nl
->
trigger
,
unit
,
status_addr
,
data_addr
,
&
rcv
->
nibble
,
(
unsigned
char
*
)
&
rcv
->
length
))
{
if
(
plip_receive
(
nl
->
trigger
,
status_addr
,
&
rcv
->
nibble
,
&
rcv
->
length
.
b
.
lsb
))
{
/* collision, here dev->tbusy == 1 */
rcv
->
state
=
PLIP_PK_DONE
;
nl
->
is_deferred
=
1
;
...
...
@@ -490,29 +515,27 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
return
OK
;
}
}
else
{
if
(
plip_receive
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
&
rcv
->
nibble
,
(
unsigned
char
*
)
&
rcv
->
length
))
if
(
plip_receive
(
nibble_timeout
,
status_addr
,
&
rcv
->
nibble
,
&
rcv
->
length
.
b
.
lsb
))
return
TIMEOUT
;
}
rcv
->
state
=
PLIP_PK_LENGTH_MSB
;
case
PLIP_PK_LENGTH_MSB
:
if
(
plip_receive
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
&
rcv
->
nibble
,
(
unsigned
char
*
)
&
rcv
->
length
+
1
))
if
(
plip_receive
(
nibble_timeout
,
status_addr
,
&
rcv
->
nibble
,
&
rcv
->
length
.
b
.
msb
))
return
TIMEOUT
;
if
(
rcv
->
length
>
dev
->
mtu
||
rcv
->
lengt
h
<
8
)
{
printk
(
"%s: bogus packet size %d.
\n
"
,
dev
->
name
,
rcv
->
length
);
if
(
rcv
->
length
.
h
>
dev
->
mtu
||
rcv
->
length
.
h
<
8
)
{
printk
(
"%s: bogus packet size %d.
\n
"
,
dev
->
name
,
rcv
->
length
.
h
);
return
ERROR
;
}
/* Malloc up new buffer. */
rcv
->
skb
=
alloc_skb
(
rcv
->
length
,
GFP_ATOMIC
);
rcv
->
skb
=
alloc_skb
(
rcv
->
length
.
h
,
GFP_ATOMIC
);
if
(
rcv
->
skb
==
NULL
)
{
printk
(
"%s: Memory squeeze.
\n
"
,
dev
->
name
);
return
ERROR
;
}
rcv
->
skb
->
len
=
rcv
->
length
;
rcv
->
skb
->
len
=
rcv
->
length
.
h
;
rcv
->
skb
->
dev
=
dev
;
rcv
->
state
=
PLIP_PK_DATA
;
rcv
->
byte
=
0
;
...
...
@@ -520,18 +543,19 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
case
PLIP_PK_DATA
:
lbuf
=
rcv
->
skb
->
data
;
do
{
if
(
plip_receive
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
do
if
(
plip_receive
(
nibble_timeout
,
status_addr
,
&
rcv
->
nibble
,
&
lbuf
[
rcv
->
byte
]))
return
TIMEOUT
;
rcv
->
checksum
+=
lbuf
[
rcv
->
byte
];
}
while
(
++
rcv
->
byte
<
rcv
->
length
);
while
(
++
rcv
->
byte
<
rcv
->
length
.
h
);
do
rcv
->
checksum
+=
lbuf
[
--
rcv
->
byte
];
while
(
rcv
->
byte
);
rcv
->
state
=
PLIP_PK_CHECKSUM
;
case
PLIP_PK_CHECKSUM
:
if
(
plip_receive
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
&
rcv
->
nibble
,
&
rcv
->
data
))
if
(
plip_receive
(
nibble_timeout
,
status_addr
,
&
rcv
->
nibble
,
&
rcv
->
data
))
return
TIMEOUT
;
if
(
rcv
->
data
!=
rcv
->
checksum
)
{
nl
->
enet_stats
.
rx_crc_errors
++
;
...
...
@@ -573,8 +597,7 @@ plip_receive_packet(struct device *dev, struct net_local *nl,
/* PLIP_SEND --- send a byte (two nibbles)
Returns OK on success, TIMEOUT when timeout */
inline
static
int
plip_send
(
unsigned
short
nibble_timeout
,
unsigned
short
unit
,
unsigned
short
status_addr
,
unsigned
short
data_addr
,
plip_send
(
unsigned
short
nibble_timeout
,
unsigned
short
data_addr
,
enum
plip_nibble_state
*
ns_p
,
unsigned
char
data
)
{
unsigned
char
c0
;
...
...
@@ -588,28 +611,31 @@ plip_send(unsigned short nibble_timeout, unsigned short unit,
case
PLIP_NB_1
:
outb
(
0x10
|
(
data
&
0x0f
),
data_addr
);
cx
=
nibble_timeout
;
data_addr
++
;
while
(
1
)
{
c0
=
inb
(
status
_addr
);
c0
=
inb
(
data
_addr
);
if
((
c0
&
0x80
)
==
0
)
break
;
if
(
--
cx
==
0
)
return
TIMEOUT
;
udelay
(
unit
);
udelay
(
PLIP_DELAY_UNIT
);
}
outb
(
0x10
|
(
data
>>
4
),
data_addr
);
outb
(
0x10
|
(
data
>>
4
),
--
data_addr
);
*
ns_p
=
PLIP_NB_2
;
case
PLIP_NB_2
:
outb
((
data
>>
4
),
data_addr
);
data_addr
++
;
cx
=
nibble_timeout
;
while
(
1
)
{
c0
=
inb
(
status
_addr
);
c0
=
inb
(
data
_addr
);
if
(
c0
&
0x80
)
break
;
if
(
--
cx
==
0
)
return
TIMEOUT
;
udelay
(
unit
);
udelay
(
PLIP_DELAY_UNIT
);
}
data_addr
--
;
*
ns_p
=
PLIP_NB_BEGIN
;
return
OK
;
}
...
...
@@ -620,9 +646,8 @@ static int
plip_send_packet
(
struct
device
*
dev
,
struct
net_local
*
nl
,
struct
plip_local
*
snd
,
struct
plip_local
*
rcv
)
{
unsigned
short
data_addr
=
PAR_DATA
(
dev
),
status_addr
=
PAR_STATUS
(
dev
);
unsigned
short
nibble_timeout
=
nl
->
nibble
,
unit
=
nl
->
unit
;
unsigned
short
data_addr
=
PAR_DATA
(
dev
);
unsigned
short
nibble_timeout
=
nl
->
nibble
;
unsigned
char
*
lbuf
;
unsigned
char
c0
;
unsigned
int
cx
;
...
...
@@ -637,10 +662,10 @@ plip_send_packet(struct device *dev, struct net_local *nl,
switch
(
snd
->
state
)
{
case
PLIP_PK_TRIGGER
:
/* Trigger remote rx interrupt. */
outb
(
0x08
,
PAR_DATA
(
dev
)
);
outb
(
0x08
,
data_addr
);
cx
=
nl
->
trigger
;
while
(
1
)
{
udelay
(
nl
->
unit
);
udelay
(
PLIP_DELAY_UNIT
);
cli
();
if
(
nl
->
connection
==
PLIP_CN_RECEIVE
)
{
sti
();
...
...
@@ -664,37 +689,38 @@ plip_send_packet(struct device *dev, struct net_local *nl,
}
sti
();
if
(
--
cx
==
0
)
{
outb
(
0x00
,
PAR_DATA
(
dev
)
);
outb
(
0x00
,
data_addr
);
return
TIMEOUT
;
}
}
case
PLIP_PK_LENGTH_LSB
:
if
(
plip_send
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
&
snd
->
nibble
,
snd
->
length
&
0xff
))
if
(
plip_send
(
nibble_timeout
,
data_addr
,
&
snd
->
nibble
,
snd
->
length
.
b
.
lsb
))
return
TIMEOUT
;
snd
->
state
=
PLIP_PK_LENGTH_MSB
;
case
PLIP_PK_LENGTH_MSB
:
if
(
plip_send
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
&
snd
->
nibble
,
snd
->
length
>>
8
))
if
(
plip_send
(
nibble_timeout
,
data_addr
,
&
snd
->
nibble
,
snd
->
length
.
b
.
msb
))
return
TIMEOUT
;
snd
->
state
=
PLIP_PK_DATA
;
snd
->
byte
=
0
;
snd
->
checksum
=
0
;
case
PLIP_PK_DATA
:
do
{
if
(
plip_send
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
do
if
(
plip_send
(
nibble_timeout
,
data_addr
,
&
snd
->
nibble
,
lbuf
[
snd
->
byte
]))
return
TIMEOUT
;
snd
->
checksum
+=
lbuf
[
snd
->
byte
];
}
while
(
++
snd
->
byte
<
snd
->
length
);
while
(
++
snd
->
byte
<
snd
->
length
.
h
);
do
snd
->
checksum
+=
lbuf
[
--
snd
->
byte
];
while
(
snd
->
byte
);
snd
->
state
=
PLIP_PK_CHECKSUM
;
case
PLIP_PK_CHECKSUM
:
if
(
plip_send
(
nibble_timeout
,
unit
,
status_addr
,
data_addr
,
if
(
plip_send
(
nibble_timeout
,
data_addr
,
&
snd
->
nibble
,
snd
->
checksum
))
return
TIMEOUT
;
...
...
@@ -704,7 +730,7 @@ plip_send_packet(struct device *dev, struct net_local *nl,
case
PLIP_PK_DONE
:
/* Close the connection */
outb
(
0x00
,
PAR_DATA
(
dev
)
);
outb
(
0x00
,
data_addr
);
snd
->
skb
=
NULL
;
if
(
net_debug
>
2
)
printk
(
"%s: send end
\n
"
,
dev
->
name
);
...
...
@@ -816,9 +842,13 @@ static int
plip_rebuild_header
(
void
*
buff
,
struct
device
*
dev
,
unsigned
long
dst
,
struct
sk_buff
*
skb
)
{
struct
net_local
*
nl
=
(
struct
net_local
*
)
dev
->
priv
;
struct
ethhdr
*
eth
=
(
struct
ethhdr
*
)
buff
;
int
i
;
if
((
dev
->
flags
&
IFF_NOARP
)
==
0
)
return
nl
->
orig_rebuild_header
(
buff
,
dev
,
dst
,
skb
);
if
(
eth
->
h_proto
!=
htons
(
ETH_P_IP
))
{
printk
(
"plip_rebuild_header: Don't know how to resolve type %d addresses?
\n
"
,
(
int
)
eth
->
h_proto
);
memcpy
(
eth
->
h_source
,
dev
->
dev_addr
,
dev
->
addr_len
);
...
...
@@ -865,7 +895,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
cli
();
dev
->
trans_start
=
jiffies
;
snd
->
skb
=
skb
;
snd
->
length
=
skb
->
len
;
snd
->
length
.
h
=
skb
->
len
;
snd
->
state
=
PLIP_PK_TRIGGER
;
if
(
nl
->
connection
==
PLIP_CN_NONE
)
{
nl
->
connection
=
PLIP_CN_SEND
;
...
...
@@ -997,12 +1027,10 @@ plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
case
PLIP_GET_TIMEOUT
:
pc
->
trigger
=
nl
->
trigger
;
pc
->
nibble
=
nl
->
nibble
;
pc
->
unit
=
nl
->
unit
;
break
;
case
PLIP_SET_TIMEOUT
:
nl
->
trigger
=
pc
->
trigger
;
nl
->
nibble
=
pc
->
nibble
;
nl
->
unit
=
pc
->
unit
;
break
;
default:
return
-
EOPNOTSUPP
;
...
...
drivers/scsi/eata.c
View file @
55415e93
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
* 9 Feb 1995 rev. 1.16 for linux 1.1.90
* Use host->wish_block instead of host->block.
* New list of Data Out SCSI commands.
*
* 8 Feb 1995 rev. 1.15 for linux 1.1.89
* Cleared target_time_out counter while p
re
forming a reset.
* Cleared target_time_out counter while p
er
forming a reset.
* All external symbols renamed to avoid possible name conflicts.
*
* 28 Jan 1995 rev. 1.14 for linux 1.1.86
...
...
@@ -88,7 +92,7 @@
* CACHE : DISABLED
*
* In order to support multiple ISA boards in a reliable way,
* the driver sets host->block = TRUE for all ISA boards.
* the driver sets host->
wish_
block = TRUE for all ISA boards.
*/
#if defined(MODULE)
...
...
@@ -167,6 +171,8 @@
#define ASOK 0x00
#define ASST 0x01
#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
/* "EATA", in Big Endian format */
#define EATA_SIGNATURE 0x41544145
...
...
@@ -466,7 +472,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
if
(
HD
(
j
)
->
subversion
==
ESA
)
sh
[
j
]
->
unchecked_isa_dma
=
FALSE
;
else
{
sh
[
j
]
->
block
=
sh
[
j
]
;
sh
[
j
]
->
wish_block
=
TRUE
;
sh
[
j
]
->
unchecked_isa_dma
=
TRUE
;
disable_dma
(
dma_channel
);
clear_dma_ff
(
dma_channel
);
...
...
@@ -562,6 +568,12 @@ int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
struct
mscp
*
cpp
;
struct
mssp
*
spp
;
static
const
unsigned
char
data_out_cmds
[]
=
{
0x0a
,
0x2a
,
0x15
,
0x55
,
0x04
,
0x07
,
0x0b
,
0x10
,
0x16
,
0x18
,
0x1d
,
0x24
,
0x2b
,
0x2e
,
0x30
,
0x31
,
0x32
,
0x38
,
0x39
,
0x3a
,
0x3b
,
0x3d
,
0x3f
,
0x40
,
0x41
,
0x4c
,
0xaa
,
0xae
,
0xb0
,
0xb1
,
0xb2
,
0xb6
,
0xea
};
save_flags
(
flags
);
cli
();
/* j is the board number */
...
...
@@ -619,11 +631,13 @@ int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
if
(
do_trace
)
printk
(
"%s: qcomm, mbox %d, target %d, pid %ld.
\n
"
,
BN
(
j
),
i
,
SCpnt
->
target
,
SCpnt
->
pid
);
if
(
SCpnt
->
cmnd
[
0
]
==
WRITE_10
||
SCpnt
->
cmnd
[
0
]
==
WRITE_6
)
cpp
->
dout
=
TRUE
;
else
cpp
->
din
=
TRUE
;
for
(
k
=
0
;
k
<
ARRAY_SIZE
(
data_out_cmds
);
k
++
)
if
(
SCpnt
->
cmnd
[
0
]
==
data_out_cmds
[
k
])
{
cpp
->
dout
=
TRUE
;
break
;
}
cpp
->
din
=
!
cpp
->
dout
;
cpp
->
reqsen
=
TRUE
;
cpp
->
dispri
=
TRUE
;
cpp
->
one
=
TRUE
;
...
...
drivers/scsi/eata.h
View file @
55415e93
...
...
@@ -7,7 +7,7 @@
#include <linux/scsicam.h>
#define EATA_VERSION "1.1
5
.00"
#define EATA_VERSION "1.1
6
.00"
int
eata2x_detect
(
Scsi_Host_Template
*
);
int
eata2x_queuecommand
(
Scsi_Cmnd
*
,
void
(
*
done
)(
Scsi_Cmnd
*
));
...
...
drivers/scsi/hosts.c
View file @
55415e93
...
...
@@ -241,6 +241,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
(
tpnt
->
unchecked_isa_dma
&&
j
?
GFP_DMA
:
0
)
|
GFP_ATOMIC
);
retval
->
host_busy
=
0
;
retval
->
block
=
NULL
;
retval
->
wish_block
=
0
;
if
(
j
>
0xffff
)
panic
(
"Too many extra bytes requested
\n
"
);
retval
->
extra_bytes
=
j
;
retval
->
loaded_as_module
=
scsi_loadable_module_flag
;
...
...
drivers/scsi/hosts.h
View file @
55415e93
...
...
@@ -243,6 +243,7 @@ struct Scsi_Host
that should be locked out of performing I/O while we have an active
command on this host. */
struct
Scsi_Host
*
block
;
unsigned
wish_block
:
1
;
/* These parameters should be set by the detect routine */
unsigned
char
*
base
;
...
...
drivers/scsi/scsi.c
View file @
55415e93
...
...
@@ -212,10 +212,7 @@ void scsi_make_blocked_list(void) {
/*
* Create a circular linked list from the scsi hosts which have
* the "block" field in the Scsi_Host structure set to any value
* different from NULL.
* If there is only one host such that host->block != NULL, the list is
* empty and host->block is reset to NULL.
* the "wish_block" field in the Scsi_Host structure set.
* The blocked list should include all the scsi hosts using ISA DMA.
* In some systems, using two dma channels simultaneously causes
* unpredictable results.
...
...
@@ -243,10 +240,10 @@ void scsi_make_blocked_list(void) {
* Useful to put into the blocked list all the hosts whose driver
* does not know about the host->block feature.
*/
if (shpnt->unchecked_isa_dma) shpnt->
block = shpnt
;
if (shpnt->unchecked_isa_dma) shpnt->
wish_block = 1
;
#endif
if
(
shpnt
->
block
)
sh
[
block_count
++
]
=
shpnt
;
if
(
shpnt
->
wish_
block
)
sh
[
block_count
++
]
=
shpnt
;
}
if
(
block_count
==
1
)
sh
[
0
]
->
block
=
NULL
;
...
...
drivers/scsi/sg.c
View file @
55415e93
...
...
@@ -374,7 +374,7 @@ static void sg_init()
memset
(
scsi_generics
,
0
,
(
sg_template
.
dev_noticed
+
SG_EXTRA_DEVS
)
*
sizeof
(
struct
scsi_generic
));
sg_template
.
dev_max
=
sg_template
.
dev_noticed
;
sg_template
.
dev_max
=
sg_template
.
dev_noticed
+
SG_EXTRA_DEVS
;
}
static
int
sg_attach
(
Scsi_Device
*
SDp
)
...
...
drivers/scsi/u14-34f.c
View file @
55415e93
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
* 9 Feb 1995 rev. 1.16 for linux 1.1.90
* Use host->wish_block instead of host->block.
*
* 8 Feb 1995 rev. 1.15 for linux 1.1.89
* Cleared target_time_out counter while p
re
forming a reset.
* Cleared target_time_out counter while p
er
forming a reset.
*
* 28 Jan 1995 rev. 1.14 for linux 1.1.86
* Added module support.
...
...
@@ -111,7 +114,7 @@
* The new firmware has fixed all the above problems.
*
* In order to support multiple ISA boards in a reliable way,
* the driver sets host->block = TRUE for all ISA boards.
* the driver sets host->
wish_
block = TRUE for all ISA boards.
*/
#if defined(MODULE)
...
...
@@ -428,7 +431,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
sprintf
(
BN
(
j
),
"U34F%d"
,
j
);
}
else
{
sh
[
j
]
->
block
=
sh
[
j
]
;
sh
[
j
]
->
wish_block
=
TRUE
;
#if defined (HAVE_OLD_U14F_FIRMWARE)
sh
[
j
]
->
hostt
->
use_clustering
=
DISABLE_CLUSTERING
;
...
...
drivers/scsi/u14-34f.h
View file @
55415e93
...
...
@@ -10,7 +10,7 @@ int u14_34f_abort(Scsi_Cmnd *);
int
u14_34f_reset
(
Scsi_Cmnd
*
);
int
u14_34f_biosparam
(
Disk
*
,
int
,
int
*
);
#define U14_34F_VERSION "1.1
5
.00"
#define U14_34F_VERSION "1.1
6
.00"
#define ULTRASTOR_14_34F { \
NULL,
/* Ptr for modules */
\
...
...
drivers/sound/Readme
View file @
55415e93
...
...
@@ -79,7 +79,7 @@ Snail mail: Hannu Savolainen
Finland
FAX: +358 0 341 6272 (answers if I have my machine (mgetty) on).
NOTE! I pro
p
ably don't answer to Snail mail or FAX messages. Sending answer
NOTE! I pro
b
ably don't answer to Snail mail or FAX messages. Sending answer
to each of them is simply too expensive and time consuming. However I
try to reply every email message I get (within a week). If you don't
get response, please check how your address is written in the message
...
...
fs/proc/inode.c
View file @
55415e93
...
...
@@ -140,17 +140,17 @@ void proc_read_inode(struct inode * inode)
}
#ifdef CONFIG_IP_ACCT
/*
be careful: /proc/net/ip_acct_0 resets IP
accounting */
if
(
ino
==
PROC_NET_IPACCT
0
)
{
inode
->
i_mode
=
S_IFREG
|
S_IRUSR
;
/*
this file may be opened R/W by root to reset the
accounting */
if
(
ino
==
PROC_NET_IPACCT
)
{
inode
->
i_mode
=
S_IFREG
|
S_IRU
GO
|
S_IWU
SR
;
inode
->
i_op
=
&
proc_net_inode_operations
;
return
;
}
#endif
#ifdef CONFIG_IP_FIREWALL
/*
/proc/net/ip_forward_0 and /proc/net/ip_block_0 reset
counters */
if
((
ino
==
PROC_NET_IPFWFWD
0
)
||
(
ino
==
PROC_NET_IPFWBLK0
))
{
inode
->
i_mode
=
S_IFREG
|
S_IRUSR
;
/*
these files may be opened R/W by root to reset the
counters */
if
((
ino
==
PROC_NET_IPFWFWD
)
||
(
ino
==
PROC_NET_IPFWBLK
))
{
inode
->
i_mode
=
S_IFREG
|
S_IRU
GO
|
S_IWU
SR
;
inode
->
i_op
=
&
proc_net_inode_operations
;
return
;
}
...
...
fs/proc/net.c
View file @
55415e93
...
...
@@ -32,6 +32,7 @@
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/config.h>
#include <linux/mm.h>
...
...
@@ -59,14 +60,11 @@ extern int afinet_get_info(char *, char **, off_t, int);
extern
int
wavelan_get_info
(
char
*
,
char
**
,
off_t
,
int
);
#endif
/* defined(CONFIG_WAVELAN) */
#ifdef CONFIG_IP_ACCT
extern
int
ip_acct_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_acct0_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_acct_procinfo
(
char
*
,
char
**
,
off_t
,
int
,
int
);
#endif
/* CONFIG_IP_ACCT */
#ifdef CONFIG_IP_FIREWALL
extern
int
ip_fw_blk_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_fw_blk0_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_fw_fwd_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_fw_fwd0_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_fw_blk_procinfo
(
char
*
,
char
**
,
off_t
,
int
,
int
);
extern
int
ip_fw_fwd_procinfo
(
char
*
,
char
**
,
off_t
,
int
,
int
);
#endif
/* CONFIG_IP_FIREWALL */
extern
int
ip_msqhst_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
extern
int
ip_mc_procinfo
(
char
*
,
char
**
,
off_t
,
int
);
...
...
@@ -147,16 +145,13 @@ static struct proc_dir_entry net_dir[] = {
#endif
#ifdef CONFIG_IP_FIREWALL
{
PROC_NET_IPFWFWD
,
10
,
"ip_forward"
},
{
PROC_NET_IPFWFWD0
,
12
,
"ip_forward_0"
},
{
PROC_NET_IPFWBLK
,
8
,
"ip_block"
},
{
PROC_NET_IPFWBLK0
,
10
,
"ip_block_0"
},
#endif
#ifdef CONFIG_IP_MASQUERADE
{
PROC_NET_IPMSQHST
,
13
,
"ip_masquerade"
},
#endif
#ifdef CONFIG_IP_ACCT
{
PROC_NET_IPACCT
,
7
,
"ip_acct"
},
{
PROC_NET_IPACCT0
,
9
,
"ip_acct_0"
},
#endif
#if defined(CONFIG_WAVELAN)
{
PROC_NET_WAVELAN
,
7
,
"wavelan"
},
...
...
@@ -300,24 +295,18 @@ static int proc_readnet(struct inode * inode, struct file * file,
#endif
#ifdef CONFIG_IP_FIREWALL
case
PROC_NET_IPFWFWD
:
length
=
ip_fw_fwd_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
case
PROC_NET_IPFWFWD0
:
length
=
ip_fw_fwd0_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
length
=
ip_fw_fwd_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
,
(
file
->
f_flags
&
O_ACCMODE
)
==
O_RDWR
);
break
;
case
PROC_NET_IPFWBLK
:
length
=
ip_fw_blk_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
case
PROC_NET_IPFWBLK0
:
length
=
ip_fw_blk0_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
length
=
ip_fw_blk_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
,
(
file
->
f_flags
&
O_ACCMODE
)
==
O_RDWR
);
break
;
#endif
#ifdef CONFIG_IP_ACCT
case
PROC_NET_IPACCT
:
length
=
ip_acct_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
break
;
case
PROC_NET_IPACCT0
:
length
=
ip_acct0_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
);
length
=
ip_acct_procinfo
(
page
,
&
start
,
file
->
f_pos
,
thistime
,
(
file
->
f_flags
&
O_ACCMODE
)
==
O_RDWR
);
break
;
#endif
#ifdef CONFIG_IP_MASQUERADE
...
...
include/asm-alpha/bitops.h
View file @
55415e93
...
...
@@ -32,7 +32,7 @@ extern __inline__ unsigned long set_bit(unsigned long nr, void * addr)
"=&r"
(
oldbit
)
:
"r"
(
1UL
<<
(
nr
&
63
)),
"m"
(((
unsigned
long
*
)
addr
)[
nr
>>
6
]));
return
oldbit
;
return
oldbit
!=
0
;
}
extern
__inline__
unsigned
long
clear_bit
(
unsigned
long
nr
,
void
*
addr
)
...
...
@@ -54,7 +54,7 @@ extern __inline__ unsigned long clear_bit(unsigned long nr, void * addr)
"=&r"
(
oldbit
)
:
"r"
(
1UL
<<
(
nr
&
63
)),
"m"
(((
unsigned
long
*
)
addr
)[
nr
>>
6
]));
return
oldbit
;
return
oldbit
!=
0
;
}
extern
__inline__
unsigned
long
change_bit
(
unsigned
long
nr
,
void
*
addr
)
...
...
@@ -74,7 +74,7 @@ extern __inline__ unsigned long change_bit(unsigned long nr, void * addr)
"=&r"
(
oldbit
)
:
"r"
(
1UL
<<
(
nr
&
63
)),
"m"
(((
unsigned
long
*
)
addr
)[
nr
>>
6
]));
return
oldbit
;
return
oldbit
!=
0
;
}
extern
__inline__
unsigned
long
test_bit
(
int
nr
,
void
*
addr
)
...
...
include/asm-alpha/pgtable.h
View file @
55415e93
...
...
@@ -158,16 +158,19 @@ extern inline unsigned long pgd_page(pgd_t pgd)
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
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
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
;
}
/*
...
...
@@ -344,6 +347,16 @@ extern inline pmd_t * pmd_alloc(pgd_t *pgd, unsigned long address)
return
(
pmd_t
*
)
pgd_page
(
*
pgd
)
+
address
;
}
extern
inline
void
pgd_free
(
pgd_t
*
pgd
)
{
free_page
((
unsigned
long
)
pgd
);
}
extern
inline
pgd_t
*
pgd_alloc
(
void
)
{
return
(
pgd_t
*
)
get_free_page
(
GFP_KERNEL
);
}
extern
pgd_t
swapper_pg_dir
[
1024
];
#endif
/* _ALPHA_PGTABLE_H */
include/asm-alpha/processor.h
View file @
55415e93
...
...
@@ -77,4 +77,13 @@ extern inline void end_bh_atomic(void)
:
"0"
(
0
));
}
/*
* Do necessary setup to start up a newly executed thread.
*/
static
inline
void
start_thread
(
struct
pt_regs
*
regs
,
unsigned
long
pc
,
unsigned
long
sp
)
{
regs
->
pc
=
pc
;
wrusp
(
sp
);
}
#endif
/* __ASM_ALPHA_PROCESSOR_H */
include/asm-alpha/ptrace.h
View file @
55415e93
...
...
@@ -36,7 +36,7 @@ struct pt_regs {
unsigned
long
r26
;
unsigned
long
r27
;
unsigned
long
r28
;
unsigned
long
padding
;
unsigned
long
hae
;
/* These are saved by PAL-code: */
unsigned
long
ps
;
unsigned
long
pc
;
...
...
include/asm-i386/pgtable.h
View file @
55415e93
...
...
@@ -29,9 +29,6 @@
#define PTRS_PER_PMD 1
#define PTRS_PER_PGD 1024
/* the no. of pointers that fit on a page: this will go away */
#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*))
/* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
* physical memory until the kernel virtual memory starts. That means that
...
...
@@ -133,17 +130,36 @@ extern unsigned long high_memory;
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_PRESENT
;
}
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
int
pmd_none
(
pmd_t
pmd
)
{
return
!
pmd_val
(
pmd
);
}
extern
inline
int
pmd_bad
(
pmd_t
pmd
)
{
return
(
pmd_val
(
pmd
)
&
~
PAGE_MASK
)
!=
_PAGE_TABLE
||
pmd_val
(
pmd
)
>
high_memory
;
}
extern
inline
int
pmd_present
(
pmd_t
pmd
)
{
return
pmd_val
(
pmd
)
&
_PAGE_PRESENT
;
}
extern
inline
int
pmd_inuse
(
pmd_t
*
pmdp
)
{
return
0
;
}
extern
inline
void
pmd_clear
(
pmd_t
*
pmdp
)
{
pmd_val
(
*
pmdp
)
=
0
;
}
#ifdef THREE_LEVEL
/*
* The "pgd_xxx()" functions here are trivial for a folded two-level
* setup: the pgd is never bad, and a pmd always exists (as it's folded
* into the pgd entry)
*/
extern
inline
int
pgd_none
(
pgd_t
pgd
)
{
return
0
;
}
extern
inline
int
pgd_bad
(
pgd_t
pgd
)
{
return
0
;
}
extern
inline
int
pgd_present
(
pgd_t
pgd
)
{
return
1
;
}
extern
inline
int
pgd_inuse
(
pgd_t
*
pgdp
)
{
return
mem_map
[
MAP_NR
(
pgdp
)]
>
1
;
}
extern
inline
void
pgd_clear
(
pgd_t
*
pgdp
)
{
}
#else
/*
* These are the old (and incorrect) ones needed for code that doesn't
* know about three-level yet..
*/
extern
inline
int
pgd_none
(
pgd_t
pgd
)
{
return
!
pgd_val
(
pgd
);
}
extern
inline
int
pgd_bad
(
pgd_t
pgd
)
{
return
(
pgd_val
(
pgd
)
&
~
PAGE_MASK
)
!=
_PAGE_TABLE
||
pgd_val
(
pgd
)
>
high_memory
;
}
extern
inline
int
pgd_present
(
pgd_t
pgd
)
{
return
pgd_val
(
pgd
)
&
_PAGE_PRESENT
;
}
extern
inline
void
pgd_clear
(
pgd_t
*
pgdp
)
{
pgd_val
(
*
pgdp
)
=
0
;
}
#endif
/*
* The following only work if pte_present() is true.
...
...
@@ -185,6 +201,8 @@ extern inline unsigned long pte_page(pte_t pte)
extern
inline
unsigned
long
pmd_page
(
pmd_t
pmd
)
{
return
pmd_val
(
pmd
)
&
PAGE_MASK
;
}
#ifndef THREE_LEVEL
extern
inline
unsigned
long
pgd_page
(
pgd_t
pgd
)
{
return
pgd_val
(
pgd
)
&
PAGE_MASK
;
}
...
...
@@ -193,6 +211,11 @@ extern inline void pgd_set(pgd_t * pgdp, pte_t * ptep)
#define PAGE_DIR_OFFSET(tsk,address) pgd_offset((tsk),(address))
/* the no. of pointers that fit on a page: this will go away */
#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*))
#endif
/* to find an entry in a page-table-directory */
extern
inline
pgd_t
*
pgd_offset
(
struct
task_struct
*
tsk
,
unsigned
long
address
)
{
...
...
@@ -300,6 +323,16 @@ extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address)
return
(
pmd_t
*
)
pgd
;
}
extern
inline
void
pgd_free
(
pgd_t
*
pgd
)
{
free_page
((
unsigned
long
)
pgd
);
}
extern
inline
pgd_t
*
pgd_alloc
(
void
)
{
return
(
pgd_t
*
)
get_free_page
(
GFP_KERNEL
);
}
extern
pgd_t
swapper_pg_dir
[
1024
];
#endif
/* _I386_PAGE_H */
include/asm-i386/processor.h
View file @
55415e93
...
...
@@ -39,7 +39,7 @@ extern int EISA_bus;
* User space process size: 3GB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing.
*/
#define TASK_SIZE
0xc0000000
#define TASK_SIZE
(0xC0000000UL)
/*
* Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
...
...
@@ -128,4 +128,12 @@ struct thread_struct {
NULL, 0, 0, 0, 0
/* vm86_info */
\
}
static
inline
void
start_thread
(
struct
pt_regs
*
regs
,
unsigned
long
eip
,
unsigned
long
esp
)
{
regs
->
cs
=
USER_CS
;
regs
->
ds
=
regs
->
es
=
regs
->
ss
=
regs
->
fs
=
regs
->
gs
=
USER_DS
;
regs
->
eip
=
eip
;
regs
->
esp
=
esp
;
}
#endif
/* __ASM_I386_PROCESSOR_H */
include/asm-mips/processor.h
View file @
55415e93
...
...
@@ -80,7 +80,7 @@ extern int EISA_bus;
* User space process size: 2GB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing.
*/
#define TASK_SIZE
0x80000000
#define TASK_SIZE
(0x80000000UL)
/*
* Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
...
...
include/asm-sparc/processor.h
View file @
55415e93
...
...
@@ -27,7 +27,7 @@
*
* "this is gonna have to change to 1gig for the sparc" - David S. Miller
*/
#define TASK_SIZE (0x
c
0000000UL)
#define TASK_SIZE (0x
C
0000000UL)
/*
* Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
...
...
include/linux/if_plip.h
View file @
55415e93
...
...
@@ -20,7 +20,6 @@ struct plipconf
unsigned
short
pcmd
;
unsigned
long
nibble
;
unsigned
long
trigger
;
unsigned
long
unit
;
};
#define PLIP_GET_TIMEOUT 0x1
...
...
include/linux/proc_fs.h
View file @
55415e93
...
...
@@ -69,13 +69,10 @@ enum net_directory_inos {
#endif
#ifdef CONFIG_IP_FIREWALL
PROC_NET_IPFWFWD
,
PROC_NET_IPFWFWD0
,
PROC_NET_IPFWBLK
,
PROC_NET_IPFWBLK0
,
#endif
#ifdef CONFIG_IP_ACCT
PROC_NET_IPACCT
,
PROC_NET_IPACCT0
,
#endif
#if defined(CONFIG_WAVELAN)
PROC_NET_WAVELAN
,
...
...
include/linux/sched.h
View file @
55415e93
...
...
@@ -269,7 +269,6 @@ extern int request_irq(unsigned int irq,void (*handler)(int, struct pt_regs *),
extern
void
free_irq
(
unsigned
int
irq
);
extern
unsigned
long
copy_thread
(
int
,
unsigned
long
,
struct
task_struct
*
,
struct
pt_regs
*
);
extern
void
start_thread
(
struct
pt_regs
*
,
unsigned
long
pc
,
unsigned
long
sp
);
extern
void
flush_thread
(
void
);
extern
void
exit_thread
(
void
);
...
...
include/linux/sonycd535.h
0 → 100644
View file @
55415e93
#ifndef SONYCD535_H
#define SONYCD535_H
/*
* define all the commands recognized by the CDU-531/5
*/
#define SONY535_REQUEST_DRIVE_STATUS_1 (0x80)
#define SONY535_REQUEST_SENSE (0x82)
#define SONY535_REQUEST_DRIVE_STATUS_2 (0x84)
#define SONY535_REQUEST_ERROR_STATUS (0x86)
#define SONY535_REQUEST_AUDIO_STATUS (0x88)
#define SONY535_INQUIRY (0x8a)
#define SONY535_SET_INACTIVITY_TIME (0x90)
#define SONY535_SEEK_AND_READ_N_BLOCKS_1 (0xa0)
#define SONY535_SEEK_AND_READ_N_BLOCKS_2 (0xa4)
#define SONY535_PLAY_AUDIO (0xa6)
#define SONY535_REQUEST_DISC_CAPACITY (0xb0)
#define SONY535_REQUEST_TOC_DATA (0xb2)
#define SONY535_REQUEST_SUB_Q_DATA (0xb4)
#define SONY535_REQUEST_ISRC (0xb6)
#define SONY535_REQUEST_UPC_EAN (0xb8)
#define SONY535_SET_DRIVE_MODE (0xc0)
#define SONY535_REQUEST_DRIVE_MODE (0xc2)
#define SONY535_SET_RETRY_COUNT (0xc4)
#define SONY535_DIAGNOSTIC_1 (0xc6)
#define SONY535_DIAGNOSTIC_4 (0xcc)
#define SONY535_DIAGNOSTIC_5 (0xce)
#define SONY535_EJECT_CADDY (0xd0)
#define SONY535_DISABLE_EJECT_BUTTON (0xd2)
#define SONY535_ENABLE_EJECT_BUTTON (0xd4)
#define SONY535_HOLD (0xe0)
#define SONY535_AUDIO_PAUSE_ON_OFF (0xe2)
#define SONY535_SET_VOLUME (0xe8)
#define SONY535_STOP (0xf0)
#define SONY535_SPIN_UP (0xf2)
#define SONY535_SPIN_DOWN (0xf4)
#define SONY535_CLEAR_PARAMETERS (0xf6)
#define SONY535_CLEAR_ENDING_ADDRESS (0xf8)
/*
* define some masks
*/
#define SONY535_DATA_NOT_READY_BIT (0x1)
#define SONY535_RESULT_NOT_READY_BIT (0x2)
/*
* drive status 1
*/
#define SONY535_STATUS1_COMMAND_ERROR (0x1)
#define SONY535_STATUS1_DATA_ERROR (0x2)
#define SONY535_STATUS1_SEEK_ERROR (0x4)
#define SONY535_STATUS1_DISC_TYPE_ERROR (0x8)
#define SONY535_STATUS1_NOT_SPINNING (0x10)
#define SONY535_STATUS1_EJECT_BUTTON_PRESSED (0x20)
#define SONY535_STATUS1_CADDY_NOT_INSERTED (0x40)
#define SONY535_STATUS1_BYTE_TWO_FOLLOWS (0x80)
/*
* drive status 2
*/
#define SONY535_CDD_LOADING_ERROR (0x7)
#define SONY535_CDD_NO_DISC (0x8)
#define SONY535_CDD_UNLOADING_ERROR (0x9)
#define SONY535_CDD_CADDY_NOT_INSERTED (0xd)
#define SONY535_ATN_RESET_OCCURRED (0x2)
#define SONY535_ATN_DISC_CHANGED (0x4)
#define SONY535_ATN_RESET_AND_DISC_CHANGED (0x6)
#define SONY535_ATN_EJECT_IN_PROGRESS (0xe)
#define SONY535_ATN_BUSY (0xf)
/*
* define some parameters
*/
#define SONY535_AUDIO_DRIVE_MODE (0)
#define SONY535_CDROM_DRIVE_MODE (0xe0)
#define SONY535_PLAY_OP_PLAYBACK (0)
#define SONY535_PLAY_OP_ENTER_HOLD (1)
#define SONY535_PLAY_OP_SET_AUDIO_ENDING_ADDR (2)
#define SONY535_PLAY_OP_SCAN_FORWARD (3)
#define SONY535_PLAY_OP_SCAN_BACKWARD (4)
/*
* convert from msf format to block number
*/
#define SONY_BLOCK_NUMBER(m,s,f) (((m)*60L+(s))*75L+(f))
#define SONY_BLOCK_NUMBER_MSF(x) (((x)[0]*60L+(x)[1])*75L+(x)[2])
/*
* error return values from the doSonyCmd() routines
*/
#define TIME_OUT (-1)
#define NO_CDROM (-2)
#define BAD_STATUS (-3)
#define CD_BUSY (-4)
#define NOT_DATA_CD (-5)
#define NO_ROOM (-6)
#define LOG_START_OFFSET 150
/* Offset of first logical sector */
#define SONY_JIFFIES_TIMEOUT 500
/* Maximum number of jiffies (10ms)
the drive will wait/try for an
operation */
#define SONY_READY_RETRIES (50000)
/* How many times to retry a
spin waiting for a register
to come ready */
#define SONY535_FAST_POLLS (10000)
/* how many times recheck
status waiting for a data
to become ready */
typedef
unsigned
char
Byte
;
/*
* This is the complete status returned from the drive configuration request
* command.
*/
struct
s535_sony_drive_config
{
char
vendor_id
[
8
];
char
product_id
[
16
];
char
product_rev_level
[
4
];
};
/* The following is returned from the request sub-q data command */
struct
s535_sony_subcode
{
unsigned
char
address
:
4
;
unsigned
char
control
:
4
;
unsigned
char
track_num
;
unsigned
char
index_num
;
unsigned
char
rel_msf
[
3
];
unsigned
char
abs_msf
[
3
];
};
struct
s535_sony_disc_capacity
{
Byte
mFirstTrack
,
sFirstTrack
,
fFirstTrack
;
Byte
mLeadOut
,
sLeadOut
,
fLeadOut
;
};
/*
* The following is returned from the request TOC (Table Of Contents) command.
* (last_track_num-first_track_num+1) values are valid in tracks.
*/
struct
s535_sony_toc
{
unsigned
char
reserved0
:
4
;
unsigned
char
control0
:
4
;
unsigned
char
point0
;
unsigned
char
first_track_num
;
unsigned
char
reserved0a
;
unsigned
char
reserved0b
;
unsigned
char
reserved1
:
4
;
unsigned
char
control1
:
4
;
unsigned
char
point1
;
unsigned
char
last_track_num
;
unsigned
char
dummy1
;
unsigned
char
dummy2
;
unsigned
char
reserved2
:
4
;
unsigned
char
control2
:
4
;
unsigned
char
point2
;
unsigned
char
lead_out_start_msf
[
3
];
struct
{
unsigned
char
reserved
:
4
;
unsigned
char
control
:
4
;
unsigned
char
track
;
unsigned
char
track_start_msf
[
3
];
}
tracks
[
100
];
unsigned
int
lead_out_start_lba
;
};
#endif
/* SONYCD535_H */
init/main.c
View file @
55415e93
...
...
@@ -105,6 +105,9 @@ extern void sbpcd_setup(char *str, int *ints);
#ifdef CONFIG_CDU31A
extern
void
cdu31a_setup
(
char
*
str
,
int
*
ints
);
#endif CONFIG_CDU31A
#ifdef CONFIG_CDU535
extern
void
sonycd535_setup
(
char
*
str
,
int
*
ints
);
#endif CONFIG_CDU535
void
ramdisk_setup
(
char
*
str
,
int
*
ints
);
#ifdef CONFIG_SYSVIPC
...
...
@@ -222,6 +225,9 @@ struct {
#ifdef CONFIG_AZTCD
{
"aztcd="
,
aztcd_setup
},
#endif
#ifdef CONFIG_CDU535
{
"sonycd535="
,
sonycd535_setup
},
#endif CONFIG_CDU535
#ifdef CONFIG_SOUND
{
"sound="
,
sound_setup
},
#endif
...
...
kernel/ksyms.c
View file @
55415e93
...
...
@@ -67,6 +67,7 @@ extern int sys_tz;
extern
int
request_dma
(
unsigned
int
dmanr
,
char
*
deviceID
);
extern
void
free_dma
(
unsigned
int
dmanr
);
extern
int
close_fp
(
struct
file
*
filp
,
unsigned
int
fd
);
extern
void
(
*
iABI_hook
)(
struct
pt_regs
*
regs
);
struct
symbol_table
symbol_table
=
{
...
...
@@ -128,6 +129,7 @@ struct symbol_table symbol_table = {
X
(
namei
),
X
(
lnamei
),
X
(
open_namei
),
X
(
close_fp
),
X
(
check_disk_change
),
X
(
invalidate_buffers
),
X
(
fsync_dev
),
...
...
mm/memory.c
View file @
55415e93
#define THREE_LEVEL
/*
* linux/mm/memory.c
*
...
...
@@ -62,9 +63,9 @@ unsigned char * free_area_map[NR_MEM_LISTS];
#define copy_page(from,to) memcpy((void *) to, (void *) from, PAGE_SIZE)
mem_map_t
*
mem_map
=
NULL
;
#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
#define CODE_SPACE(addr,p) ((addr) < (p)->end_code)
mem_map_t
*
mem_map
=
NULL
;
/*
* oom() prints a message (so that the user knows why the process died),
...
...
@@ -93,29 +94,53 @@ static inline void free_one_pte(pte_t * page_table)
return
;
}
static
void
free_one_table
(
pgd_t
*
page_
dir
)
static
inline
void
free_one_pmd
(
pmd_t
*
dir
)
{
int
j
;
pgd_t
pg_table
=
*
page_dir
;
pte_t
*
page_table
;
unsigned
long
page
;
pte_t
*
pte
;
if
(
p
gd_none
(
pg_table
))
if
(
p
md_none
(
*
dir
))
return
;
pgd_clear
(
page_dir
);
if
(
pgd_bad
(
pg_table
))
{
p
rintk
(
"Bad page table: [%p]=%08lx
\n
"
,
page_dir
,
pgd_val
(
pg_table
)
);
if
(
pmd_bad
(
*
dir
))
{
printk
(
"free_one_pmd: bad directory entry %08lx
\n
"
,
pmd_val
(
*
dir
));
p
md_clear
(
dir
);
return
;
}
page
=
pgd_page
(
pg_table
);
if
(
mem_map
[
MAP_NR
(
page
)]
&
MAP_PAGE_RESERVED
)
pte
=
pte_offset
(
dir
,
0
);
pmd_clear
(
dir
);
if
(
pte_inuse
(
pte
))
{
pte_free
(
pte
);
return
;
page_table
=
(
pte_t
*
)
page
;
for
(
j
=
0
;
j
<
PTRS_PER_PAGE
;
j
++
,
page_table
++
)
free_one_pte
(
p
age_table
);
free_page
(
pag
e
);
}
for
(
j
=
0
;
j
<
PTRS_PER_PTE
;
j
++
)
free_one_pte
(
p
te
+
j
);
pte_free
(
pt
e
);
}
static
inline
void
free_one_pgd
(
pgd_t
*
dir
)
{
int
j
;
pmd_t
*
pmd
;
if
(
pgd_none
(
*
dir
))
return
;
if
(
pgd_bad
(
*
dir
))
{
printk
(
"free_one_pgd: bad directory entry %08lx
\n
"
,
pgd_val
(
*
dir
));
pgd_clear
(
dir
);
return
;
}
pmd
=
pmd_offset
(
dir
,
0
);
pgd_clear
(
dir
);
if
(
pmd_inuse
(
pmd
))
{
pmd_free
(
pmd
);
return
;
}
for
(
j
=
0
;
j
<
PTRS_PER_PMD
;
j
++
)
free_one_pmd
(
pmd
+
j
);
pmd_free
(
pmd
);
}
/*
* This function clears all user-level page tables of a process - this
* is needed by execve(), so that old pages aren't in the way. Note that
...
...
@@ -132,26 +157,26 @@ void clear_page_tables(struct task_struct * tsk)
return
;
if
(
tsk
==
task
[
0
])
panic
(
"task[0] (swapper) doesn't support exec()
\n
"
);
page_dir
=
PAGE_DIR_OFFSET
(
tsk
,
0
);
page_dir
=
pgd_offset
(
tsk
,
0
);
if
(
!
page_dir
||
page_dir
==
swapper_pg_dir
)
{
printk
(
"Trying to clear kernel page-directory: not good
\n
"
);
return
;
}
if
(
mem_map
[
MAP_NR
((
unsigned
long
)
page_dir
)]
>
1
)
{
if
(
pgd_inuse
(
page_dir
)
)
{
pgd_t
*
new_pg
;
if
(
!
(
new_pg
=
(
pgd_t
*
)
get_free_page
(
GFP_KERNEL
)))
{
if
(
!
(
new_pg
=
pgd_alloc
(
)))
{
oom
(
tsk
);
return
;
}
for
(
i
=
768
;
i
<
1024
;
i
++
)
for
(
i
=
USER_PTRS_PER_PGD
;
i
<
PTRS_PER_PGD
;
i
++
)
new_pg
[
i
]
=
page_dir
[
i
];
free_page
((
unsigned
long
)
page_dir
);
SET_PAGE_DIR
(
tsk
,
new_pg
);
pgd_free
(
page_dir
);
return
;
}
for
(
i
=
0
;
i
<
768
;
i
++
,
page_dir
++
)
free_one_
table
(
page_dir
);
for
(
i
=
0
;
i
<
USER_PTRS_PER_PGD
;
i
++
)
free_one_
pgd
(
page_dir
+
i
);
invalidate
();
return
;
}
...
...
@@ -170,19 +195,19 @@ void free_page_tables(struct task_struct * tsk)
printk
(
"task[0] (swapper) killed: unable to recover
\n
"
);
panic
(
"Trying to free up swapper memory space"
);
}
page_dir
=
PAGE_DIR_OFFSET
(
tsk
,
0
);
page_dir
=
pgd_offset
(
tsk
,
0
);
if
(
!
page_dir
||
page_dir
==
swapper_pg_dir
)
{
printk
(
"Trying to free kernel page-directory: not good
\n
"
);
return
;
}
SET_PAGE_DIR
(
tsk
,
swapper_pg_dir
);
if
(
mem_map
[
MAP_NR
((
unsigned
long
)
page_dir
)]
>
1
)
{
free_page
((
unsigned
long
)
page_dir
);
if
(
pgd_inuse
(
page_dir
)
)
{
pgd_free
(
page_dir
);
return
;
}
for
(
i
=
0
;
i
<
PTRS_PER_P
AGE
;
i
++
)
free_one_
table
(
page_dir
+
i
);
free_page
((
unsigned
long
)
page_dir
);
for
(
i
=
0
;
i
<
PTRS_PER_P
GD
;
i
++
)
free_one_
pgd
(
page_dir
+
i
);
pgd_free
(
page_dir
);
invalidate
();
}
...
...
@@ -196,12 +221,94 @@ int clone_page_tables(struct task_struct * tsk)
{
pgd_t
*
pg_dir
;
pg_dir
=
PAGE_DIR_OFFSET
(
current
,
0
);
mem_map
[
MAP_NR
(
(
unsigned
long
)
pg_dir
)]
++
;
pg_dir
=
pgd_offset
(
current
,
0
);
mem_map
[
MAP_NR
(
pg_dir
)]
++
;
SET_PAGE_DIR
(
tsk
,
pg_dir
);
return
0
;
}
static
inline
void
copy_one_pte
(
pte_t
*
old_pte
,
pte_t
*
new_pte
)
{
pte_t
pte
=
*
old_pte
;
if
(
pte_none
(
pte
))
return
;
if
(
!
pte_present
(
pte
))
{
swap_duplicate
(
pte_val
(
pte
));
*
new_pte
=
pte
;
return
;
}
if
(
pte_page
(
pte
)
>
high_memory
||
(
mem_map
[
MAP_NR
(
pte_page
(
pte
))]
&
MAP_PAGE_RESERVED
))
{
*
new_pte
=
pte
;
return
;
}
if
(
pte_cow
(
pte
))
pte
=
pte_wrprotect
(
pte
);
if
(
delete_from_swap_cache
(
pte_page
(
pte
)))
pte
=
pte_mkdirty
(
pte
);
*
new_pte
=
pte
;
*
old_pte
=
pte
;
mem_map
[
MAP_NR
(
pte_page
(
pte
))]
++
;
}
static
inline
int
copy_one_pmd
(
pmd_t
*
old_pmd
,
pmd_t
*
new_pmd
)
{
int
j
;
pte_t
*
old_pte
,
*
new_pte
;
if
(
pmd_none
(
*
old_pmd
))
return
0
;
if
(
pmd_bad
(
*
old_pmd
))
{
printk
(
"copy_one_pmd: bad page table: probable memory corruption
\n
"
);
pmd_clear
(
old_pmd
);
return
0
;
}
old_pte
=
pte_offset
(
old_pmd
,
0
);
if
(
pte_inuse
(
old_pte
))
{
*
new_pmd
=
*
old_pmd
;
return
0
;
}
new_pte
=
pte_alloc
(
new_pmd
,
0
);
if
(
!
new_pte
)
return
-
ENOMEM
;
for
(
j
=
0
;
j
<
PTRS_PER_PTE
;
j
++
)
{
copy_one_pte
(
old_pte
,
new_pte
);
old_pte
++
;
new_pte
++
;
}
return
0
;
}
static
inline
int
copy_one_pgd
(
pgd_t
*
old_pgd
,
pgd_t
*
new_pgd
)
{
int
j
;
pmd_t
*
old_pmd
,
*
new_pmd
;
if
(
pgd_none
(
*
old_pgd
))
return
0
;
if
(
pgd_bad
(
*
old_pgd
))
{
printk
(
"copy_one_pgd: bad page table: probable memory corruption
\n
"
);
pgd_clear
(
old_pgd
);
return
0
;
}
old_pmd
=
pmd_offset
(
old_pgd
,
0
);
if
(
pmd_inuse
(
old_pmd
))
{
*
new_pgd
=
*
old_pgd
;
return
0
;
}
new_pmd
=
pmd_alloc
(
new_pgd
,
0
);
if
(
!
new_pmd
)
return
-
ENOMEM
;
for
(
j
=
0
;
j
<
PTRS_PER_PMD
;
j
++
)
{
int
error
=
copy_one_pmd
(
old_pmd
,
new_pmd
);
if
(
error
)
return
error
;
old_pmd
++
;
new_pmd
++
;
}
return
0
;
}
/*
* copy_page_tables() just copies the whole process memory range:
* note the special handling of RESERVED (ie kernel) pages, which
...
...
@@ -210,59 +317,23 @@ int clone_page_tables(struct task_struct * tsk)
int
copy_page_tables
(
struct
task_struct
*
tsk
)
{
int
i
;
pgd_t
*
old_p
age_dir
;
pgd_t
*
new_p
age_dir
;
pgd_t
*
old_p
gd
;
pgd_t
*
new_p
gd
;
new_p
age_dir
=
(
pgd_t
*
)
get_free_page
(
GFP_KERNEL
);
if
(
!
new_p
age_dir
)
new_p
gd
=
pgd_alloc
(
);
if
(
!
new_p
gd
)
return
-
ENOMEM
;
old_page_dir
=
PAGE_DIR_OFFSET
(
current
,
0
);
SET_PAGE_DIR
(
tsk
,
new_page_dir
);
for
(
i
=
0
;
i
<
PTRS_PER_PAGE
;
i
++
,
old_page_dir
++
,
new_page_dir
++
)
{
int
j
;
pgd_t
old_pg_table
;
pte_t
*
old_page_table
,
*
new_page_table
;
old_pg_table
=
*
old_page_dir
;
if
(
pgd_none
(
old_pg_table
))
continue
;
if
(
pgd_bad
(
old_pg_table
))
{
printk
(
"copy_page_tables: bad page table: "
"probable memory corruption
\n
"
);
pgd_clear
(
old_page_dir
);
continue
;
}
if
(
mem_map
[
MAP_NR
(
pgd_page
(
old_pg_table
))]
&
MAP_PAGE_RESERVED
)
{
*
new_page_dir
=
old_pg_table
;
continue
;
}
if
(
!
(
new_page_table
=
(
pte_t
*
)
get_free_page
(
GFP_KERNEL
)))
{
old_pgd
=
pgd_offset
(
current
,
0
);
SET_PAGE_DIR
(
tsk
,
new_pgd
);
for
(
i
=
0
;
i
<
PTRS_PER_PGD
;
i
++
)
{
int
errno
=
copy_one_pgd
(
old_pgd
,
new_pgd
);
if
(
errno
)
{
free_page_tables
(
tsk
);
return
-
ENOMEM
;
}
old_page_table
=
(
pte_t
*
)
pgd_page
(
old_pg_table
);
pgd_set
(
new_page_dir
,
new_page_table
);
for
(
j
=
0
;
j
<
PTRS_PER_PAGE
;
j
++
,
old_page_table
++
,
new_page_table
++
)
{
pte_t
pte
=
*
old_page_table
;
if
(
pte_none
(
pte
))
continue
;
if
(
!
pte_present
(
pte
))
{
swap_duplicate
(
pte_val
(
pte
));
*
new_page_table
=
pte
;
continue
;
}
if
(
pte_page
(
pte
)
>
high_memory
||
(
mem_map
[
MAP_NR
(
pte_page
(
pte
))]
&
MAP_PAGE_RESERVED
))
{
*
new_page_table
=
pte
;
continue
;
}
if
(
pte_cow
(
pte
))
pte
=
pte_wrprotect
(
pte
);
if
(
delete_from_swap_cache
(
pte_page
(
pte
)))
pte
=
pte_mkdirty
(
pte
);
*
new_page_table
=
pte
;
*
old_page_table
=
pte
;
mem_map
[
MAP_NR
(
pte_page
(
pte
))]
++
;
invalidate
();
return
errno
;
}
old_pgd
++
;
new_pgd
++
;
}
invalidate
();
return
0
;
...
...
@@ -418,67 +489,67 @@ int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
* mappings are removed. any references to nonexistent pages results
* in null mappings (currently treated as "copy-on-access")
*/
int
remap_page_range
(
unsigned
long
from
,
unsigned
long
to
,
unsigned
long
size
,
pgprot_t
prot
)
static
inline
void
remap_pte_range
(
pte_t
*
pte
,
unsigned
long
address
,
unsigned
long
size
,
unsigned
long
offset
,
pgprot_t
prot
)
{
unsigned
long
end
;
address
&=
~
PMD_MASK
;
end
=
address
+
size
;
if
(
end
>
PMD_SIZE
)
end
=
PMD_SIZE
;
do
{
pte_t
oldpage
=
*
pte
;
*
pte
=
mk_pte
(
offset
,
prot
);
forget_pte
(
oldpage
);
address
+=
PAGE_SIZE
;
offset
+=
PAGE_SIZE
;
pte
++
;
}
while
(
address
<
end
);
}
static
inline
int
remap_pmd_range
(
pmd_t
*
pmd
,
unsigned
long
address
,
unsigned
long
size
,
unsigned
long
offset
,
pgprot_t
prot
)
{
unsigned
long
end
;
address
&=
~
PGDIR_MASK
;
end
=
address
+
size
;
if
(
end
>
PGDIR_SIZE
)
end
=
PGDIR_SIZE
;
offset
-=
address
;
do
{
pte_t
*
pte
=
pte_alloc
(
pmd
,
address
);
if
(
!
pte
)
return
-
ENOMEM
;
remap_pte_range
(
pte
,
address
,
end
-
address
,
address
+
offset
,
prot
);
address
=
(
address
+
PMD_SIZE
)
&
PMD_MASK
;
pmd
++
;
}
while
(
address
<
end
);
return
0
;
}
int
remap_page_range
(
unsigned
long
from
,
unsigned
long
offset
,
unsigned
long
size
,
pgprot_t
prot
)
{
int
error
=
0
;
pgd_t
*
dir
;
pte_t
*
page_table
;
unsigned
long
poff
,
pcnt
;
if
((
from
&
~
PAGE_MASK
)
||
(
to
&
~
PAGE_MASK
))
{
printk
(
"remap_page_range: from = %08lx, to=%08lx
\n
"
,
from
,
to
);
return
-
EINVAL
;
}
dir
=
PAGE_DIR_OFFSET
(
current
,
from
);
size
=
(
size
+
~
PAGE_MASK
)
>>
PAGE_SHIFT
;
poff
=
(
from
>>
PAGE_SHIFT
)
&
(
PTRS_PER_PAGE
-
1
);
if
((
pcnt
=
PTRS_PER_PAGE
-
poff
)
>
size
)
pcnt
=
size
;
while
(
size
>
0
)
{
if
(
!
pgd_present
(
*
dir
))
{
if
(
!
(
page_table
=
(
pte_t
*
)
get_free_page
(
GFP_KERNEL
)))
{
invalidate
();
return
-
1
;
}
if
(
pgd_present
(
*
dir
))
{
free_page
((
unsigned
long
)
page_table
);
page_table
=
(
pte_t
*
)
pgd_page
(
*
dir
);
}
else
pgd_set
(
dir
,
page_table
);
}
else
page_table
=
(
pte_t
*
)
pgd_page
(
*
dir
);
unsigned
long
end
=
from
+
size
;
offset
-=
from
;
dir
=
pgd_offset
(
current
,
from
);
while
(
from
<
end
)
{
pmd_t
*
pmd
=
pmd_alloc
(
dir
,
from
);
error
=
-
ENOMEM
;
if
(
!
pmd
)
break
;
error
=
remap_pmd_range
(
pmd
,
from
,
end
-
from
,
offset
+
from
,
prot
);
if
(
error
)
break
;
from
=
(
from
+
PGDIR_SIZE
)
&
PGDIR_MASK
;
dir
++
;
page_table
+=
poff
;
poff
=
0
;
for
(
size
-=
pcnt
;
pcnt
--
;)
{
pte_t
page
=
*
page_table
;
if
(
!
pte_none
(
page
))
{
pte_clear
(
page_table
);
if
(
pte_present
(
page
))
{
if
(
!
(
mem_map
[
MAP_NR
(
pte_page
(
page
))]
&
MAP_PAGE_RESERVED
))
if
(
current
->
mm
->
rss
>
0
)
--
current
->
mm
->
rss
;
free_page
(
pte_page
(
page
));
}
else
swap_free
(
pte_val
(
page
));
}
if
(
to
>=
high_memory
)
*
page_table
=
mk_pte
(
to
,
prot
);
else
if
(
mem_map
[
MAP_NR
(
to
)])
{
*
page_table
=
mk_pte
(
to
,
prot
);
if
(
!
(
mem_map
[
MAP_NR
(
to
)]
&
MAP_PAGE_RESERVED
))
{
++
current
->
mm
->
rss
;
mem_map
[
MAP_NR
(
to
)]
++
;
}
}
page_table
++
;
to
+=
PAGE_SIZE
;
}
pcnt
=
(
size
>
PTRS_PER_PAGE
?
PTRS_PER_PAGE
:
size
);
}
invalidate
();
return
0
;
return
error
;
}
/*
...
...
@@ -501,33 +572,27 @@ static void put_page(pte_t * page_table, pte_t pte)
*/
unsigned
long
put_dirty_page
(
struct
task_struct
*
tsk
,
unsigned
long
page
,
unsigned
long
address
)
{
pgd_t
*
page_dir
;
pte_t
*
page_table
;
pgd_t
*
pgd
;
pmd_t
*
pmd
;
pte_t
*
pte
;
if
(
page
>=
high_memory
)
printk
(
"put_dirty_page: trying to put page %08lx at %08lx
\n
"
,
page
,
address
);
if
(
mem_map
[
MAP_NR
(
page
)]
!=
1
)
printk
(
"mem_map disagrees with %08lx at %08lx
\n
"
,
page
,
address
);
page_dir
=
PAGE_DIR_OFFSET
(
tsk
,
address
);
if
(
pgd_present
(
*
page_dir
))
{
page_table
=
(
pte_t
*
)
pgd_page
(
*
page_dir
);
}
else
{
if
(
!
(
page_table
=
(
pte_t
*
)
get_free_page
(
GFP_KERNEL
)))
return
0
;
if
(
pgd_present
(
*
page_dir
))
{
free_page
((
unsigned
long
)
page_table
);
page_table
=
(
pte_t
*
)
pgd_page
(
*
page_dir
);
}
else
{
pgd_set
(
page_dir
,
page_table
);
}
}
page_table
+=
(
address
>>
PAGE_SHIFT
)
&
(
PTRS_PER_PAGE
-
1
);
if
(
!
pte_none
(
*
page_table
))
{
pgd
=
pgd_offset
(
tsk
,
address
);
pmd
=
pmd_alloc
(
pgd
,
address
);
if
(
!
pmd
)
return
0
;
pte
=
pte_alloc
(
pmd
,
address
);
if
(
!
pte
)
return
0
;
if
(
!
pte_none
(
*
pte
))
{
printk
(
"put_dirty_page: page already exists
\n
"
);
pte_clear
(
p
age_tabl
e
);
pte_clear
(
p
t
e
);
invalidate
();
}
*
p
age_tabl
e
=
pte_mkwrite
(
pte_mkdirty
(
mk_pte
(
page
,
PAGE_COPY
)));
*
p
t
e
=
pte_mkwrite
(
pte_mkdirty
(
mk_pte
(
page
,
PAGE_COPY
)));
/* no need for invalidate */
return
page
;
}
...
...
@@ -553,17 +618,22 @@ void do_wp_page(struct vm_area_struct * vma, unsigned long address,
int
write_access
)
{
pgd_t
*
page_dir
;
pmd_t
*
page_middle
;
pte_t
*
page_table
,
pte
;
unsigned
long
old_page
,
new_page
;
new_page
=
__get_free_page
(
GFP_KERNEL
);
page_dir
=
PAGE_DIR_OFFSET
(
vma
->
vm_task
,
address
);
page_dir
=
pgd_offset
(
vma
->
vm_task
,
address
);
if
(
pgd_none
(
*
page_dir
))
goto
end_wp_page
;
if
(
pgd_bad
(
*
page_dir
))
goto
bad_wp_pagetable
;
page_table
=
(
pte_t
*
)
pgd_page
(
*
page_dir
);
page_table
+=
(
address
>>
PAGE_SHIFT
)
&
(
PTRS_PER_PAGE
-
1
);
goto
bad_wp_pagedir
;
page_middle
=
pmd_offset
(
page_dir
,
address
);
if
(
pmd_none
(
*
page_middle
))
goto
end_wp_page
;
if
(
pmd_bad
(
*
page_middle
))
goto
bad_wp_pagemiddle
;
page_table
=
pte_offset
(
page_middle
,
address
);
pte
=
*
page_table
;
if
(
!
pte_present
(
pte
))
goto
end_wp_page
;
...
...
@@ -599,12 +669,14 @@ void do_wp_page(struct vm_area_struct * vma, unsigned long address,
return
;
bad_wp_page:
printk
(
"do_wp_page: bogus page at address %08lx (%08lx)
\n
"
,
address
,
old_page
);
*
page_table
=
BAD_PAGE
;
send_sig
(
SIGKILL
,
vma
->
vm_task
,
1
);
goto
end_wp_page
;
bad_wp_pagetable:
printk
(
"do_wp_page: bogus page-table at address %08lx (%08lx)
\n
"
,
address
,
pgd_val
(
*
page_dir
));
pgd_set
(
page_dir
,
BAD_PAGETABLE
);
bad_wp_pagemiddle:
printk
(
"do_wp_page: bogus page-middle at address %08lx (%08lx)
\n
"
,
address
,
pmd_val
(
*
page_middle
));
send_sig
(
SIGKILL
,
vma
->
vm_task
,
1
);
goto
end_wp_page
;
bad_wp_pagedir:
printk
(
"do_wp_page: bogus page-dir entry at address %08lx (%08lx)
\n
"
,
address
,
pgd_val
(
*
page_dir
));
send_sig
(
SIGKILL
,
vma
->
vm_task
,
1
);
end_wp_page:
if
(
new_page
)
...
...
@@ -719,14 +791,27 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
unsigned
long
newpage
)
{
pgd_t
*
from_dir
,
*
to_dir
;
pmd_t
*
from_middle
,
*
to_middle
;
pte_t
*
from_table
,
*
to_table
;
pte_t
from
,
to
;
from_dir
=
PAGE_DIR_OFFSET
(
from_area
->
vm_task
,
from_address
);
from_dir
=
pgd_offset
(
from_area
->
vm_task
,
from_address
);
/* is there a page-directory at from? */
if
(
!
pgd_present
(
*
from_dir
))
if
(
pgd_none
(
*
from_dir
))
return
0
;
if
(
pgd_bad
(
*
from_dir
))
{
printk
(
"try_to_share: bad page directory %08lx
\n
"
,
pgd_val
(
*
from_dir
));
return
0
;
from_table
=
(
pte_t
*
)
(
pgd_page
(
*
from_dir
)
+
PAGE_PTR
(
from_address
));
}
from_middle
=
pmd_offset
(
from_dir
,
from_address
);
/* is there a mid-directory at from? */
if
(
pmd_none
(
*
from_middle
))
return
0
;
if
(
pmd_bad
(
*
from_middle
))
{
printk
(
"try_to_share: bad mid directory %08lx
\n
"
,
pmd_val
(
*
from_middle
));
return
0
;
}
from_table
=
pte_offset
(
from_middle
,
from_address
);
from
=
*
from_table
;
/* is the page present? */
if
(
!
pte_present
(
from
))
...
...
@@ -746,10 +831,23 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
if
(
mem_map
[
MAP_NR
(
pte_page
(
from
))]
&
MAP_PAGE_RESERVED
)
return
0
;
/* is the destination ok? */
to_dir
=
PAGE_DIR_OFFSET
(
to_area
->
vm_task
,
to_address
);
if
(
!
pgd_present
(
*
to_dir
))
to_dir
=
pgd_offset
(
to_area
->
vm_task
,
to_address
);
/* is there a page-directory at to? */
if
(
pgd_none
(
*
to_dir
))
return
0
;
if
(
pgd_bad
(
*
to_dir
))
{
printk
(
"try_to_share: bad page directory %08lx
\n
"
,
pgd_val
(
*
to_dir
));
return
0
;
to_table
=
(
pte_t
*
)
(
pgd_page
(
*
to_dir
)
+
PAGE_PTR
(
to_address
));
}
to_middle
=
pmd_offset
(
to_dir
,
to_address
);
/* is there a mid-directory at to? */
if
(
pmd_none
(
*
to_middle
))
return
0
;
if
(
pmd_bad
(
*
to_middle
))
{
printk
(
"try_to_share: bad mid directory %08lx
\n
"
,
pmd_val
(
*
to_middle
));
return
0
;
}
to_table
=
pte_offset
(
to_middle
,
to_address
);
to
=
*
to_table
;
if
(
!
pte_none
(
to
))
return
0
;
...
...
@@ -855,32 +953,16 @@ static int share_page(struct vm_area_struct * area, unsigned long address,
*/
static
inline
pte_t
*
get_empty_pgtable
(
struct
task_struct
*
tsk
,
unsigned
long
address
)
{
pgd_t
*
p
;
unsigned
long
page
;
p
=
PAGE_DIR_OFFSET
(
tsk
,
address
);
if
(
pgd_present
(
*
p
))
return
(
pte_t
*
)
(
PAGE_PTR
(
address
)
+
pgd_page
(
*
p
));
if
(
!
pgd_none
(
*
p
))
{
printk
(
"get_empty_pgtable: bad page-directory entry
\n
"
);
pgd_clear
(
p
);
}
page
=
get_free_page
(
GFP_KERNEL
);
if
(
pgd_present
(
*
p
))
{
free_page
(
page
);
return
(
pte_t
*
)
(
PAGE_PTR
(
address
)
+
pgd_page
(
*
p
));
}
if
(
!
pgd_none
(
*
p
))
{
printk
(
"get_empty_pgtable: bad page-directory entry
\n
"
);
pgd_clear
(
p
);
}
if
(
page
)
{
pgd_set
(
p
,
(
pte_t
*
)
page
);
return
(
pte_t
*
)
(
PAGE_PTR
(
address
)
+
page
);
}
oom
(
current
);
pgd_set
(
p
,
BAD_PAGETABLE
);
return
NULL
;
pgd_t
*
pgd
;
pmd_t
*
pmd
;
pte_t
*
pte
;
pgd
=
pgd_offset
(
tsk
,
address
);
pmd
=
pmd_alloc
(
pgd
,
address
);
if
(
!
pmd
)
return
NULL
;
pte
=
pte_alloc
(
pmd
,
address
);
return
pte
;
}
static
inline
void
do_swap_page
(
struct
vm_area_struct
*
vma
,
unsigned
long
address
,
...
...
@@ -929,7 +1011,6 @@ void do_no_page(struct vm_area_struct * vma, unsigned long address,
return
;
}
address
&=
PAGE_MASK
;
if
(
!
vma
->
vm_ops
||
!
vma
->
vm_ops
->
nopage
)
{
++
vma
->
vm_task
->
mm
->
rss
;
++
vma
->
vm_task
->
mm
->
min_flt
;
...
...
mm/mprotect.c
View file @
55415e93
...
...
@@ -53,6 +53,7 @@ static void change_protection(unsigned long start, unsigned long end, pgprot_t n
*
page_table
=
pte_modify
(
entry
,
newprot
);
++
page_table
;
}
while
(
--
offset
);
dir
++
;
}
return
;
}
...
...
mm/vmalloc.c
View file @
55415e93
#define THREE_LEVEL
/*
* linux/mm/vmalloc.c
*
...
...
@@ -32,7 +33,7 @@ static inline void set_pgdir(unsigned long address, pgd_t entry)
struct
task_struct
*
p
;
for_each_task
(
p
)
*
PAGE_DIR_OFFSET
(
p
,
address
)
=
entry
;
*
pgd_offset
(
p
,
address
)
=
entry
;
}
static
inline
void
free_area_pte
(
pmd_t
*
pmd
,
unsigned
long
address
,
unsigned
long
size
)
...
...
@@ -152,7 +153,7 @@ static int alloc_area_pages(unsigned long address, unsigned long size)
pgd_t
*
dir
;
unsigned
long
end
=
address
+
size
;
dir
=
PAGE_DIR_OFFSET
(
&
init_task
,
address
);
dir
=
pgd_offset
(
&
init_task
,
address
);
while
(
address
<
end
)
{
pmd_t
*
pmd
=
pmd_alloc_kernel
(
dir
,
address
);
if
(
!
pmd
)
...
...
net/inet/af_inet.c
View file @
55415e93
...
...
@@ -26,6 +26,8 @@
* this fixed and the accept bug fixed
* some RPC stuff seems happier.
* Niibe Yutaka : 4.4BSD style write async I/O
* Alan Cox,
* Tony Gale : Fixed reuse semantics.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
...
...
@@ -854,7 +856,7 @@ static int inet_bind(struct socket *sock, struct sockaddr *uaddr,
destroy_sock
(
sk2
);
goto
outside_loop
;
}
if
(
!
sk
->
reuse
)
if
(
!
sk
->
reuse
||
sk2
->
state
==
TCP_LISTEN
)
{
sti
();
return
(
-
EADDRINUSE
);
...
...
net/inet/arp.c
View file @
55415e93
...
...
@@ -680,7 +680,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
having to use a huge number of proxy arp entries
and having to keep them uptodate.
*/
if
(
proxy_entry
->
htype
==
htype
&&
if
(
proxy_entry
->
dev
!=
dev
&&
!
((
proxy_entry
->
ip
^
tip
)
&
proxy_entry
->
mask
))
break
;
...
...
net/inet/igmp.c
View file @
55415e93
...
...
@@ -179,7 +179,7 @@ static void igmp_group_dropped(struct ip_mc_list *im)
del_timer
(
&
im
->
timer
);
igmp_send_report
(
im
->
interface
,
im
->
multiaddr
,
IGMP_HOST_LEAVE_MESSAGE
);
ip_mc_filter_del
(
im
->
interface
,
im
->
multiaddr
);
printk
(
"Left group %lX
\n
"
,
im
->
multiaddr
);
/* printk("Left group %lX\n",im->multiaddr);*/
}
static
void
igmp_group_added
(
struct
ip_mc_list
*
im
)
...
...
@@ -187,7 +187,7 @@ static void igmp_group_added(struct ip_mc_list *im)
igmp_init_timer
(
im
);
igmp_send_report
(
im
->
interface
,
im
->
multiaddr
,
IGMP_HOST_MEMBERSHIP_REPORT
);
ip_mc_filter_add
(
im
->
interface
,
im
->
multiaddr
);
printk
(
"Joined group %lX
\n
"
,
im
->
multiaddr
);
/* printk("Joined group %lX\n",im->multiaddr);*/
}
int
igmp_rcv
(
struct
sk_buff
*
skb
,
struct
device
*
dev
,
struct
options
*
opt
,
...
...
net/inet/ip_fw.c
View file @
55415e93
...
...
@@ -1005,38 +1005,23 @@ static int ip_chain_procinfo(int stage, char *buffer, char **start,
#ifdef CONFIG_IP_ACCT
int
ip_acct_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
ip_acct_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
,
int
reset
)
{
return
ip_chain_procinfo
(
IP_INFO_ACCT
,
buffer
,
start
,
offset
,
length
,
0
);
}
int
ip_acct0_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
return
ip_chain_procinfo
(
IP_INFO_ACCT
,
buffer
,
start
,
offset
,
length
,
1
);
return
ip_chain_procinfo
(
IP_INFO_ACCT
,
buffer
,
start
,
offset
,
length
,
reset
);
}
#endif
#ifdef CONFIG_IP_FIREWALL
int
ip_fw_blk_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
return
ip_chain_procinfo
(
IP_INFO_BLK
,
buffer
,
start
,
offset
,
length
,
0
);
}
int
ip_fw_blk0_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
{
return
ip_chain_procinfo
(
IP_INFO_BLK
,
buffer
,
start
,
offset
,
length
,
1
);
}
int
ip_fw_fwd_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
ip_fw_blk_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
,
int
reset
)
{
return
ip_chain_procinfo
(
IP_INFO_
FWD
,
buffer
,
start
,
offset
,
length
,
0
);
return
ip_chain_procinfo
(
IP_INFO_
BLK
,
buffer
,
start
,
offset
,
length
,
reset
);
}
int
ip_fw_fwd
0_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
)
int
ip_fw_fwd
_procinfo
(
char
*
buffer
,
char
**
start
,
off_t
offset
,
int
length
,
int
reset
)
{
return
ip_chain_procinfo
(
IP_INFO_FWD
,
buffer
,
start
,
offset
,
length
,
1
);
return
ip_chain_procinfo
(
IP_INFO_FWD
,
buffer
,
start
,
offset
,
length
,
reset
);
}
#endif
net/inet/ipx.c
View file @
55415e93
...
...
@@ -544,7 +544,12 @@ ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
ipx_interface
*
i
;
/* See if we should update our network number */
if
((
intrfc
->
if_netnum
==
0L
)
&&
(
ipx
->
ipx_tctrl
==
0
))
{
if
((
intrfc
->
if_netnum
==
0L
)
&&
(
ipx
->
ipx_source
.
net
==
ipx
->
ipx_dest
.
net
))
{
/* NB: NetWare servers lie about their hop count so we
* dropped the test based on it. This is the best way
* to determine this is a 0 hop count packet.
*/
if
((
i
=
ipxitf_find_using_net
(
ipx
->
ipx_source
.
net
))
==
NULL
)
{
intrfc
->
if_netnum
=
ipx
->
ipx_source
.
net
;
(
void
)
ipxitf_add_local_route
(
intrfc
);
...
...
@@ -558,8 +563,15 @@ ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
}
}
if
(
intrfc
->
if_netnum
!=
ipx
->
ipx_dest
.
net
)
return
ipxrtr_route_skb
(
skb
);
if
(
intrfc
->
if_netnum
!=
ipx
->
ipx_dest
.
net
)
{
/* We only route point-to-point packets. */
if
((
skb
->
pkt_type
!=
PACKET_BROADCAST
)
&&
(
skb
->
pkt_type
!=
PACKET_MULTICAST
))
return
ipxrtr_route_skb
(
skb
);
kfree_skb
(
skb
,
FREE_READ
);
return
0
;
}
/* see if we should keep it */
if
((
memcmp
(
ipx_broadcast_node
,
ipx
->
ipx_dest
.
node
,
IPX_NODE_LEN
)
==
0
)
...
...
net/inet/route.c
View file @
55415e93
...
...
@@ -301,7 +301,8 @@ void ip_rt_add(short flags, unsigned long dst, unsigned long mask,
rp
=
&
rt_base
;
while
((
r
=
*
rp
)
!=
NULL
)
{
if
(
r
->
rt_dst
!=
dst
)
if
(
r
->
rt_dst
!=
dst
||
r
->
rt_mask
!=
mask
)
{
rp
=
&
r
->
rt_next
;
continue
;
...
...
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