Commit 55415e93 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.91

parent 40820e9a
......@@ -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
......
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 90
SUBLEVEL = 91
ARCH = i386
......
......@@ -46,15 +46,6 @@ void show_regs(struct pt_regs * regs)
printk("\nPS: %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..
*/
......
......@@ -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_DE4x5 n
bool 'DE425, DE434, DE435 support' CONFIG_DE4X5 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
......
......@@ -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..
*/
......
......@@ -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)
......
......@@ -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>. Additionnaly, this drive is
Sets the cmos type of <drive> to <type>. Additionally, 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:
......
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.
......@@ -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"
......
......@@ -91,7 +91,7 @@
#include <linux/config.h>
/* do print messages for unexpected interupts */
/* do print messages for unexpected interrupts */
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 thinkpad related quirks! */
void floppy_invert_dcl(int *ints,int param)
{
int i;
......
......@@ -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
......
/*
* 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 */
......@@ -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) {
......
......@@ -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.
......
......@@ -194,11 +194,13 @@ ifdef CONFIG_ATP
NETDRV_OBJS := $(NETDRV_OBJS) atp.o
endif
ifdef CONFIG_DE4x5
ifdef CONFIG_DE4X5
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
......
......@@ -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!
......
......@@ -115,7 +115,7 @@ ethif_probe(struct device *dev)
#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */
&& ewrk3_probe(dev)
#endif
#ifdef CONFIG_DE4x5 /* DEC DE425, DE434, DE435 adapters */
#ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */
&& de4x5_probe(dev)
#endif
#ifdef CONFIG_APRICOT /* Apricot I82596 */
......
......@@ -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;
......
......@@ -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.21 1/19/95 davies@wanton.lkg.dec.com\n";
static char *version = "de4x5.c:v0.22 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/DC21041/DC21140 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("\tchecked memory: 0x%08lx\n",eisa_slots_full);
printk("Descriptor head addresses:\n");
printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
printk("Descriptor addresses:\nRX: ");
......@@ -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=0x2000; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
int io=0x000b; /* <--- 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)
*/
......@@ -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.381 12/12/94 davies@wanton.lkg.dec.com\n";
static char *version = "depca.c:v0.382 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);
}
}
......
/* $Id: plip.c,v 1.10 1995/02/08 05:47:12 gniibe Exp $ */
/* $Id: plip.c,v 1.12 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->length < 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;
......
/*
* 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 preforming a reset.
* Cleared target_time_out counter while performing 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;
......
......@@ -7,7 +7,7 @@
#include <linux/scsicam.h>
#define EATA_VERSION "1.15.00"
#define EATA_VERSION "1.16.00"
int eata2x_detect(Scsi_Host_Template *);
int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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)
......
/*
* 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 preforming a reset.
* Cleared target_time_out counter while performing 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;
......
......@@ -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.15.00"
#define U14_34F_VERSION "1.16.00"
#define ULTRASTOR_14_34F { \
NULL, /* Ptr for modules */ \
......
......@@ -79,7 +79,7 @@ Snail mail: Hannu Savolainen
Finland
FAX: +358 0 341 6272 (answers if I have my machine (mgetty) on).
NOTE! I propably don't answer to Snail mail or FAX messages. Sending answer
NOTE! I probably 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
......
......@@ -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_IPACCT0) {
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_IRUGO | S_IWUSR;
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_IPFWFWD0) || (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_IRUGO | S_IWUSR;
inode->i_op = &proc_net_inode_operations;
return;
}
......
......@@ -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
......
......@@ -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)
......
......@@ -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 */
......@@ -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 */
......@@ -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;
......
......@@ -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 */
......@@ -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 */
......@@ -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.
......
......@@ -27,7 +27,7 @@
*
* "this is gonna have to change to 1gig for the sparc" - David S. Miller
*/
#define TASK_SIZE (0xc0000000UL)
#define TASK_SIZE (0xC0000000UL)
/*
* Size of io_bitmap in longwords: 32 is ports 0-0x3ff.
......
......@@ -20,7 +20,6 @@ struct plipconf
unsigned short pcmd;
unsigned long nibble;
unsigned long trigger;
unsigned long unit;
};
#define PLIP_GET_TIMEOUT 0x1
......
......@@ -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,
......
......@@ -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);
......
#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 */
......@@ -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
......
......@@ -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),
......
#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 (pgd_none(pg_table))
if (pmd_none(*dir))
return;
pgd_clear(page_dir);
if (pgd_bad(pg_table)) {
printk("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));
pmd_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(page_table);
free_page(page);
}
for (j = 0; j < PTRS_PER_PTE ; j++)
free_one_pte(pte+j);
pte_free(pte);
}
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_PAGE ; i++)
free_one_table(page_dir + i);
free_page((unsigned long) page_dir);
for (i = 0 ; i < PTRS_PER_PGD ; 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_page_dir;
pgd_t *new_page_dir;
pgd_t *old_pgd;
pgd_t *new_pgd;
new_page_dir = (pgd_t *) get_free_page(GFP_KERNEL);
if (!new_page_dir)
new_pgd = pgd_alloc();
if (!new_pgd)
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(page_table);
pte_clear(pte);
invalidate();
}
*page_table = pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY)));
*pte = 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;
......
......@@ -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;
}
......
#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)
......
......@@ -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);
......
......@@ -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;
......
......@@ -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,
......
......@@ -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_fwd0_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
......@@ -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)
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment