Commit a6614639 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.61

parent ba97e35a
...@@ -64,7 +64,7 @@ S: 6369 BG Simpelveld ...@@ -64,7 +64,7 @@ S: 6369 BG Simpelveld
S: The Netherlands S: The Netherlands
N: Hennus Bergman N: Hennus Bergman
E: hennus@sky.nl.mugnet.org [My uucp-fed Linux box at home] E: hennus@sky.ow.org [My uucp-fed Linux box at home]
D: Author and maintainer of the QIC-02 tape driver D: Author and maintainer of the QIC-02 tape driver
S: The Netherlands S: The Netherlands
......
VERSION = 1 VERSION = 1
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 60 SUBLEVEL = 61
ARCH = i386 ARCH = i386
......
This README belongs to release 2.6 or newer of the SoundBlaster Pro This README belongs to release 2.7 or newer of the SoundBlaster Pro
(Matsushita, Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux. (Matsushita, Kotobuki, Panasonic, CreativeLabs) CD-ROM driver for Linux.
The driver is able to drive the whole family of "traditional" IDE-style (that The driver is able to drive the whole family of "traditional" IDE-style (that
...@@ -6,6 +6,14 @@ has nothing to do with the new "Enhanced IDE" drive standard) Matsushita, ...@@ -6,6 +6,14 @@ has nothing to do with the new "Enhanced IDE" drive standard) Matsushita,
Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The
well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563. well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563.
There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-562
with a special controller board. This drive is supported (the interface is
of the "LaserMate" type), and it is possibly the best buy today (cheaper than
an internal drive, and you can use it as an internal, too - f.e. plug it into
a soundcard). If you own such a drive, please mail me the DOS driver (gzipped
and uuencoded) and the specifications (exact name, address range etc.) I still
have to confirm my opinion. ;-)
This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives. This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives.
The matter that some other brand's drives work with newer sound card The matter that some other brand's drives work with newer sound card
interfaces does NOT make the drives compatible. :-) interfaces does NOT make the drives compatible. :-)
...@@ -49,8 +57,8 @@ to change old drives to any ID, too. He writes in this sense: ...@@ -49,8 +57,8 @@ to change old drives to any ID, too. He writes in this sense:
To use more than 4 drives (now that the single-speed CR-521's are as cheap as To use more than 4 drives (now that the single-speed CR-521's are as cheap as
50$), you need a second interface card and you have to "duplicate" the driver. 50$), you need a second interface card and you have to "duplicate" the driver.
Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE (at top
accordingly. of sbpcd2.c) accordingly.
The driver supports reading of data from the CD and playing of audio tracks. The driver supports reading of data from the CD and playing of audio tracks.
The audio part should run with WorkMan, xcdplayer, with the "non-X11" products The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
...@@ -72,9 +80,10 @@ the beginning of each single frame. ...@@ -72,9 +80,10 @@ the beginning of each single frame.
The software interface possibly may change a bit the day the SCSI driver The software interface possibly may change a bit the day the SCSI driver
supports it too. supports it too.
MultiSession is supported, "ManySession" (not recommended, see below) With the CR-562 and CR-563 drives, MultiSession is supported, "ManySession"
alternatively. (not recommended, see below) alternatively.
Photo CDs work, too (even with my "old" CR-521). Photo CDs work, too (the "old" drives like CR-521 can access only the first
session of a photoCD).
At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
photo CD image files. photo CD image files.
...@@ -189,6 +198,57 @@ distribution) which MUST get handled with a block_size of 1024. Generally, ...@@ -189,6 +198,57 @@ distribution) which MUST get handled with a block_size of 1024. Generally,
one can say all the CDs which hold files of the name YMTRANS.TBL are defective; one can say all the CDs which hold files of the name YMTRANS.TBL are defective;
do not use block=2048 with those. do not use block=2048 with those.
At the beginning of sbpcd.c, you will find some "#define"s (f.e. EJECT and
JUKEBOX). With that, you can configure the driver for some special things.
The following program disables the auto-eject feature during runtime:
/*=================== begin program ========================================*/
/*
* set the "eject" switch (enable/disable auto-ejecting)
*
* (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de>
* may be used & enhanced freely
*
* Disables or enables the auto-eject feature at run time.
* Works only if a CD is in the drive (just like the feature itself ;-)
* Useful for a "quiet" shutdown or for weird audio player programs.
*/
#define EJECT 0 /* 0: disable, 1: enable auto-ejecting */
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
static char arg=EJECT;
static int drive;
static int err;
main(int argc, char *argv[])
{
/*
* open /dev/cdrom
*/
drive=open("/dev/cdrom", 0);
if (drive<0)
{
fprintf(stderr, "can't open drive /dev/cdrom.\n");
exit (-1);
}
/*
* set EJECT_SW
*/
err=ioctl(drive, CDROMEJECT_SW, arg);
if (err!=0)
{
fprintf(stderr, "can't set EJECT_SW (error %d).\n", err);
exit (-1);
}
else
fprintf(stdout, "EJECT_SW set to %d\n", arg);
}
/*===================== end program ========================================*/
Auto-probing at boot time: Auto-probing at boot time:
-------------------------- --------------------------
......
...@@ -2856,8 +2856,8 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end) ...@@ -2856,8 +2856,8 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
{ {
if (request_irq(irq_used, cdu31a_interrupt, SA_INTERRUPT, "cdu31a")) if (request_irq(irq_used, cdu31a_interrupt, SA_INTERRUPT, "cdu31a"))
{ {
irq_used = 0;
printk("Unable to grab IRQ%d for the CDU31A driver\n", irq_used); printk("Unable to grab IRQ%d for the CDU31A driver\n", irq_used);
irq_used = 0;
} }
} }
......
...@@ -348,6 +348,7 @@ struct floppy_struct *current_type[N_DRIVE] = { ...@@ -348,6 +348,7 @@ struct floppy_struct *current_type[N_DRIVE] = {
struct floppy_struct user_params[N_DRIVE]; struct floppy_struct user_params[N_DRIVE];
static int floppy_sizes[256]; static int floppy_sizes[256];
static int floppy_blocksizes[256] = { 0, };
/* /*
* The driver is trying to determine the correct media format * The driver is trying to determine the correct media format
...@@ -2848,7 +2849,7 @@ static int floppy_open(struct inode * inode, struct file * filp) ...@@ -2848,7 +2849,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
if (floppy_grab_irq_and_dma()) if (floppy_grab_irq_and_dma())
return -EBUSY; return -EBUSY;
if(filp->f_flags & O_EXCL) if (filp->f_flags & O_EXCL)
UDRS->fd_ref = -1; UDRS->fd_ref = -1;
else else
UDRS->fd_ref++; UDRS->fd_ref++;
...@@ -2956,7 +2957,10 @@ static int floppy_revalidate(dev_t dev) ...@@ -2956,7 +2957,10 @@ static int floppy_revalidate(dev_t dev)
UDRS->generation++; UDRS->generation++;
if(!current_type[drive] && !TYPE(dev)){ if(!current_type[drive] && !TYPE(dev)){
/* auto-sensing */ /* auto-sensing */
if (!(bh = getblk(dev,0,1024))){ int size = floppy_blocksizes[MINOR(dev)];
if (!size)
size = 1024;
if (!(bh = getblk(dev,0,size))){
redo_fd_request(); redo_fd_request();
return 1; return 1;
} }
...@@ -3062,6 +3066,7 @@ void floppy_init(void) ...@@ -3062,6 +3066,7 @@ void floppy_init(void)
floppy_sizes[i] = MAX_DISK_SIZE; floppy_sizes[i] = MAX_DISK_SIZE;
blk_size[MAJOR_NR] = floppy_sizes; blk_size[MAJOR_NR] = floppy_sizes;
blksize_size[MAJOR_NR] = floppy_blocksizes;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
timer_table[FLOPPY_TIMER].fn = floppy_shutdown; timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
timer_active &= ~(1 << FLOPPY_TIMER); timer_active &= ~(1 << FLOPPY_TIMER);
......
...@@ -1182,7 +1182,6 @@ mcd_init(unsigned long mem_start, unsigned long mem_end) ...@@ -1182,7 +1182,6 @@ mcd_init(unsigned long mem_start, unsigned long mem_end)
mcd_invalidate_buffers(); mcd_invalidate_buffers();
mcdPresent = 1; mcdPresent = 1;
printk("\n");
return mem_start; return mem_start;
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* and for "no-sound" interfaces like Lasermate and the * and for "no-sound" interfaces like Lasermate and the
* Panasonic CI-101P. * Panasonic CI-101P.
* *
* NOTE: This is release 2.6. * NOTE: This is release 2.7.
* It works with my SbPro & drive CR-521 V2.11 from 2/92 * It works with my SbPro & drive CR-521 V2.11 from 2/92
* and with the new CR-562-B V0.75 on a "naked" Panasonic * and with the new CR-562-B V0.75 on a "naked" Panasonic
* CI-101P interface. And vice versa. * CI-101P interface. And vice versa.
...@@ -128,6 +128,10 @@ ...@@ -128,6 +128,10 @@
* *
* 2.6 Nothing new. * 2.6 Nothing new.
* *
* 2.7 Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly:
* 0 disables, 1 enables auto-ejecting. Useful to keep the tray in
* during shutdown.
*
* TODO * TODO
* *
* disk change detection * disk change detection
...@@ -203,7 +207,7 @@ ...@@ -203,7 +207,7 @@
#include "blk.h" #include "blk.h"
#define VERSION "2.6 Eberhard Moenkeberg <emoenke@gwdg.de>" #define VERSION "2.7 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define SBPCD_DEBUG #define SBPCD_DEBUG
...@@ -303,6 +307,9 @@ static int autoprobe[] = ...@@ -303,6 +307,9 @@ static int autoprobe[] =
0x320, 2, /* SPEA Media FX */ 0x320, 2, /* SPEA Media FX */
0x340, 2, /* SPEA Media FX */ 0x340, 2, /* SPEA Media FX */
0x350, 2, /* SPEA Media FX */ 0x350, 2, /* SPEA Media FX */
/* due to incomplete address decoding of the SbPro card, these must be last */
0x630, 0, /* "sound card #9" (default) */
0x650, 0, /* "sound card #9" */
#if 0 #if 0
/* some "hazardous" locations (ethernet cards) */ /* some "hazardous" locations (ethernet cards) */
0x330, 0, /* Lasermate, CI-101P, WDH-7001C */ 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
...@@ -310,9 +317,6 @@ static int autoprobe[] = ...@@ -310,9 +317,6 @@ static int autoprobe[] =
0x370, 0, /* Lasermate, CI-101P */ 0x370, 0, /* Lasermate, CI-101P */
0x290, 1, /* Soundblaster 16 */ 0x290, 1, /* Soundblaster 16 */
0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
/* excluded due to incomplete address decoding of the SbPro card */
0x630, 0, /* "sound card #9" (default) */
0x650, 0, /* "sound card #9" */
#endif #endif
}; };
...@@ -390,6 +394,7 @@ static int sbpcd_debug = (1<<DBG_INF) | ...@@ -390,6 +394,7 @@ static int sbpcd_debug = (1<<DBG_INF) |
#else #else
static int sbpcd_debug = (1<<DBG_INF) | static int sbpcd_debug = (1<<DBG_INF) |
(1<<DBG_TOC) | (1<<DBG_TOC) |
(1<<DBG_MUL) |
(1<<DBG_UPC); (1<<DBG_UPC);
#endif #endif
#endif #endif
...@@ -481,6 +486,7 @@ static struct { ...@@ -481,6 +486,7 @@ static struct {
char drive_model[4]; char drive_model[4];
char firmware_version[4]; char firmware_version[4];
char f_eject; /* auto-eject flag: 0 or 1 */
u_char *sbp_buf; /* Pointer to internal data buffer, u_char *sbp_buf; /* Pointer to internal data buffer,
space allocated during sbpcd_init() */ space allocated during sbpcd_init() */
int sbp_first_frame; /* First frame in buffer */ int sbp_first_frame; /* First frame in buffer */
...@@ -2390,7 +2396,7 @@ static int sbp_status(void) ...@@ -2390,7 +2396,7 @@ static int sbp_status(void)
/*==========================================================================*/ /*==========================================================================*/
/*==========================================================================*/ /*==========================================================================*/
/* /*
* ioctl support, adopted from scsi/sr_ioctl.c and mcd.c * ioctl support
*/ */
static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg) u_long arg)
...@@ -2583,6 +2589,12 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, ...@@ -2583,6 +2589,12 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
DriveStruct[d].audio_state=0; DriveStruct[d].audio_state=0;
return (0); return (0);
case CDROMEJECT_SW:
DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT_SW entered.\n"));
if (!new_drive) return (0);
DriveStruct[d].f_eject=arg;
return (0);
case CDROMVOLCTRL: /* Volume control */ case CDROMVOLCTRL: /* Volume control */
DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n")); DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n"));
st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl)); st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl));
...@@ -2918,7 +2930,9 @@ static void DO_SBPCD_REQUEST(void) ...@@ -2918,7 +2930,9 @@ static void DO_SBPCD_REQUEST(void)
} }
DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect)); DPRINTF((DBG_BSZ,"SBPCD: read sector %d (%d sectors)\n", block, nsect));
#if 0
DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4)); DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4));
#endif
sbp_transfer(); sbp_transfer();
/* if we satisfied the request from the buffer, we're done. */ /* if we satisfied the request from the buffer, we're done. */
...@@ -3007,7 +3021,7 @@ static void sbp_read_cmd(void) ...@@ -3007,7 +3021,7 @@ static void sbp_read_cmd(void)
DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n", DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n",
blk2msf(DriveStruct[d].lba_multi+16), blk2msf(DriveStruct[d].lba_multi+16),
blk2msf(block))); blk2msf(block)));
block=DriveStruct[d].lba_multi+16; block=DriveStruct[d].lba_multi+block;
} }
#endif MANY_SESSION #endif MANY_SESSION
} }
...@@ -3323,9 +3337,7 @@ static void sbpcd_release(struct inode * ip, struct file * file) ...@@ -3323,9 +3337,7 @@ static void sbpcd_release(struct inode * ip, struct file * file)
do do
i=yy_LockDoor(0); i=yy_LockDoor(0);
while (i!=0); while (i!=0);
#if EJECT if (DriveStruct[d].f_eject) yy_SpinDown();
if (new_drive) yy_SpinDown();
#endif
} }
} }
} }
...@@ -3550,6 +3562,12 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end) ...@@ -3550,6 +3562,12 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
DriveStruct[d].sbp_current = 0; /* Frame being currently read */ DriveStruct[d].sbp_current = 0; /* Frame being currently read */
DriveStruct[d].CD_changed=1; DriveStruct[d].CD_changed=1;
DriveStruct[d].frame_size=CD_FRAMESIZE; DriveStruct[d].frame_size=CD_FRAMESIZE;
#if EJECT
if (new_drive) DriveStruct[d].f_eject=1;
else DriveStruct[d].f_eject=0;
#else
DriveStruct[d].f_eject=0;
#endif
xx_ReadStatus(); xx_ReadStatus();
i=ResponseStatus(); /* returns orig. status or p_busy_new */ i=ResponseStatus(); /* returns orig. status or p_busy_new */
......
/* $Id: tpqic02.c,v 0.4.1.4 1994/07/21 02:15:45 root Exp root $ /* $Id: tpqic02.c,v 0.4.1.5 1994/10/29 02:46:13 root Exp root $
* *
* Driver for tape drive support for Linux-i386 1.1.30 * Driver for tape drive support for Linux-i386 1.1.58
* *
* Copyright (c) 1992, 1993, 1994 by H. H. Bergman. All rights reserved. * Copyright (c) 1992, 1993, 1994 by H. H. Bergman. All rights reserved.
* Current e-mail address: hennus@sky.nl.mugnet.org [This is a UUCP link.] * Current e-mail address: hennus@sky.ow.org [This is a UUCP link.]
* Secondary e-mail address: csg279@wing.rug.nl [IP connected, but flaky]
* [If you are unable to reach me directly, try the TAPE mailing list * [If you are unable to reach me directly, try the TAPE mailing list
* channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as * channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as
* the first line in your message.] * the first line in your message.]
...@@ -35,6 +34,9 @@ ...@@ -35,6 +34,9 @@
* You are not allowed to change this line nor the text above. * You are not allowed to change this line nor the text above.
* *
* $Log: tpqic02.c,v $ * $Log: tpqic02.c,v $
* Revision 0.4.1.5 1994/10/29 02:46:13 root
* Minor cleanups.
*
* Revision 0.4.1.4 1994/07/21 02:15:45 root * Revision 0.4.1.4 1994/07/21 02:15:45 root
* ifdef'd DDI. Exception masks. * ifdef'd DDI. Exception masks.
* *
...@@ -191,10 +193,8 @@ ...@@ -191,10 +193,8 @@
* Also, be careful to avoid IO conflicts with other devices! * Also, be careful to avoid IO conflicts with other devices!
*/ */
#include <linux/config.h> #include <linux/autoconf.h>
/* skip this driver if not required for this configuration */
#if CONFIG_QIC02_TAPE
/* /*
#define TDEBUG #define TDEBUG
...@@ -233,8 +233,8 @@ ...@@ -233,8 +233,8 @@
*/ */
#ifdef CONFIG_QIC02_DYNCONF #ifdef CONFIG_QIC02_DYNCONF
/* This may hold the dynamic configuration info for the interface /* This holds the dynamic configuration info for the interface
* card+drive info in future versions. * card+drive info if runtime configuration has been selected.
*/ */
struct mtconfiginfo qic02_tape_dynconf = { 0, }; /* user settable */ struct mtconfiginfo qic02_tape_dynconf = { 0, }; /* user settable */
struct qic02_ccb qic02_tape_ccb = { 0, }; /* private stuff */ struct qic02_ccb qic02_tape_ccb = { 0, }; /* private stuff */
...@@ -256,8 +256,8 @@ static volatile struct mtget ioctl_status; /* current generic status */ ...@@ -256,8 +256,8 @@ static volatile struct mtget ioctl_status; /* current generic status */
static volatile struct tpstatus tperror; /* last drive status */ static volatile struct tpstatus tperror; /* last drive status */
static char rcs_revision[] = "$Revision: 0.4.1.4 $"; static char rcs_revision[] = "$Revision: 0.4.1.5 $";
static char rcs_date[] = "$Date: 1994/07/21 02:15:45 $"; static char rcs_date[] = "$Date: 1994/10/29 02:46:13 $";
/* Flag bits for status and outstanding requests. /* Flag bits for status and outstanding requests.
* (Could all be put in one bit-field-struct.) * (Could all be put in one bit-field-struct.)
...@@ -285,7 +285,7 @@ static volatile unsigned long dma_bytes_done; ...@@ -285,7 +285,7 @@ static volatile unsigned long dma_bytes_done;
static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */ static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */
static flag need_rewind = YES; static flag need_rewind = YES;
static dev_t current_tape_dev = QIC02_TAPE_MAJOR << 8; static dev_t current_tape_dev = MKDEV(QIC02_TAPE_MAJOR, 0);
static int extra_blocks_left = BLOCKS_BEYOND_EW; static int extra_blocks_left = BLOCKS_BEYOND_EW;
...@@ -570,7 +570,9 @@ static void report_error(int s) ...@@ -570,7 +570,9 @@ static void report_error(int s)
#endif #endif
/* perform appropriate action for certain exceptions */ /* Perform appropriate action for certain exceptions.
* should return a value to indicate stop/continue (in case of bad blocks)
*/
static void handle_exception(int exnr, int exbits) static void handle_exception(int exnr, int exbits)
{ {
if (exnr==EXC_NCART) { if (exnr==EXC_NCART) {
...@@ -1358,9 +1360,7 @@ static int do_ioctl_cmd(int cmd) ...@@ -1358,9 +1360,7 @@ static int do_ioctl_cmd(int cmd)
return do_qic_cmd(QCMD_REWIND, TIM_R); return do_qic_cmd(QCMD_REWIND, TIM_R);
case MTOFFL: case MTOFFL:
tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline"); /*---*/ tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline");
/******* What exactly are we supposed to do, to take it offline????
*****/
/* Doing a drive select will clear (unlock) the current drive. /* Doing a drive select will clear (unlock) the current drive.
* But that requires support for multiple drives and locking. * But that requires support for multiple drives and locking.
*/ */
...@@ -1927,8 +1927,9 @@ static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf, ...@@ -1927,8 +1927,9 @@ static int qic02_tape_read(struct inode * inode, struct file * filp, char * buf,
} }
if (TP_DIAGS(current_tape_dev)) if (TP_DIAGS(current_tape_dev))
/* can't print a ``long long'' (for filp->f_pos), so chop it */
printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n", printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
MINOR(dev), buf, count, filp->f_pos, flags); MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */ if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */
tpqputs(TPQD_BLKSZ, "Wrong block size"); tpqputs(TPQD_BLKSZ, "Wrong block size");
...@@ -2100,8 +2101,9 @@ static int qic02_tape_write(struct inode * inode, struct file * filp, char * buf ...@@ -2100,8 +2101,9 @@ static int qic02_tape_write(struct inode * inode, struct file * filp, char * buf
} }
if (TP_DIAGS(current_tape_dev)) if (TP_DIAGS(current_tape_dev))
/* can't print a ``long long'' (for filp->f_pos), so chop it */
printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n", printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%x, pos=%lx, flags=%x\n",
MINOR(dev), buf, count, filp->f_pos, flags); MINOR(dev), buf, count, (unsigned long) filp->f_pos, flags);
if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */ if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */
tpqputs(TPQD_BLKSZ, "Wrong block size"); tpqputs(TPQD_BLKSZ, "Wrong block size");
...@@ -2587,7 +2589,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, ...@@ -2587,7 +2589,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
if (!suser()) if (!suser())
return -EPERM; return -EPERM;
verify_area(VERIFY_READ, (int *) ioarg, sizeof(int)); verify_area(VERIFY_READ, (int *) ioarg, sizeof(int));
c = get_fs_long((int *) ioarg); c = get_user_long((int *) ioarg);
if (c==0) { if (c==0) {
QIC02_TAPE_DEBUG = 0; QIC02_TAPE_DEBUG = 0;
return 0; return 0;
...@@ -2619,7 +2621,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, ...@@ -2619,7 +2621,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
stp = (char *) &qic02_tape_dynconf; stp = (char *) &qic02_tape_dynconf;
argp = (char *) ioarg; argp = (char *) ioarg;
for (i=0; i<sizeof(qic02_tape_dynconf); i++) for (i=0; i<sizeof(qic02_tape_dynconf); i++)
put_fs_byte(*stp++, argp++); put_user_byte(*stp++, argp++);
return 0; return 0;
} else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) { } else if (c == (MTIOCSETCONFIG & IOCCMD_MASK)) {
...@@ -2646,7 +2648,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, ...@@ -2646,7 +2648,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
stp = (char *) &qic02_tape_dynconf; stp = (char *) &qic02_tape_dynconf;
argp = (char *) ioarg; argp = (char *) ioarg;
for (i=0; i<sizeof(qic02_tape_dynconf); i++) for (i=0; i<sizeof(qic02_tape_dynconf); i++)
*stp++ = get_fs_byte(argp++); *stp++ = get_user_byte(argp++);
if (status_zombie==NO) if (status_zombie==NO)
qic02_release_resources(); /* and go zombie */ qic02_release_resources(); /* and go zombie */
if (update_ifc_masks(qic02_tape_dynconf.ifc_type)) if (update_ifc_masks(qic02_tape_dynconf.ifc_type))
...@@ -2678,7 +2680,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, ...@@ -2678,7 +2680,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
stp = (char *) &operation; stp = (char *) &operation;
argp = (char *) ioarg; argp = (char *) ioarg;
for (i=0; i<sizeof(operation); i++) for (i=0; i<sizeof(operation); i++)
*stp++ = get_fs_byte(argp++); *stp++ = get_user_byte(argp++);
/* ---note: mt_count is signed, negative seeks must be /* ---note: mt_count is signed, negative seeks must be
* --- translated to seeks in opposite direction! * --- translated to seeks in opposite direction!
...@@ -2740,7 +2742,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, ...@@ -2740,7 +2742,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
stp = (char *) &ioctl_status; stp = (char *) &ioctl_status;
argp = (char *) ioarg; argp = (char *) ioarg;
for (i=0; i<sizeof(ioctl_status); i++) for (i=0; i<sizeof(ioctl_status); i++)
put_fs_byte(*stp++, argp++); put_user_byte(*stp++, argp++);
return 0; return 0;
...@@ -2773,7 +2775,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp, ...@@ -2773,7 +2775,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
stp = (char *) &ioctl_tell; stp = (char *) &ioctl_tell;
argp = (char *) ioarg; argp = (char *) ioarg;
for (i=0; i<sizeof(ioctl_tell); i++) for (i=0; i<sizeof(ioctl_tell); i++)
put_fs_byte(*stp++, argp++); put_user_byte(*stp++, argp++);
return 0; return 0;
} else } else
...@@ -2793,7 +2795,10 @@ static struct file_operations qic02_tape_fops = { ...@@ -2793,7 +2795,10 @@ static struct file_operations qic02_tape_fops = {
NULL, /* mmap not allowed */ NULL, /* mmap not allowed */
qic02_tape_open, /* open */ qic02_tape_open, /* open */
qic02_tape_release, /* release */ qic02_tape_release, /* release */
NULL /* fsync */ NULL, /* fsync */
NULL, /* fasync */
NULL, /* check_media_change */
NULL /* revalidate */
}; };
/* align `a' at `size' bytes. `size' must be a power of 2 */ /* align `a' at `size' bytes. `size' must be a power of 2 */
...@@ -2870,7 +2875,6 @@ static int qic02_get_resources(void) ...@@ -2870,7 +2875,6 @@ static int qic02_get_resources(void)
/* init() is called from chr_dev_init() in drivers/char/mem.c */
long qic02_tape_init(long kmem_start) long qic02_tape_init(long kmem_start)
/* Shouldn't this be a caddr_t ? */ /* Shouldn't this be a caddr_t ? */
{ {
...@@ -2969,5 +2973,3 @@ long qic02_tape_init(long kmem_start) ...@@ -2969,5 +2973,3 @@ long qic02_tape_init(long kmem_start)
return kmem_start; return kmem_start;
} /* qic02_tape_init */ } /* qic02_tape_init */
#endif /* CONFIG_QIC02_TAPE */
...@@ -34,9 +34,10 @@ ...@@ -34,9 +34,10 @@
# DE620_IO The DE620 I/O-port address (0x378 == default) # DE620_IO The DE620 I/O-port address (0x378 == default)
# DE620_IRQ The DE620 IRQ number to use (IRQ7 == default) # DE620_IRQ The DE620 IRQ number to use (IRQ7 == default)
# DE620_DEBUG Enable or disable DE600 debugging (default off) # DE620_DEBUG Enable or disable DE600 debugging (default off)
# DEPCA The DIGITAL series of AT Ethernet Cards (DE100, DE200) # DEPCA The DIGITAL series of LANCE based Ethernet Cards
# DEPCA_IRQ Set the desired IRQ (=0, for autoprobe) # (DEPCA, DE100, DE200/1/2, DE210, DE422 (EISA))
# DEPCA_DEBUG Set the desired debug level # EWRK3 The DIGITAL series of AT Ethernet Cards (DE203/4/5)
# EWRK3_DEBUG Set the desired debug level
# #
# The following options exist, but cannot be set in this file. # The following options exist, but cannot be set in this file.
...@@ -57,4 +58,5 @@ EL2_OPTS = #-DEL2_AUI ...@@ -57,4 +58,5 @@ EL2_OPTS = #-DEL2_AUI
NE_OPTS = NE_OPTS =
HP_OPTS = HP_OPTS =
PLIP_OPTS = PLIP_OPTS =
DEPCA_OPTS = -DDEPCA_IRQ=0 -DDEPCA_DEBUG=1 DEPCA_OPTS = -DDEPCA_DEBUG=1
EWRK3_OPTS = -DEWRK3_DEBUG=1
...@@ -142,6 +142,11 @@ NETDRV_OBJS := $(NETDRV_OBJS) depca.o ...@@ -142,6 +142,11 @@ NETDRV_OBJS := $(NETDRV_OBJS) depca.o
depca.o: depca.c CONFIG depca.o: depca.c CONFIG
$(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $< $(CC) $(CPPFLAGS) $(CFLAGS) $(DEPCA_OPTS) -c $<
endif endif
ifdef CONFIG_EWRK3
NETDRV_OBJS := $(NETDRV_OBJS) ewrk3.o
ewrk3.o: ewrk3.c CONFIG
$(CC) $(CPPFLAGS) $(CFLAGS) $(EWRK3_OPTS) -c $<
endif
ifdef CONFIG_ATP ifdef CONFIG_ATP
NETDRV_OBJS := $(NETDRV_OBJS) atp.o NETDRV_OBJS := $(NETDRV_OBJS) atp.o
endif endif
......
The EtherWORKS 3 driver in this distribution is designed to work with all
kernels > 1.1.33 (approx) and includes tools in the 'ewrk3tools'
subdirectory to allow set up of the card, similar to the MSDOS
'NICSETUP.EXE' tools provided on the DOS drivers disk (type 'make' in that
subdirectory to make the tools).
The supported cards are DE203, DE204 and DE205. All other cards are NOT
supported - refer to the depca files for running the LANCE based network
cards from Digital.
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). 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 ewrk3.c from the /linux/drivers/net directory to your favourite
temporary directory.
2) edit the source code near line 1750 to reflect the I/O address and
IRQ you're using.
3) compile ewrk3.c, but include -DMODULE in the command line to ensure
that the correct bits are compiled (see end of source code).
4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
kernel with the ewrk3 configuration turned off and reboot.
5) insmod ewrk3.o
6) run the net startup bits for your new eth?? interface manually
(usually /etc/rc.inet[12] at boot time).
7) enjoy!
Note that autoprobing is not allowed in loadable modules - the system is
already up and running and you're messing with interrupts.
To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod ewrk3'.
The performance we've achieved so far has been measured through the 'ttcp'
tool at 975kB/s. This measures the total tcp stack performance which
includes the card, so don't expect to get much nearer the 1.25MB/s
theoretical ethernet rate.
Enjoy!
Dave
...@@ -49,6 +49,7 @@ extern int el3_probe(struct device *); ...@@ -49,6 +49,7 @@ extern int el3_probe(struct device *);
extern int at1500_probe(struct device *); extern int at1500_probe(struct device *);
extern int at1700_probe(struct device *); extern int at1700_probe(struct device *);
extern int depca_probe(struct device *); extern int depca_probe(struct device *);
extern int ewrk3_probe(struct device *);
extern int el1_probe(struct device *); extern int el1_probe(struct device *);
extern int el16_probe(struct device *); extern int el16_probe(struct device *);
extern int elplus_probe(struct device *); extern int elplus_probe(struct device *);
...@@ -108,6 +109,9 @@ ethif_probe(struct device *dev) ...@@ -108,6 +109,9 @@ ethif_probe(struct device *dev)
#ifdef CONFIG_DEPCA /* DEC DEPCA */ #ifdef CONFIG_DEPCA /* DEC DEPCA */
&& depca_probe(dev) && depca_probe(dev)
#endif #endif
#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */
&& ewrk3_probe(dev)
#endif
#ifdef CONFIG_EL1 /* 3c501 */ #ifdef CONFIG_EL1 /* 3c501 */
&& el1_probe(dev) && el1_probe(dev)
#endif #endif
......
/* ewrk3.c: A DIGITAL EtherWORKS 3 ethernet driver for linux.
Written 1994 by David C. Davies.
Copyright 1994 Digital Equipment Corporation.
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference.
This driver is written for the Digital Equipment Corporation series
of EtherWORKS ethernet cards:
DE203 Turbo (BNC)
DE204 Turbo (TP)
DE205 Turbo (TP BNC)
The driver has been tested on a relatively busy network using the DE205
card and benchmarked with 'ttcp': it transferred 16M of data at 975kB/s
(7.8Mb/s) to a DECstation 5000/200.
The author may be reached as davies@wanton.lkg.dec.com or Digital
Equipment Corporation, 550 King Street, Littleton MA 01460.
=========================================================================
This driver has been written substantially from scratch, although its
inheritance of style and stack interface from 'depca.c' and in turn from
Donald Becker's 'lance.c' should be obvious.
The DE203/4/5 boards all use a new proprietary chip in place of the
LANCE chip used in prior cards (DEPCA, DE100, DE200/1/2, DE210, DE422).
Use the depca.c driver in the standard distribution for the LANCE based
cards from DIGITAL; this driver will not work with them.
The DE203/4/5 cards have 2 main modes: shared memory and I/O only. I/O
only makes all the card accesses through I/O transactions and no high
(shared) memory is used. This mode provides a >48% performance penalty
and is deprecated in this driver, although allowed to provide initial
setup when hardstrapped.
The shared memory mode comes in 3 flavours: 2kB, 32kB and 64kB. There is
no point in using any mode other than the 2kB mode - their performances
are virtually identical, although the driver has been tested in the 2kB
and 32kB modes. I would suggest you uncomment the line:
FORCE_2K_MODE;
to allow the driver to configure the card as a 2kB card at your current
base address, thus leaving more room to clutter your system box with
other memory hungry boards.
Upto 21 ISA and 7 EISA cards can be supported under this driver, limited
primarily by the available IRQ lines. I have checked different
configurations of multiple depca cards and ewrk3 cards and have not
found a problem yet (provided you have at least depca.c v0.38) ...
The board IRQ setting must be at an unused IRQ which is auto-probed
using Donald Becker's autoprobe routines. All these cards are at
{5,10,11,15}.
No 16MB memory limitation should exist with this driver as DMA is not
used and the common memory area is in low memory on the network card (my
current system has 20MB and I've not had problems yet).
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). 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 ewrk3.c from the /linux/drivers/net directory to your favourite
temporary directory.
2) edit the source code near line 1340 to reflect the I/O address and
IRQ you're using.
3) compile ewrk3.c, but include -DMODULE in the command line to ensure
that the correct bits are compiled (see end of source code).
4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
kernel with the ewrk3 configuration turned off and reboot.
5) insmod ewrk3.o
6) run the net startup bits for your new eth?? interface manually
(usually /etc/rc.inet[12] at boot time).
7) enjoy!
Note that autoprobing is not allowed in loadable modules - the system is
already up and running and you're messing with interrupts.
To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod ewrk3'.
Promiscuous mode has been turned off in this driver, but all the
multicast address bits have been turned on. This improved the send
performance on a busy network by about 13%.
Ioctl's have now been provided (primarily because I wanted to grab some
packet size statistics). They are patterned after 'plipconfig.c' from a
suggestion by Alan Cox. Using these ioctls, you can enable promiscuous
mode, add/delete multicast addresses, change the hardware address, get
packet size distribution statistics and muck around with the control and
status register. I'll add others if and when the need arises.
TO DO:
------
Revision History
----------------
Version Date Description
0.1 26-aug-94 Initial writing. ALPHA code release.
0.11 31-aug-94 Fixed: 2k mode memory base calc.,
LeMAC version calc.,
IRQ vector assignments during autoprobe.
0.12 31-aug-94 Tested working on LeMAC2 (DE20[345]-AC) card.
Fixed up MCA hash table algorithm.
0.20 4-sep-94 Added IOCTL functionality.
0.21 14-sep-94 Added I/O mode.
0.21axp 15-sep-94 Special version for ALPHA AXP Linux V1.0
0.22 16-sep-94 Added more IOCTLs & tidied up.
0.23 21-sep-94 Added transmit cut through
0.24 31-oct-94 Added uid checks in some ioctls
0.30 1-nov-94 BETA code release
=========================================================================
*/
static char *version = "ewrk3.c:v0.30 11/1/94 davies@wanton.lkg.dec.com\n";
#include <stdarg.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/segment.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/unistd.h>
#ifdef MODULE
#include <linux/module.h>
#include "/linux/tools/version.h"
#endif /* MODULE */
#include "ewrk3.h"
#ifdef EWRK3_DEBUG
static int ewrk3_debug = EWRK3_DEBUG;
#else
static int ewrk3_debug = 1;
#endif
#ifndef PROBE_LENGTH
#define PROBE_LENGTH 32
#endif
#ifndef PROBE_SEQUENCE
#define PROBE_SEQUENCE "FF0055AAFF0055AA"
#endif
#ifndef EWRK3_SIGNATURE
#define EWRK3_SIGNATURE {"DE203","DE204","DE205",""}
#define EWRK3_NAME_LENGTH 8
#endif
#ifndef EWRK3_RAM_BASE_ADDRESSES
#define EWRK3_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0x00000}
#endif
/*
** Sets up the search areas for the autoprobe. You can disable an area
** by writing a zero into the corresponding bit position in EWRK3_IO_SEARCH.
** The LSb -> I/O 0x100. Each bit increments the I/O location searched by 0x20.
** Bit 24 -> I/O 0x400.
**
** By default, probes at locations:
** 0x1e0 (may conflict with hard disk)
** 0x320 (may conflict with hard disk)
** 0x3e0 (may conflict with floppy disk)
**
** are disabled.
*/
#define EWRK3_IO_BASE 0x100 /* Start address for probe search */
#define EWRK3_IOP_INC 0x20 /* I/O address increment */
#define EWRK3_IO_SEARCH 0x007dff7f /* probe search mask */
static long mem_chkd = EWRK3_IO_SEARCH; /* holds which I/O addrs should be */
/* checked, for multi-EWRK3 case */
#ifndef MAX_NUM_EWRK3S
#define MAX_NUM_EWRK3S 21
#endif
#ifndef EWRK3_EISA_IO_PORTS
#define EWRK3_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
#endif
#ifndef MAX_EISA_SLOTS
#define MAX_EISA_SLOTS 8
#define EISA_SLOT_INC 0x1000
#endif
#ifndef CRC_POLYNOMIAL
#define CRC_POLYNOMIAL 0x04c11db7 /* Ethernet CRC polynomial */
#endif /* CRC_POLYNOMIAL */
/*
** EtherWORKS 3 shared memory window sizes
*/
#define IO_ONLY 0x00
#define SHMEM_2K 0x800
#define SHMEM_32K 0x8000
#define SHMEM_64K 0x10000
/*
** EtherWORKS 3 IRQ ENABLE/DISABLE
*/
static unsigned char irq_mask = TNEM|TXDM|RNEM|RXDM;
#define ENABLE_IRQs \
icr |= irq_mask;\
outb(icr, EWRK3_ICR) /* Enable the IRQs */
#define DISABLE_IRQs \
icr = inb(EWRK3_ICR);\
icr &= ~irq_mask;\
outb(icr, EWRK3_ICR) /* Disable the IRQs */
/*
** EtherWORKS 3 START/STOP
*/
#define START_EWRK3 \
csr = inb(EWRK3_CSR);\
csr &= ~(TXD|RXD);\
outb(csr, EWRK3_CSR) /* Enable the TX and/or RX */
#define STOP_EWRK3 \
csr = (TXD|RXD);\
outb(csr, EWRK3_CSR) /* Disable the TX and/or RX */
/*
** The EtherWORKS 3 private structure
*/
#define EWRK3_PKT_STAT_SZ 16
#define EWRK3_PKT_BIN_SZ 128 /* Should be >=100 unless you
increase EWRK3_PKT_STAT_SZ */
struct ewrk3_private {
long shmem_base; /* Shared memory start address */
long shmem_length; /* Shared memory window length */
struct enet_statistics stats; /* Public stats */
struct {
unsigned long bins[EWRK3_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;
short mPage; /* Maximum 2kB Page number */
unsigned char lemac; /* Chip rev. level */
unsigned char hard_strapped; /* Don't allow a full open */
unsigned char lock; /* Lock the page register */
unsigned char txc; /* Transmit cut through */
};
/*
** Force the EtherWORKS 3 card to be in 2kB MODE
*/
#define FORCE_2K_MODE \
shmem_length = SHMEM_2K;\
outb(((mem_start - 0x80000) >> 11), EWRK3_MBR)
/*
** Public Functions
*/
static int ewrk3_open(struct device *dev);
static int ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev);
static void ewrk3_interrupt(int reg_ptr);
static int ewrk3_close(struct device *dev);
static struct enet_statistics *ewrk3_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
static int ewrk3_ioctl(struct device *dev, struct ifreq *rq);
/*
** Private functions
*/
static int ewrk3_hw_init(struct device *dev, short iobase);
static void ewrk3_init(struct device *dev);
static int ewrk3_rx(struct device *dev);
static int ewrk3_tx(struct device *dev);
static void EthwrkSignature(char * name, char *eeprom_image);
static int DevicePresent(short iobase);
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table);
static int Read_EEPROM(short iobase, unsigned char eaddr);
static int Write_EEPROM(short data, short iobase, unsigned char eaddr);
static unsigned char aprom_crc (struct device *dev, unsigned char *eeprom_image, char chipType);
#ifndef MODULE
static struct device *isa_probe(struct device *dev);
static struct device *eisa_probe(struct device *dev);
static struct device *alloc_device(struct device *dev, int iobase);
static int num_ewrk3s = 0, num_eth = 0, autoprobed = 0;
static unsigned char irq[] = {5,0,10,3,11,9,15,12};
#else
int init_module(void);
void cleanup_module(void);
#endif /* MODULE */
/*
** Miscellaneous defines...
*/
#define INIT_EWRK3 {\
int i;\
outb(EEPROM_INIT, EWRK3_IOPR);\
for (i=0;i<5000;i++) inb(EWRK3_CSR);\
}
int ewrk3_probe(struct device *dev)
{
int base_addr = dev->base_addr;
int status = -ENODEV;
#ifndef MODULE
struct device *eth0;
#endif
if (base_addr > 0x0ff) { /* Check a single specified location. */
if (((mem_chkd >> ((base_addr - EWRK3_IO_BASE)/ EWRK3_IOP_INC))&0x01)==0) {
if (DevicePresent(base_addr) == 0) { /* Is EWRK3 really here? */
status = ewrk3_hw_init(dev, base_addr);
} else {
printk("ewrk3_probe(): No device found\n");
}
} else {
status = ewrk3_hw_init(dev, base_addr); /* Yes there is h/w */
}
} else if (base_addr > 0) { /* Don't probe at all. */
status = -ENXIO;
#ifdef MODULE
} else {
printk("Autoprobing is not supported when loading a module based driver.\n");
status = -EIO;
#else
} else if (!autoprobed) { /* First probe for the EWRK3 test */
/* pattern in ROM */
eth0=isa_probe(dev);
eth0=eisa_probe(eth0);
if (dev->priv) status=0;
autoprobed = 1;
} else {
status = -ENXIO;
#endif /* MODULE */
}
if (status) dev->base_addr = base_addr;
return status;
}
static int
ewrk3_hw_init(struct device *dev, short iobase)
{
struct ewrk3_private *lp;
int i, status=0;
unsigned long mem_start, shmem_length;
char name[EWRK3_NAME_LENGTH + 1];
unsigned char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
unsigned char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
/*
** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
** This also disables the EISA_ENABLE bit in the EISA Control Register.
*/
if (iobase > 0x400) eisa_cr = inb(EISA_CR);
INIT_EWRK3;
nicsr = inb(EWRK3_CSR);
/*
** Disable & mask all board interrupts
*/
DISABLE_IRQs;
if (nicsr == TXD|RXD) {
/*
** Check that the EEPROM is alive and well and not living on Pluto...
*/
for (chksum=0, i=0; i<EEPROM_MAX; i+=2) {
union {
short val;
char c[2];
} tmp;
tmp.val = (short)Read_EEPROM(iobase, (i>>1));
eeprom_image[i] = tmp.c[0];
eeprom_image[i+1] = tmp.c[1];
chksum += eeprom_image[i] + eeprom_image[i+1];
}
if (chksum != 0) { /* Bad EEPROM Data! */
printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
status = -ENXIO;
} else {
/*
** Now find out what kind of EWRK3 we have.
*/
EthwrkSignature(name, eeprom_image);
if (*name != '\0') { /* found a EWRK3 device */
dev->base_addr = iobase;
if (iobase > 0x400) {
outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */
}
lemac = eeprom_image[EEPROM_CHIPVER];
cmr = inb(EWRK3_CMR);
if (((lemac == LeMAC) && ((cmr & NO_EEPROM) != NO_EEPROM)) ||
((lemac == LeMAC2) && !(cmr & HS))) {
printk("%s: %s at %#3x", dev->name, name, iobase);
hard_strapped = 1;
} else if ((iobase&0x0fff)==EWRK3_EISA_IO_PORTS) {
/* EISA slot address */
printk("%s: %s at %#3x (EISA slot %d)",
dev->name, name, iobase, ((iobase>>12)&0x0f));
} else { /* ISA port address */
printk("%s: %s at %#3x", dev->name, name, iobase);
}
if (!status) {
printk(", h/w address ");
if (lemac == LeMAC2) {
for (i = 0;i < ETH_ALEN - 1;i++) { /* get the ethernet address */
printk("%2.2x:", dev->dev_addr[i] =
eeprom_image[EEPROM_PADDR0 + i]);
outb(eeprom_image[EEPROM_PADDR0 + i], EWRK3_PAR0 + i);
}
printk("%2.2x,\n",dev->dev_addr[i] = eeprom_image[EEPROM_PADDR0 + i]);
outb(eeprom_image[EEPROM_PADDR0 + i], EWRK3_PAR0 + i);
} else {
DevicePresent(iobase); /* needed after the EWRK3_INIT */
for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
printk("%2.2x:", dev->dev_addr[i] = inb(EWRK3_APROM));
outb(dev->dev_addr[i], EWRK3_PAR0 + i);
}
printk("%2.2x,\n", dev->dev_addr[i] = inb(EWRK3_APROM));
outb(dev->dev_addr[i], EWRK3_PAR0 + i);
}
if (aprom_crc(dev, eeprom_image, lemac)) {
printk(" which has an EEPROM CRC error.\n");
status = -ENXIO;
} else {
if (lemac == LeMAC2) { /* Special LeMAC2 CMR things */
cmr &= ~(RA | WB | LINK | POLARITY | _0WS);
if (eeprom_image[EEPROM_MISC0] & READ_AHEAD) cmr |= RA;
if (eeprom_image[EEPROM_MISC0] & WRITE_BEHIND) cmr |= WB;
if (eeprom_image[EEPROM_NETMAN0] & NETMAN_POL) cmr |= POLARITY;
if (eeprom_image[EEPROM_NETMAN0] & NETMAN_LINK) cmr |= LINK;
if (eeprom_image[EEPROM_MISC0] & _0WS_ENA) cmr |= _0WS;
}
if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM) cmr |= DRAM;
outb(cmr, EWRK3_CMR);
cr = inb(EWRK3_CR); /* Set up the Control Register */
cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
if (cr & SETUP_APD) cr |= eeprom_image[EEPROM_SETUP] & SETUP_PS;
cr |= eeprom_image[EEPROM_MISC0] & FAST_BUS;
cr |= eeprom_image[EEPROM_MISC0] & ENA_16;
outb(cr, EWRK3_CR);
/*
** Determine the base address and window length for the EWRK3
** RAM from the memory base register.
*/
mem_start = inb(EWRK3_MBR);
shmem_length = 0;
if (mem_start != 0) {
if ((mem_start >= 0x0a) && (mem_start <= 0x0f)) {
mem_start *= SHMEM_64K;
shmem_length = SHMEM_64K;
} else if ((mem_start >= 0x14) && (mem_start <= 0x1f)) {
mem_start *= SHMEM_32K;
shmem_length = SHMEM_32K;
} else if ((mem_start >= 0x40) && (mem_start <= 0xff)) {
mem_start = mem_start * SHMEM_2K + 0x80000;
shmem_length = SHMEM_2K;
} else {
status = -ENXIO;
}
}
/*
** See the top of this source code for comments about
** uncommenting this line.
*/
/* FORCE_2K_MODE;*/
if (!status) {
if (hard_strapped) {
printk(" is hard strapped.\n");
} else if (mem_start) {
printk(" has a %dk RAM window", (int)(shmem_length >> 10));
printk(" at 0x%.5lx", mem_start);
} else {
printk(" is in I/O only mode");
}
/* private area & initialise */
dev->priv = (void *) kmalloc(sizeof(struct ewrk3_private),
GFP_KERNEL);
lp = (struct ewrk3_private *)dev->priv;
memset(dev->priv, 0, sizeof(struct ewrk3_private));
lp->shmem_base = mem_start;
lp->shmem_length = shmem_length;
lp->lemac = lemac;
lp->hard_strapped = hard_strapped;
lp->mPage = 64;
if (cmr & DRAM) lp->mPage <<= 1 ; /* 2 DRAMS on module */
if (!hard_strapped) {
/*
** Enable EWRK3 board interrupts for autoprobing
*/
icr |= IE; /* Enable interrupts */
outb(icr, EWRK3_ICR);
/* The DMA channel may be passed in on this parameter. */
dev->dma = 0;
/* To auto-IRQ we enable the initialization-done and DMA err,
interrupts. For now we will always get a DMA error. */
if (dev->irq < 2) {
#ifndef MODULE
unsigned char irqnum;
autoirq_setup(0);
/*
** Trigger a TNE interrupt.
*/
icr |=TNEM;
outb(1,EWRK3_TDQ); /* Write to the TX done queue */
outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */
irqnum = irq[((icr & IRQ_SEL) >> 4)];
dev->irq = autoirq_report(1);
if ((dev->irq) && (irqnum == dev->irq)) {
printk(" and uses IRQ%d.\n", dev->irq);
} else {
if (!dev->irq) {
printk(" and failed to detect IRQ line.\n");
} else if ((irqnum == 1) && (lemac == LeMAC2)) {
printk(" and an illegal IRQ line detected.\n");
} else {
printk(", but incorrect IRQ line detected.\n");
}
status = -ENXIO;
}
DISABLE_IRQs; /* Mask all interrupts */
#endif /* MODULE */
} else {
printk(" and requires IRQ%d.\n", dev->irq);
}
}
} else {
status = -ENXIO;
}
}
}
} else {
status = -ENXIO;
}
}
if (!status) {
if (ewrk3_debug > 0) {
printk(version);
}
/* The EWRK3-specific entries in the device structure. */
dev->open = &ewrk3_open;
dev->hard_start_xmit = &ewrk3_queue_pkt;
dev->stop = &ewrk3_close;
dev->get_stats = &ewrk3_get_stats;
#ifdef HAVE_MULTICAST
dev->set_multicast_list = &set_multicast_list;
#endif
dev->do_ioctl = &ewrk3_ioctl;
dev->mem_start = 0;
/* Fill in the generic field of the device structure. */
ether_setup(dev);
}
} else {
status = -ENXIO;
}
return status;
}
static int
ewrk3_open(struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int i, iobase = dev->base_addr;
int status = 0;
unsigned char icr, csr;
/*
** Stop the TX and RX...
*/
STOP_EWRK3;
if (!lp->hard_strapped) {
if (request_irq(dev->irq, &ewrk3_interrupt, 0, "ewrk3")) {
printk("ewrk3_open(): Requested IRQ%d is busy\n",dev->irq);
status = -EAGAIN;
} else {
irq2dev_map[dev->irq] = dev;
/*
** Re-initialize the EWRK3...
*/
ewrk3_init(dev);
if (ewrk3_debug > 1){
printk("%s: ewrk3 open with irq %d\n",dev->name,dev->irq);
printk("\tphysical address: ");
for (i=0;i<6;i++){
printk("%2.2x:",(short)dev->dev_addr[i]);
}
printk("\n");
printk("\tchecked memory: 0x%08lx\n",mem_chkd);
if (lp->shmem_length == 0) {
printk("\tno shared memory, I/O only mode\n");
} else {
printk("\tstart of shared memory: 0x%08lx\n",lp->shmem_base);
printk("\twindow length: 0x%04lx\n",lp->shmem_length);
}
printk("\t# of DRAMS: %d\n",((inb(EWRK3_CMR) & 0x02) ? 2 : 1));
printk("\tcsr: 0x%02x\n", inb(EWRK3_CSR));
printk("\tcr: 0x%02x\n", inb(EWRK3_CR));
printk("\ticr: 0x%02x\n", inb(EWRK3_ICR));
printk("\tcmr: 0x%02x\n", inb(EWRK3_CMR));
printk("\tfmqc: 0x%02x\n", inb(EWRK3_FMQC));
}
dev->tbusy = 0;
dev->start = 1;
dev->interrupt = UNMASK_INTERRUPTS;
/*
** Unmask EWRK3 board interrupts
*/
icr = inb(EWRK3_ICR);
ENABLE_IRQs;
}
} else {
dev->start = 0;
dev->tbusy = 1;
printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);
printk(" Run the 'ewrk3setup' utility or remove the hard straps.\n");
}
#ifdef MODULE
MOD_INC_USE_COUNT;
#endif
return status;
}
/*
** Initialize the EtherWORKS 3 operating conditions
*/
static void
ewrk3_init(struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
char csr, page;
short iobase = dev->base_addr;
/*
** Enable all multicasts
*/
set_multicast_list(dev, HASH_TABLE_LEN, NULL);
/*
** Clean out any remaining entries in all the queues here
*/
while (inb(EWRK3_TQ));
while (inb(EWRK3_TDQ));
while (inb(EWRK3_RQ));
while (inb(EWRK3_FMQ));
/*
** Write a clean free memory queue
*/
for (page=1;page<lp->mPage;page++) { /* Write the free page numbers */
outb(page, EWRK3_FMQ); /* to the Free Memory Queue */
}
lp->lock = 0; /* Ensure there are no locks */
START_EWRK3; /* Enable the TX and/or RX */
}
/*
** Writes a socket buffer to the free page queue
*/
static int
ewrk3_queue_pkt(struct sk_buff *skb, struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int iobase = dev->base_addr;
int status = 0;
unsigned char icr, csr;
/* Transmitter timeout, serious problems. */
if (dev->tbusy || lp->lock) {
int tickssofar = jiffies - dev->trans_start;
if (tickssofar < 10) {
status = -1;
} else if (!lp->hard_strapped) {
printk("%s: transmit timed/locked out, status %04x, resetting.\n",
dev->name, inb(EWRK3_CSR));
/*
** Mask all board interrupts
*/
DISABLE_IRQs;
/*
** Stop the TX and RX...
*/
STOP_EWRK3;
ewrk3_init(dev);
/*
** Unmask EWRK3 board interrupts
*/
ENABLE_IRQs;
dev->tbusy=0;
dev->trans_start = jiffies;
}
} else if (skb == NULL) {
dev_tint(dev);
} else if (skb->len > 0) {
/*
** Block a timer-based transmit from overlapping. This could better be
** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
*/
if (set_bit(0, (void*)&dev->tbusy) != 0)
printk("%s: Transmitter access conflict.\n", dev->name);
DISABLE_IRQs; /* So that the page # remains correct */
/*
** Get a free page from the FMQ when resources are available
*/
if (inb(EWRK3_FMQC) > 0) {
unsigned char *buf;
unsigned char page;
if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
buf = NULL;
/*
** Set up shared memory window and pointer into the window
*/
while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(page, EWRK3_IOPR);
} else if (lp->shmem_length == SHMEM_2K) {
buf = (char *) lp->shmem_base;
outb(page, EWRK3_MPR);
} else if (lp->shmem_length == SHMEM_32K) {
buf = (char *)((((short)page << 11) & 0x7800) + lp->shmem_base);
outb((page >> 4), EWRK3_MPR);
} else if (lp->shmem_length == SHMEM_64K) {
buf = (char *)((((short)page << 11) & 0xf800) + lp->shmem_base);
outb((page >> 5), EWRK3_MPR);
} else {
status = -1;
printk("%s: Oops - your private data area is hosed!\n",dev->name);
}
if (!status) {
/*
** Set up the buffer control structures and copy the data from
** the socket buffer to the shared memory .
*/
if (lp->shmem_length == IO_ONLY) {
int i;
unsigned char *p = skb->data;
outb((char)(QMODE | PAD | IFC), EWRK3_DATA);
outb((char)(skb->len & 0xff), EWRK3_DATA);
outb((char)((skb->len >> 8) & 0xff), EWRK3_DATA);
outb((char)0x04, EWRK3_DATA);
for (i=0; i<skb->len; i++) {
outb(*p++, EWRK3_DATA);
}
outb(page, EWRK3_TQ); /* Start sending pkt */
} else {
*buf++ = (char)(QMODE | PAD | IFC); /* control byte */
*buf++ = (char)(skb->len & 0xff); /* length (16 bit xfer)*/
if (lp->txc) {
*buf++ = (char)(((skb->len >> 8) & 0xff) | XCT);
*buf++ = 0x04; /* index byte */
*(buf + skb->len) = 0x00; /* Write the XCT flag */
memcpy(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */
outb(page, EWRK3_TQ); /* Start sending pkt */
memcpy(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
*(buf + skb->len) = 0xff; /* Write the XCT flag */
} else {
*buf++ = (char)((skb->len >> 8) & 0xff);
*buf++ = 0x04; /* index byte */
memcpy(buf, skb->data, skb->len); /* Write data bytes */
outb(page, EWRK3_TQ); /* Start sending pkt */
}
}
dev->trans_start = jiffies;
dev_kfree_skb (skb, FREE_WRITE);
} else { /* return unused page to the free memory queue */
outb(page, EWRK3_FMQ);
}
lp->lock = 0; /* unlock the page register */
} else {
printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
(unsigned char) page);
}
} else {
printk("ewrk3_queue_pkt(): No free resources...\n");
printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));
}
/* Check for free resources: clear 'tbusy' if there are some */
if (inb(EWRK3_FMQC) > 0) {
dev->tbusy = 0;
}
ENABLE_IRQs;
}
return status;
}
/*
** The EWRK3 interrupt handler.
*/
static void
ewrk3_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
struct device *dev = (struct device *)(irq2dev_map[irq]);
struct ewrk3_private *lp;
int iobase;
unsigned char icr, cr, csr;
if (dev == NULL) {
printk ("ewrk3_interrupt(): irq %d for unknown device.\n", irq);
} else {
lp = (struct ewrk3_private *)dev->priv;
iobase = dev->base_addr;
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
dev->interrupt = MASK_INTERRUPTS;
/* get the interrupt information */
csr = inb(EWRK3_CSR);
/*
** Mask the EWRK3 board interrupts and turn on the LED
*/
DISABLE_IRQs;
cr = inb(EWRK3_CR);
cr |= LED;
outb(cr, EWRK3_CR);
if (csr & RNE) /* Rx interrupt (packet[s] arrived) */
ewrk3_rx(dev);
if (csr & TNE) /* Tx interrupt (packet sent) */
ewrk3_tx(dev);
/*
** Now deal with the TX/RX disable flags. These are set when there
** are no more resources. If resources free up then enable these
** interrupts, otherwise mask them - failure to do this will result
** in the system hanging in an interrupt loop.
*/
if (inb(EWRK3_FMQC)) { /* any resources available? */
irq_mask |= TXDM|RXDM; /* enable the interrupt source */
csr &= ~(TXD|RXD); /* ensure restart of a stalled TX or RX */
outb(csr, EWRK3_CSR);
dev->tbusy = 0; /* clear TX busy flag */
mark_bh(NET_BH);
} else {
irq_mask &= ~(TXDM|RXDM); /* disable the interrupt source */
}
/* Unmask the EWRK3 board interrupts and turn off the LED */
cr &= ~LED;
outb(cr, EWRK3_CR);
dev->interrupt = UNMASK_INTERRUPTS;
ENABLE_IRQs;
}
return;
}
static int
ewrk3_rx(struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int i, iobase = dev->base_addr;
unsigned char page, tmpPage = 0, tmpLock = 0, *buf;
int status = 0;
while (inb(EWRK3_RQC) && !status) { /* Whilst there's incoming data */
if ((page = inb(EWRK3_RQ)) < lp->mPage) {/* Get next entry's buffer page */
buf = NULL;
/*
** Preempt any process using the current page register. Check for
** an existing lock to reduce time taken in I/O transactions.
*/
if ((tmpLock = set_bit(0, (void *)&lp->lock)) == 1) { /* Assert lock */
if (lp->shmem_length == IO_ONLY) { /* Get existing page */
tmpPage = inb(EWRK3_IOPR);
} else {
tmpPage = inb(EWRK3_MPR);
}
}
/*
** Set up shared memory window and pointer into the window
*/
if (lp->shmem_length == IO_ONLY) {
outb(page, EWRK3_IOPR);
} else if (lp->shmem_length == SHMEM_2K) {
buf = (char *) lp->shmem_base;
outb(page, EWRK3_MPR);
} else if (lp->shmem_length == SHMEM_32K) {
buf = (char *)((((short)page << 11) & 0x7800) + lp->shmem_base);
outb((page >> 4), EWRK3_MPR);
} else if (lp->shmem_length == SHMEM_64K) {
buf = (char *)((((short)page << 11) & 0xf800) + lp->shmem_base);
outb((page >> 5), EWRK3_MPR);
} else {
status = -1;
printk("%s: Oops - your private data area is hosed!\n",dev->name);
}
if (!status) {
char rx_status;
int pkt_len;
if (lp->shmem_length == IO_ONLY) {
rx_status = inb(EWRK3_DATA);
pkt_len = inb(EWRK3_DATA);
pkt_len |= ((unsigned short)inb(EWRK3_DATA) << 8);
} else {
rx_status = (char)(*buf++);
pkt_len = (short)(*buf+((*(buf+1))<<8));
buf+=3;
}
if (!(rx_status & ROK)) { /* There was an error. */
lp->stats.rx_errors++; /* Update the error stats. */
if (rx_status & DBE) lp->stats.rx_frame_errors++;
if (rx_status & CRC) lp->stats.rx_crc_errors++;
if (rx_status & PLL) lp->stats.rx_fifo_errors++;
} else {
struct sk_buff *skb;
if ((skb = alloc_skb(pkt_len, GFP_ATOMIC)) != NULL) {
skb->len = pkt_len;
skb->dev = dev;
if (lp->shmem_length == IO_ONLY) {
unsigned char *p = skb->data;
*p = inb(EWRK3_DATA); /* dummy read */
for (i=0; i<skb->len; i++) {
*p++ = inb(EWRK3_DATA);
}
} else {
memcpy(skb->data, buf, pkt_len);
}
/*
** Notify the upper protocol layers that there is another
** packet to handle
*/
netif_rx(skb);
/*
** Update stats
*/
lp->stats.rx_packets++;
for (i=1; i<EWRK3_PKT_STAT_SZ-1; i++) {
if (pkt_len < i*EWRK3_PKT_BIN_SZ) {
lp->pktStats.bins[i]++;
i = EWRK3_PKT_STAT_SZ;
}
}
buf = skb->data; /* Look at the dest addr */
if (buf[0] & 0x01) { /* Multicast/Broadcast */
if ((*(long *)&buf[0] == -1) && (*(short *)&buf[4] == -1)) {
lp->pktStats.broadcast++;
} else {
lp->pktStats.multicast++;
}
} else if ((*(long *)&buf[0] == *(long *)&dev->dev_addr[0]) &&
(*(short *)&buf[4] == *(short *)&dev->dev_addr[4])) {
lp->pktStats.unicast++;
}
lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
if (lp->pktStats.bins[0] == 0) { /* Reset counters */
memset(&lp->pktStats, 0, sizeof(lp->pktStats));
}
} else {
printk("%s: Insufficient memory; nuking packet.\n", dev->name);
lp->stats.rx_dropped++; /* Really, deferred. */
break;
}
}
}
/*
** Return the received buffer to the free memory queue
*/
outb(page, EWRK3_FMQ);
if (tmpLock) { /* If a lock was preempted */
if (lp->shmem_length == IO_ONLY) { /* Replace old page */
outb(tmpPage, EWRK3_IOPR);
} else {
outb(tmpPage, EWRK3_MPR);
}
}
lp->lock = 0; /* Unlock the page register */
} else {
printk("ewrk3_rx(): Illegal page number, page %d\n",page);
printk("ewrk3_rx(): CSR: %02x ICR: %02x FMQC: %02x\n",inb(EWRK3_CSR),inb(EWRK3_ICR),inb(EWRK3_FMQC));
}
}
return status;
}
/*
** Buffer sent - check for TX buffer errors.
*/
static int
ewrk3_tx(struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int iobase = dev->base_addr;
unsigned char tx_status;
while ((tx_status = inb(EWRK3_TDQ)) > 0) { /* Whilst there's old buffers */
if (tx_status & VSTS) { /* The status is valid */
if (tx_status & MAC_TXE) {
lp->stats.tx_errors++;
if (tx_status & MAC_NCL) lp->stats.tx_carrier_errors++;
if (tx_status & MAC_LCL) lp->stats.tx_window_errors++;
if (tx_status & MAC_CTU) {
if ((tx_status & MAC_COLL) ^ MAC_XUR) {
lp->pktStats.tx_underruns++;
} else {
lp->pktStats.excessive_underruns++;
}
} else if (tx_status & MAC_COLL) {
if ((tx_status & MAC_COLL) ^ MAC_XCOLL) {
lp->stats.collisions++;
} else {
lp->pktStats.excessive_collisions++;
}
}
} else {
lp->stats.tx_packets++;
}
}
}
return 0;
}
static int
ewrk3_close(struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int iobase = dev->base_addr;
unsigned char icr, csr;
dev->start = 0;
dev->tbusy = 1;
if (ewrk3_debug > 1) {
printk("%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inb(EWRK3_CSR));
}
/*
** We stop the EWRK3 here... mask interrupts and stop TX & RX
*/
DISABLE_IRQs;
STOP_EWRK3;
/*
** Clean out the TX and RX queues here (note that one entry
** may get added to either the TXD or RX queues if the the TX or RX
** just starts processing a packet before the STOP_EWRK3 command
** is received. This will be flushed in the ewrk3_open() call).
*/
while (inb(EWRK3_TQ));
while (inb(EWRK3_TDQ));
while (inb(EWRK3_RQ));
if (!lp->hard_strapped) {
free_irq(dev->irq);
irq2dev_map[dev->irq] = 0;
}
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
return 0;
}
static struct enet_statistics *
ewrk3_get_stats(struct device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
/* Null body since there is no framing error counter */
return &lp->stats;
}
/*
** Set or clear the multicast filter for this adaptor.
** num_addrs == -1 Promiscuous mode, receive all packets
** num_addrs == 0 Normal mode, clear multicast list
** num_addrs > 0 Multicast mode, receive normal and MC packets, and do
** best-effort filtering.
*/
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int iobase = dev->base_addr;
char *multicast_table;
unsigned char csr;
csr = inb(EWRK3_CSR);
if (lp->shmem_length == IO_ONLY) {
multicast_table = (char *) PAGE0_HTE;
} else {
multicast_table = (char *)(lp->shmem_base + PAGE0_HTE);
}
if (num_addrs >= 0) {
SetMulticastFilter(dev, num_addrs, (char *)addrs, multicast_table);
csr &= ~PME;
csr |= MCE;
outb(csr, EWRK3_CSR);
} else { /* set promiscuous mode */
csr |= PME;
csr &= ~MCE;
outb(csr, EWRK3_CSR);
}
}
/*
** Calculate the hash code and update the logical address filter
** from a list of ethernet multicast addresses.
** Derived from a 'C' program in the AMD data book:
** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
** Pub #17781, Rev. A, May 1993
**
*/
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs, char *multicast_table)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
int iobase = dev->base_addr;
char j, ctrl, bit, octet;
short *p = (short *) multicast_table;
unsigned short hashcode;
int i;
long int crc, poly = (long int) CRC_POLYNOMIAL;
while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(0, EWRK3_IOPR);
outw((short)((long)multicast_table), EWRK3_PIR1);
} else {
outb(0, EWRK3_MPR);
}
if (num_addrs == HASH_TABLE_LEN) {
for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
if (lp->shmem_length == IO_ONLY) {
outb(0xff, EWRK3_DATA);
} else { /* memset didn't work here */
*p++ = 0xffff;
i++;
}
}
} else if (num_addrs == 0) {
if (lp->shmem_length == IO_ONLY) {
for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
outb(0x00, EWRK3_DATA);
}
} else {
memset(multicast_table, 0, (HASH_TABLE_LEN >> 3));
}
} else {
for (i=0;i<num_addrs;i++) { /* for each address in the list */
if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* multicast address? */
crc = (long int) 0xffffffff; /* init CRC for each address */
for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
for(j=0;j<8;j++) { /* process each address bit */
bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
ctrl = ((crc < 0) ? 1 : 0); /* shift the control bit */
crc <<= 1; /* shift the CRC */
if (bit ^ ctrl) { /* (bit) XOR (control bit) */
crc ^= poly; /* (CRC) XOR (polynomial) */
}
}
}
hashcode = (crc & 0x01); /* hashcode is 9 LSb of CRC ... */
for (j=0;j<8;j++) { /* ... in reverse order. */
hashcode <<= 1;
crc >>= 1;
hashcode |= (crc & 0x01);
}
octet = hashcode >> 3; /* bit[3-8] -> octet in filter */
/* bit[0-2] -> bit in octet */
if (lp->shmem_length == IO_ONLY) {
unsigned char tmp;
outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
tmp = inb(EWRK3_DATA);
tmp |= (1 << (hashcode & 0x07));
outw((short)((long)multicast_table) + octet, EWRK3_PIR1);
outb(tmp, EWRK3_DATA);
} else {
multicast_table[octet] |= (1 << (hashcode & 0x07));
}
}
}
}
lp->lock = 0; /* Unlock the page register */
return;
}
#ifndef MODULE
/*
** ISA bus I/O device probe
*/
static struct device *isa_probe(struct device *dev)
{
int i, iobase, status;
unsigned long int tmp = mem_chkd;
for (status = -ENODEV, iobase = EWRK3_IO_BASE,i = 0;
i < 24;
iobase += EWRK3_IOP_INC, i++) {
if (tmp & 0x01) {
if (DevicePresent(iobase) == 0) {
/*
** Device found. Mark its (I/O) location for future reference. Only 24
** EtherWORKS devices can exist between 0x100 and 0x3e0.
*/
if (num_ewrk3s > 0) { /* only gets here in autoprobe */
dev = alloc_device(dev, iobase);
} else {
if ((status = ewrk3_hw_init(dev, iobase)) == 0) {
num_ewrk3s++;
}
}
num_eth++;
} else {
mem_chkd &= ~(0x01 << ((iobase - EWRK3_IO_BASE)/EWRK3_IOP_INC));
}
}
tmp >>= 1;
}
return dev;
}
/*
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
** the motherboard.
*/
static struct device *eisa_probe(struct device *dev)
{
int i, iobase = EWRK3_EISA_IO_PORTS;
int status;
iobase+=EISA_SLOT_INC; /* get the first slot address */
for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, iobase+=EISA_SLOT_INC) {
if (DevicePresent(iobase) == 0) {
/*
** Device found. Mark its slot location for future reference. Only 7
** EtherWORKS devices can exist in EISA space....
*/
mem_chkd |= (0x01 << (i + 24));
if (num_ewrk3s > 0) { /* only gets here in autoprobe */
dev = alloc_device(dev, iobase);
} else {
if ((status = ewrk3_hw_init(dev, iobase)) == 0) {
num_ewrk3s++;
}
}
num_eth++;
}
}
return dev;
}
/*
** Allocate the device by pointing to the next available space in the
** device structure. Should one not be available, it is created.
*/
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->next->base_addr == 0xffe0) break;
dev = dev->next; /* walk through eth device list */
num_eth++; /* increment eth device number */
}
/*
** If no more device structures, malloc one up. If memory could
** not be allocated, print an error message.
*/
if (dev->next == NULL) {
dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
GFP_KERNEL);
if (dev->next == NULL) {
printk("eth%d: Device not initialised, insufficient memory\n",
num_eth);
}
}
/*
** 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).
*/
if ((dev->next != NULL) &&
(num_eth > 0) && (num_eth < 9999)) {
dev = dev->next; /* point to the new device */
dev->name = (char *)(dev + sizeof(struct device));
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 = &ewrk3_probe; /* initialisation routine */
num_ewrk3s++;
}
return dev;
}
#endif /* MODULE */
/*
** Read the EWRK3 EEPROM using this routine
*/
static int Read_EEPROM(short iobase, unsigned char eaddr)
{
int i;
outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */
outb(EEPROM_RD, EWRK3_IOPR); /* issue read command */
for (i=0;i<5000;i++) inb(EWRK3_CSR); /* wait 1msec */
return inw(EWRK3_EPROM1); /* 16 bits data return */
}
/*
** Write the EWRK3 EEPROM using this routine
*/
static int Write_EEPROM(short data, short iobase, unsigned char eaddr)
{
int i;
outb(EEPROM_WR_EN, EWRK3_IOPR); /* issue write enable command */
for (i=0;i<5000;i++) inb(EWRK3_CSR); /* wait 1msec */
outw(data, EWRK3_EPROM1); /* write data to register */
outb((eaddr & 0x3f), EWRK3_PIR1); /* set up 6 bits of address info */
outb(EEPROM_WR, EWRK3_IOPR); /* issue write command */
for (i=0;i<75000;i++) inb(EWRK3_CSR); /* wait 15msec */
outb(EEPROM_WR_DIS, EWRK3_IOPR); /* issue write disable command */
for (i=0;i<5000;i++) inb(EWRK3_CSR); /* wait 1msec */
return 0;
}
/*
** Look for a particular board name in the on-board EEPROM.
*/
static void EthwrkSignature(char *name, char *eeprom_image)
{
unsigned long i,j,k;
char signatures[][EWRK3_NAME_LENGTH] = EWRK3_SIGNATURE;
strcpy(name, "");
for (i=0;*signatures[i] != '\0' && *name == '\0';i++) {
for (j=EEPROM_PNAME7,k=0;j<=EEPROM_PNAME0 && k<strlen(signatures[i]);j++) {
if (signatures[i][k] == eeprom_image[j]) { /* track signature */
k++;
} else { /* lost signature; begin search again */
k=0;
}
}
if (k == strlen(signatures[i])) {
for (k=0; k<EWRK3_NAME_LENGTH; k++) {
name[k] = eeprom_image[EEPROM_PNAME7 + k];
name[EWRK3_NAME_LENGTH] = '\0';
}
}
}
return; /* return the device name string */
}
/*
** Look for a special sequence in the Ethernet station address PROM that
** is common across all EWRK3 products.
*/
static int DevicePresent(short iobase)
{
static short fp=1,sigLength=0;
static char devSig[] = PROBE_SEQUENCE;
char data;
int i, j, status = 0;
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;
}
/*
** 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(EWRK3_APROM);
if (devSig[j] == data) { /* track signature */
j++;
} else { /* lost signature; begin search again */
j=0;
}
}
if (j!=sigLength) {
status = -ENODEV; /* search failed */
}
}
return status;
}
static unsigned char aprom_crc(struct device *dev, unsigned char *eeprom_image, char chipType)
{
long k;
unsigned short j,chksum;
unsigned char crc, lfsr, sd, status = 0;
int iobase = dev->base_addr;
if (chipType == LeMAC2) {
for (crc=0x6a, j=0; j<ETH_ALEN; j++) {
for (sd=inb(EWRK3_PAR0+j), k=0; k<8; k++, sd >>= 1) {
lfsr = ((((crc & 0x02) >> 1) ^ (crc & 0x01)) ^ (sd & 0x01)) << 7;
crc = (crc >> 1) + lfsr;
}
}
if (crc != eeprom_image[EEPROM_PA_CRC]) status = -1;
} else {
for (k=0,j=0;j<3;j++) {
k <<= 1 ;
if (k > 0xffff) k-=0xffff;
k += inw(EWRK3_PAR0 + (j<<1));
if (k > 0xffff) k-=0xffff;
}
if (k == 0xffff) k=0;
chksum = inb(EWRK3_APROM);
chksum |= (inb(EWRK3_APROM)<<8);
if (k != chksum) status = -1;
}
return status;
}
/*
** Perform IOCTL call functions here. Some are privileged operations and the
** effective uid is checked in those cases.
*/
static int ewrk3_ioctl(struct device *dev, struct ifreq *rq)
{
struct ewrk3_private *lp = (struct ewrk3_private *)dev->priv;
struct ewrk3_ioctl *ioc = (struct ewrk3_ioctl *) &rq->ifr_data;
int i, j, iobase = dev->base_addr, status = 0;
unsigned char csr;
union {
unsigned char addr[HASH_TABLE_LEN * ETH_ALEN];
unsigned short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
} tmp;
switch(ioc->cmd) {
case EWRK3_GET_HWADDR: /* Get the hardware address */
for (i=0; i<ETH_ALEN; i++) {
tmp.addr[i] = dev->dev_addr[i];
}
ioc->len = ETH_ALEN;
memcpy_tofs(ioc->data, tmp.addr, ioc->len);
break;
case EWRK3_SET_HWADDR: /* Set the hardware address */
if (suser()) {
csr = inb(EWRK3_CSR);
csr |= (TXD|RXD);
outb(csr, EWRK3_CSR); /* Disable the TX and RX */
memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
for (i=0; i<ETH_ALEN; i++) {
dev->dev_addr[i] = tmp.addr[i];
outb(tmp.addr[i], EWRK3_PAR0 + i);
}
csr &= ~(TXD|RXD); /* Enable the TX and RX */
outb(csr, EWRK3_CSR);
} else {
status = -EPERM;
}
break;
case EWRK3_SET_PROM: /* Set Promiscuous Mode */
if (suser()) {
csr = inb(EWRK3_CSR);
csr |= PME;
csr &= ~MCE;
outb(csr, EWRK3_CSR);
} else {
status = -EPERM;
}
break;
case EWRK3_CLR_PROM: /* Clear Promiscuous Mode */
if (suser()) {
csr = inb(EWRK3_CSR);
csr &= ~PME;
outb(csr, EWRK3_CSR);
} else {
status = -EPERM;
}
break;
case EWRK3_SAY_BOO: /* Say "Boo!" to the kernel log file */
printk("%s: Boo!\n", dev->name);
break;
case EWRK3_GET_MCA: /* Get the multicast address table */
while (set_bit(0, (void *)&lp->lock) != 0); /* Wait for lock to free */
if (lp->shmem_length == IO_ONLY) {
outb(0, EWRK3_IOPR);
outw(PAGE0_HTE, EWRK3_PIR1);
for (i=0; i<(HASH_TABLE_LEN >> 3); i++) {
tmp.addr[i] = inb(EWRK3_DATA);
}
} else {
outb(0, EWRK3_MPR);
memcpy(tmp.addr, (char *)(lp->shmem_base + PAGE0_HTE), (HASH_TABLE_LEN >> 3));
}
ioc->len = (HASH_TABLE_LEN >> 3);
memcpy_tofs(ioc->data, tmp.addr, ioc->len);
lp->lock = 0; /* Unlock the page register */
break;
case EWRK3_SET_MCA: /* Set a multicast address */
if (suser()) {
if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */
memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
}
set_multicast_list(dev, ioc->len, tmp.addr);
} else {
status = -EPERM;
}
break;
case EWRK3_CLR_MCA: /* Clear all multicast addresses */
if (suser()) {
set_multicast_list(dev, 0, NULL);
} else {
status = -EPERM;
}
break;
case EWRK3_MCA_EN: /* Enable multicast addressing */
if (suser()) {
csr = inb(EWRK3_CSR);
csr |= MCE;
csr &= ~PME;
outb(csr, EWRK3_CSR);
} else {
status = -EPERM;
}
break;
case EWRK3_GET_STATS: /* Get the driver statistics */
cli();
memcpy_tofs(ioc->data, &lp->pktStats, sizeof(lp->pktStats));
ioc->len = EWRK3_PKT_STAT_SZ;
sti();
break;
case EWRK3_CLR_STATS: /* Zero out the driver statistics */
if (suser()) {
cli();
memset(&lp->pktStats, 0, sizeof(lp->pktStats));
sti();
} else {
status = -EPERM;
}
break;
case EWRK3_GET_CSR: /* Get the CSR Register contents */
tmp.addr[0] = inb(EWRK3_CSR);
memcpy_tofs(ioc->data, tmp.addr, 1);
break;
case EWRK3_SET_CSR: /* Set the CSR Register contents */
if (suser()) {
memcpy_fromfs(tmp.addr, ioc->data, 1);
outb(tmp.addr[0], EWRK3_CSR);
} else {
status = -EPERM;
}
break;
case EWRK3_GET_EEPROM: /* Get the EEPROM contents */
if (suser()) {
for (i=0; i<(EEPROM_MAX>>1); i++) {
tmp.val[i] = (short)Read_EEPROM(iobase, i);
}
i = EEPROM_MAX;
tmp.addr[i++] = inb(EWRK3_CMR); /* Config/Management Reg. */
for (j=0;j<ETH_ALEN;j++) {
tmp.addr[i++] = inb(EWRK3_PAR0 + j);
}
ioc->len = EEPROM_MAX + 1 + ETH_ALEN;
memcpy_tofs(ioc->data, tmp.addr, ioc->len);
} else {
status = -EPERM;
}
break;
case EWRK3_SET_EEPROM: /* Set the EEPROM contents */
if (suser()) {
memcpy_fromfs(tmp.addr, ioc->data, EEPROM_MAX);
for (i=0; i<(EEPROM_MAX>>1); i++) {
Write_EEPROM(tmp.val[i], iobase, i);
}
} else {
status = -EPERM;
}
break;
case EWRK3_GET_CMR: /* Get the CMR Register contents */
tmp.addr[0] = inb(EWRK3_CMR);
memcpy_tofs(ioc->data, tmp.addr, 1);
break;
case EWRK3_SET_TX_CUT_THRU: /* Set TX cut through mode */
if (suser()) {
lp->txc = 1;
} else {
status = -EPERM;
}
break;
case EWRK3_CLR_TX_CUT_THRU: /* Clear TX cut through mode */
if (suser()) {
lp->txc = 0;
} else {
status = -EPERM;
}
break;
default:
status = -EOPNOTSUPP;
}
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 thisEthwrk = {
" ", /* device name inserted by /linux/drivers/net/net_init.c */
0, 0, 0, 0,
0x300, 5, /* I/O address, IRQ <--- EDIT THIS LINE FOR YOUR CONFIGURATION */
0, 0, 0, NULL, ewrk3_probe };
int
init_module(void)
{
if (register_netdev(&thisEthwrk) != 0)
return -EIO;
return 0;
}
void
cleanup_module(void)
{
if (MOD_IN_USE) {
printk("%s: device busy, remove delayed\n",thisEthwrk.name);
} else {
unregister_netdev(&thisEthwrk);
}
}
#endif /* MODULE */
/*
* Local variables:
* kernel-compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c"
*
* module-compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c"
* End:
*/
/*
Written 1994 by David C. Davies.
Copyright 1994 Digital Equipment Corporation.
This software may be used and distributed according to the terms of the
GNU Public License, incorporated herein by reference.
The author may be reached as davies@wanton.lkg.dec.com or Digital
Equipment Corporation, 550 King Street, Littleton MA 01460.
=========================================================================
*/
/*
** I/O Address Register Map
*/
#define EWRK3_CSR iobase+0x00 /* Control and Status Register */
#define EWRK3_CR iobase+0x01 /* Control Register */
#define EWRK3_ICR iobase+0x02 /* Interrupt Control Register */
#define EWRK3_TSR iobase+0x03 /* Transmit Status Register */
#define EWRK3_RSVD1 iobase+0x04 /* RESERVED */
#define EWRK3_RSVD2 iobase+0x05 /* RESERVED */
#define EWRK3_FMQ iobase+0x06 /* Free Memory Queue */
#define EWRK3_FMQC iobase+0x07 /* Free Memory Queue Counter */
#define EWRK3_RQ iobase+0x08 /* Receive Queue */
#define EWRK3_RQC iobase+0x09 /* Receive Queue Counter */
#define EWRK3_TQ iobase+0x0a /* Transmit Queue */
#define EWRK3_TQC iobase+0x0b /* Transmit Queue Counter */
#define EWRK3_TDQ iobase+0x0c /* Transmit Done Queue */
#define EWRK3_TDQC iobase+0x0d /* Transmit Done Queue Counter */
#define EWRK3_PIR1 iobase+0x0e /* Page Index Register 1 */
#define EWRK3_PIR2 iobase+0x0f /* Page Index Register 2 */
#define EWRK3_DATA iobase+0x10 /* Data Register */
#define EWRK3_IOPR iobase+0x11 /* I/O Page Register */
#define EWRK3_IOBR iobase+0x12 /* I/O Base Register */
#define EWRK3_MPR iobase+0x13 /* Memory Page Register */
#define EWRK3_MBR iobase+0x14 /* Memory Base Register */
#define EWRK3_APROM iobase+0x15 /* Address PROM */
#define EWRK3_EPROM1 iobase+0x16 /* EEPROM Data Register 1 */
#define EWRK3_EPROM2 iobase+0x17 /* EEPROM Data Register 2 */
#define EWRK3_PAR0 iobase+0x18 /* Physical Address Register 0 */
#define EWRK3_PAR1 iobase+0x19 /* Physical Address Register 1 */
#define EWRK3_PAR2 iobase+0x1a /* Physical Address Register 2 */
#define EWRK3_PAR3 iobase+0x1b /* Physical Address Register 3 */
#define EWRK3_PAR4 iobase+0x1c /* Physical Address Register 4 */
#define EWRK3_PAR5 iobase+0x1d /* Physical Address Register 5 */
#define EWRK3_CMR iobase+0x1e /* Configuration/Management Register */
/*
** Control Page Map
*/
#define PAGE0_FMQ 0x000 /* Free Memory Queue */
#define PAGE0_RQ 0x080 /* Receive Queue */
#define PAGE0_TQ 0x100 /* Transmit Queue */
#define PAGE0_TDQ 0x180 /* Transmit Done Queue */
#define PAGE0_HTE 0x200 /* Hash Table Entries */
#define PAGE0_RSVD 0x240 /* RESERVED */
#define PAGE0_USRD 0x600 /* User Data */
/*
** Control and Status Register bit definitions (EWRK3_CSR)
*/
#define RA 0x80 /* Runt Accept */
#define PME 0x40 /* Promiscuous Mode Enable */
#define MCE 0x20 /* Multicast Enable */
#define TNE 0x08 /* TX Done Queue Not Empty */
#define RNE 0x04 /* RX Queue Not Empty */
#define TXD 0x02 /* TX Disable */
#define RXD 0x01 /* RX Disable */
/*
** Control Register bit definitions (EWRK3_CR)
*/
#define APD 0x80 /* Auto Port Disable */
#define PSEL 0x40 /* Port Select (0->TP port) */
#define LBCK 0x20 /* LoopBaCK enable */
#define FDUP 0x10 /* Full DUPlex enable */
#define FBUS 0x08 /* Fast BUS enable (ISA clk > 8.33MHz) */
#define EN_16 0x04 /* ENable 16 bit memory accesses */
#define LED 0x02 /* LED (1-> turn on) */
/*
** Interrupt Control Register bit definitions (EWRK3_ICR)
*/
#define IE 0x80 /* Interrupt Enable */
#define IS 0x60 /* Interrupt Selected */
#define TNEM 0x08 /* TNE Mask (0->mask) */
#define RNEM 0x04 /* RNE Mask (0->mask) */
#define TXDM 0x02 /* TXD Mask (0->mask) */
#define RXDM 0x01 /* RXD Mask (0->mask) */
/*
** Transmit Status Register bit definitions (EWRK3_TSR)
*/
#define NCL 0x80 /* No Carrier Loopback */
#define ID 0x40 /* Initially Deferred */
#define LCL 0x20 /* Late CoLlision */
#define ECL 0x10 /* Excessive CoLlisions */
#define RCNTR 0x0f /* Retries CouNTeR */
/*
** I/O Page Register bit definitions (EWRK3_IOPR)
*/
#define EEPROM_INIT 0xc0 /* EEPROM INIT command */
#define EEPROM_WR_EN 0xc8 /* EEPROM WRITE ENABLE command */
#define EEPROM_WR 0xd0 /* EEPROM WRITE command */
#define EEPROM_WR_DIS 0xd8 /* EEPROM WRITE DISABLE command */
#define EEPROM_RD 0xe0 /* EEPROM READ command */
/*
** I/O Base Register bit definitions (EWRK3_IOBR)
*/
#define EISA 0x20 /* Enable EISA ID and Control Registers */
#define IOB 0x1f /* Compare bits for I/O Base Address */
/*
** I/O Congiguration/Management Register bit definitions (EWRK3_CMR)
*/
#define RA 0x80 /* Read Ahead */
#define WB 0x40 /* Write Behind */
#define LINK 0x20 /* 0->TP */
#define POLARITY 0x10 /* Informational */
#define NO_EEPROM 0x0c /* NO_EEPROM<1:0> pin status */
#define HS 0x08 /* Hard Strapped pin status (LeMAC2) */
#define PNP 0x04 /* Plug 'n Play */
#define DRAM 0x02 /* 0-> 1DRAM, 1-> 2 DRAM on board */
#define _0WS 0x01 /* Zero Wait State */
/*
** MAC Receive Status Register bit definitions
*/
#define ROK 0x80 /* Receive OK summary */
#define IAM 0x10 /* Individual Address Match */
#define MCM 0x08 /* MultiCast Match */
#define DBE 0x04 /* Dribble Bit Error */
#define CRC 0x02 /* CRC error */
#define PLL 0x01 /* Phase Lock Lost */
/*
** MAC Transmit Control Register bit definitions
*/
#define SQEE 0x40 /* SQE Enable - look for heartbeat */
#define SED 0x20 /* Stop when Error Detected */
#define QMODE 0x10 /* Q_MODE */
#define LAB 0x08 /* Less Aggressive Backoff */
#define PAD 0x04 /* PAD Runt Packets */
#define IFC 0x02 /* Insert Frame Check */
#define ISA 0x01 /* Insert Source Address */
/*
** MAC Transmit Status Register bit definitions
*/
#define VSTS 0x80 /* Valid STatuS */
#define MAC_CTU 0x40 /* Cut Through Used */
#define MAC_SQE 0x20 /* Signal Quality Error */
#define MAC_NCL 0x10 /* No Carrier Loopback */
#define MAC_LCL 0x08 /* Late Collision */
#define MAC_ID 0x04 /* Initially Deferred */
#define MAC_COLL 0x03 /* COLLision status */
#define MAC_XCOLL 0x03 /* Excessive Collisions */
#define MAC_MCOLL 0x02 /* Multiple Collisions */
#define MAC_OCOLL 0x01 /* One Collision */
#define MAC_NOCOLL 0x00 /* No Collisions */
#define MAC_XUR 0x03 /* Excessive Underruns */
#define MAC_TXE 0x7f /* TX Errors */
/*
** EISA Configuration Register bit definitions
*/
#define EISA_ID0 iobase + 0x0c80 /* EISA ID Register 0 */
#define EISA_ID1 iobase + 0x0c81 /* EISA ID Register 1 */
#define EISA_ID2 iobase + 0x0c82 /* EISA ID Register 2 */
#define EISA_ID3 iobase + 0x0c83 /* EISA ID Register 3 */
#define EISA_CR iobase + 0x0c84 /* EISA Control Register */
/*
** EEPROM BYTES
*/
#define EEPROM_MEMB 0x00
#define EEPROM_IOB 0x01
#define EEPROM_EISA_ID0 0x02
#define EEPROM_EISA_ID1 0x03
#define EEPROM_EISA_ID2 0x04
#define EEPROM_EISA_ID3 0x05
#define EEPROM_MISC0 0x06
#define EEPROM_MISC1 0x07
#define EEPROM_PNAME7 0x08
#define EEPROM_PNAME6 0x09
#define EEPROM_PNAME5 0x0a
#define EEPROM_PNAME4 0x0b
#define EEPROM_PNAME3 0x0c
#define EEPROM_PNAME2 0x0d
#define EEPROM_PNAME1 0x0e
#define EEPROM_PNAME0 0x0f
#define EEPROM_SWFLAGS 0x10
#define EEPROM_HWCAT 0x11
#define EEPROM_NETMAN2 0x12
#define EEPROM_REVLVL 0x13
#define EEPROM_NETMAN0 0x14
#define EEPROM_NETMAN1 0x15
#define EEPROM_CHIPVER 0x16
#define EEPROM_SETUP 0x17
#define EEPROM_PADDR0 0x18
#define EEPROM_PADDR1 0x19
#define EEPROM_PADDR2 0x1a
#define EEPROM_PADDR3 0x1b
#define EEPROM_PADDR4 0x1c
#define EEPROM_PADDR5 0x1d
#define EEPROM_PA_CRC 0x1e
#define EEPROM_CHKSUM 0x1f
/*
** EEPROM bytes for checksumming
*/
#define EEPROM_MAX 32 /* bytes */
/*
** EEPROM MISCELLANEOUS FLAGS
*/
#define RBE_SHADOW 0x0100 /* Remote Boot Enable Shadow */
#define READ_AHEAD 0x0080 /* Read Ahead feature */
#define IRQ_SEL2 0x0070 /* IRQ line selection (LeMAC2) */
#define IRQ_SEL 0x0060 /* IRQ line selection */
#define FAST_BUS 0x0008 /* ISA Bus speeds > 8.33MHz */
#define ENA_16 0x0004 /* Enables 16 bit memory transfers */
#define WRITE_BEHIND 0x0002 /* Write Behind feature */
#define _0WS_ENA 0x0001 /* Zero Wait State Enable */
/*
** EEPROM NETWORK MANAGEMENT FLAGS
*/
#define NETMAN_POL 0x04 /* Polarity defeat */
#define NETMAN_LINK 0x02 /* Link defeat */
#define NETMAN_CCE 0x01 /* Custom Counters Enable */
/*
** EEPROM SW FLAGS
*/
#define SW_SQE 0x10 /* Signal Quality Error */
#define SW_LAB 0x08 /* Less Aggressive Backoff */
#define SW_INIT 0x04 /* Initialized */
#define SW_TIMEOUT 0x02 /* 0:2.5 mins, 1: 30 secs */
#define SW_REMOTE 0x01 /* Remote Boot Enable -> 1 */
/*
** EEPROM SETUP FLAGS
*/
#define SETUP_APD 0x80 /* AutoPort Disable */
#define SETUP_PS 0x40 /* Port Select */
#define SETUP_MP 0x20 /* MultiPort */
#define SETUP_1TP 0x10 /* 1 port, TP */
#define SETUP_1COAX 0x00 /* 1 port, Coax */
#define SETUP_DRAM 0x02 /* Number of DRAMS on board */
/*
** EEPROM MANAGEMENT FLAGS
*/
#define MGMT_CCE 0x01 /* Custom Counters Enable */
/*
** EEPROM VERSIONS
*/
#define LeMAC 0x11
#define LeMAC2 0x12
/*
** Miscellaneous
*/
#define EEPROM_WAIT_TIME 1000 /* Number of microseconds */
#define EISA_EN 0x0001 /* Enable EISA bus buffers */
#define HASH_TABLE_LEN 512 /* Bits */
#define XCT 0x80 /* Transmit Cut Through */
#define PRELOAD 16 /* 4 long words */
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
/*
** Include the IOCTL stuff
*/
#include <linux/sockios.h>
#define EWRK3IOCTL SIOCDEVPRIVATE
struct ewrk3_ioctl {
unsigned short cmd; /* Command to run */
unsigned short len; /* Length of the data buffer */
unsigned char *data; /* Pointer to the data buffer */
};
/*
** Recognised commands for the driver
*/
#define EWRK3_GET_HWADDR 0x01 /* Get the hardware address */
#define EWRK3_SET_HWADDR 0x02 /* Get the hardware address */
#define EWRK3_SET_PROM 0x03 /* Set Promiscuous Mode */
#define EWRK3_CLR_PROM 0x04 /* Clear Promiscuous Mode */
#define EWRK3_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */
#define EWRK3_GET_MCA 0x06 /* Get a multicast address */
#define EWRK3_SET_MCA 0x07 /* Set a multicast address */
#define EWRK3_CLR_MCA 0x08 /* Clear a multicast address */
#define EWRK3_MCA_EN 0x09 /* Enable a multicast address group */
#define EWRK3_GET_STATS 0x0a /* Get the driver statistics */
#define EWRK3_CLR_STATS 0x0b /* Zero out the driver statistics */
#define EWRK3_GET_CSR 0x0c /* Get the CSR Register contents */
#define EWRK3_SET_CSR 0x0d /* Set the CSR Register contents */
#define EWRK3_GET_EEPROM 0x0e /* Get the EEPROM contents */
#define EWRK3_SET_EEPROM 0x0f /* Set the EEPROM contents */
#define EWRK3_GET_CMR 0x10 /* Get the CMR Register contents */
#define EWRK3_CLR_TX_CUT_THRU 0x11 /* Clear the TX cut through mode */
#define EWRK3_SET_TX_CUT_THRU 0x12 /* Set the TX cut through mode */
...@@ -24,7 +24,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -24,7 +24,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
loff_t offset; loff_t offset;
int chars; int chars;
int written = 0; int written = 0;
int cluster_list[4]; int cluster_list[8];
struct buffer_head * bhlist[NBUF]; struct buffer_head * bhlist[NBUF];
int blocks_per_cluster; int blocks_per_cluster;
unsigned int size; unsigned int size;
...@@ -159,7 +159,7 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count) ...@@ -159,7 +159,7 @@ int block_read(struct inode * inode, struct file * filp, char * buf, int count)
int blocksize_bits, i; int blocksize_bits, i;
unsigned int blocks, rblocks, left; unsigned int blocks, rblocks, left;
int bhrequest, uptodate; int bhrequest, uptodate;
int cluster_list[4]; int cluster_list[8];
int blocks_per_cluster; int blocks_per_cluster;
struct buffer_head ** bhb, ** bhe; struct buffer_head ** bhb, ** bhe;
struct buffer_head * buflist[NBUF]; struct buffer_head * buflist[NBUF];
......
...@@ -122,6 +122,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data, ...@@ -122,6 +122,7 @@ struct super_block *minix_read_super(struct super_block *s,void *data,
if (32 != sizeof (struct minix_inode)) if (32 != sizeof (struct minix_inode))
panic("bad i-node size"); panic("bad i-node size");
lock_super(s); lock_super(s);
set_blocksize(dev, BLOCK_SIZE);
if (!(bh = bread(dev,1,BLOCK_SIZE))) { if (!(bh = bread(dev,1,BLOCK_SIZE))) {
s->s_dev=0; s->s_dev=0;
unlock_super(s); unlock_super(s);
......
...@@ -20,7 +20,6 @@ int fat_access(struct super_block *sb,int nr,int new_value) ...@@ -20,7 +20,6 @@ int fat_access(struct super_block *sb,int nr,int new_value)
{ {
struct buffer_head *bh,*bh2,*c_bh,*c_bh2; struct buffer_head *bh,*bh2,*c_bh,*c_bh2;
unsigned char *p_first,*p_last; unsigned char *p_first,*p_last;
void *data,*data2,*c_data,*c_data2;
int first,last,next,copy; int first,last,next,copy;
if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0; if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0;
...@@ -30,17 +29,15 @@ int fat_access(struct super_block *sb,int nr,int new_value) ...@@ -30,17 +29,15 @@ int fat_access(struct super_block *sb,int nr,int new_value)
last = first+1; last = first+1;
} }
if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >> if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >>
SECTOR_BITS),&data))) { SECTOR_BITS)))) {
printk("bread in fat_access failed\n"); printk("bread in fat_access failed\n");
return 0; return 0;
} }
if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) { if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS))
bh2 = bh; bh2 = bh;
data2 = data;
}
else { else {
if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last
>> SECTOR_BITS),&data2))) { >> SECTOR_BITS)))) {
brelse(bh); brelse(bh);
printk("bread in fat_access failed\n"); printk("bread in fat_access failed\n");
return 0; return 0;
...@@ -48,13 +45,13 @@ int fat_access(struct super_block *sb,int nr,int new_value) ...@@ -48,13 +45,13 @@ int fat_access(struct super_block *sb,int nr,int new_value)
} }
if (MSDOS_SB(sb)->fat_bits == 16) { if (MSDOS_SB(sb)->fat_bits == 16) {
p_first = p_last = NULL; /* GCC needs that stuff */ p_first = p_last = NULL; /* GCC needs that stuff */
next = CF_LE_W(((unsigned short *) data)[(first & next = CF_LE_W(((unsigned short *) bh->b_data)[(first &
(SECTOR_SIZE-1)) >> 1]); (SECTOR_SIZE-1)) >> 1]);
if (next >= 0xfff7) next = -1; if (next >= 0xfff7) next = -1;
} }
else { else {
p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)]; p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)];
p_last = &((unsigned char *) data2)[(first+1) & p_last = &((unsigned char *) bh2->b_data)[(first+1) &
(SECTOR_SIZE-1)]; (SECTOR_SIZE-1)];
if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff; if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff;
else next = (*p_first+(*p_last << 8)) & 0xfff; else next = (*p_first+(*p_last << 8)) & 0xfff;
...@@ -62,7 +59,7 @@ int fat_access(struct super_block *sb,int nr,int new_value) ...@@ -62,7 +59,7 @@ int fat_access(struct super_block *sb,int nr,int new_value)
} }
if (new_value != -1) { if (new_value != -1) {
if (MSDOS_SB(sb)->fat_bits == 16) if (MSDOS_SB(sb)->fat_bits == 16)
((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >> ((unsigned short *) bh->b_data)[(first & (SECTOR_SIZE-1)) >>
1] = CT_LE_W(new_value); 1] = CT_LE_W(new_value);
else { else {
if (nr & 1) { if (nr & 1) {
...@@ -79,25 +76,25 @@ int fat_access(struct super_block *sb,int nr,int new_value) ...@@ -79,25 +76,25 @@ int fat_access(struct super_block *sb,int nr,int new_value)
for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) {
if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)-> if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->
fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->
fat_length*copy,&c_data))) break; fat_length*copy))) break;
memcpy(c_data,data,SECTOR_SIZE); memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE);
mark_buffer_dirty(c_bh, 1); mark_buffer_dirty(c_bh, 1);
if (data != data2 || bh != bh2) { if (bh != bh2) {
if (!(c_bh2 = msdos_sread(sb->s_dev, if (!(c_bh2 = msdos_sread(sb->s_dev,
MSDOS_SB(sb)->fat_start+(first >> MSDOS_SB(sb)->fat_start+(first >>
SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy
+1,&c_data2))) { +1))) {
brelse(c_bh); brelse(c_bh);
break; break;
} }
memcpy(c_data2,data2,SECTOR_SIZE); memcpy(c_bh2->b_data,bh2->b_data,SECTOR_SIZE);
brelse(c_bh2); brelse(c_bh2);
} }
brelse(c_bh); brelse(c_bh);
} }
} }
brelse(bh); brelse(bh);
if (data != data2) brelse(bh2); if (bh != bh2) brelse(bh2);
return next; return next;
} }
......
...@@ -30,7 +30,7 @@ static struct file_operations msdos_file_operations = { ...@@ -30,7 +30,7 @@ static struct file_operations msdos_file_operations = {
NULL, /* readdir - bad */ NULL, /* readdir - bad */
NULL, /* select - default */ NULL, /* select - default */
NULL, /* ioctl - default */ NULL, /* ioctl - default */
generic_mmap, /* mmap */ generic_mmap, /* mmap */
NULL, /* no special open is needed */ NULL, /* no special open is needed */
NULL, /* release */ NULL, /* release */
file_fsync /* fsync */ file_fsync /* fsync */
...@@ -52,7 +52,7 @@ struct inode_operations msdos_file_inode_operations = { ...@@ -52,7 +52,7 @@ struct inode_operations msdos_file_inode_operations = {
msdos_bmap, /* bmap */ msdos_bmap, /* bmap */
msdos_truncate, /* truncate */ msdos_truncate, /* truncate */
NULL, /* permission */ NULL, /* permission */
NULL /* smap */ NULL /* smap */
}; };
/* /*
...@@ -127,12 +127,11 @@ int msdos_file_read( ...@@ -127,12 +127,11 @@ int msdos_file_read(
int sector; int sector;
if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
break; break;
if (!(bh = msdos_sread(inode->i_dev,sector,&data))) if (!(bh = msdos_sread(inode->i_dev,sector)))
break; break;
}else{ }else{
bh = pre.bhlist[pre.nolist]; bh = pre.bhlist[pre.nolist];
pre.bhlist[pre.nolist++] = NULL; pre.bhlist[pre.nolist++] = NULL;
data = bh->b_data;
wait_on_buffer(bh); wait_on_buffer(bh);
if (!bh->b_uptodate){ if (!bh->b_uptodate){
/* read error ? */ /* read error ? */
...@@ -140,6 +139,7 @@ int msdos_file_read( ...@@ -140,6 +139,7 @@ int msdos_file_read(
break; break;
} }
} }
data = bh->b_data;
offset = filp->f_pos & (SECTOR_SIZE-1); offset = filp->f_pos & (SECTOR_SIZE-1);
filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left)); filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
if (MSDOS_I(inode)->i_binary) { if (MSDOS_I(inode)->i_binary) {
...@@ -183,7 +183,6 @@ int msdos_file_write( ...@@ -183,7 +183,6 @@ int msdos_file_write(
int error,carry; int error,carry;
char *start,*to,ch; char *start,*to,ch;
struct buffer_head *bh; struct buffer_head *bh;
void *data;
int binary_mode = MSDOS_I(inode)->i_binary; int binary_mode = MSDOS_I(inode)->i_binary;
if (!inode) { if (!inode) {
...@@ -211,25 +210,28 @@ int msdos_file_write( ...@@ -211,25 +210,28 @@ int msdos_file_write(
} }
offset = filp->f_pos & (SECTOR_SIZE-1); offset = filp->f_pos & (SECTOR_SIZE-1);
size = MIN(SECTOR_SIZE-offset,MAX(carry,count)); size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
if (binary_mode && offset == 0 && size == SECTOR_SIZE){ if (binary_mode
&& offset == 0
&& (size == SECTOR_SIZE
|| filp->f_pos + size >= inode->i_size)){
/* No need to read the block first since we will */ /* No need to read the block first since we will */
/* completely overwrite it */ /* completely overwrite it */
/* or at least write past the end of file */
if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){ if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
error = -EIO; error = -EIO;
break; break;
} }
data = bh->b_data; }else if (!(bh = msdos_sread(inode->i_dev,sector))) {
}else if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
error = -EIO; error = -EIO;
break; break;
} }
if (binary_mode) { if (binary_mode) {
memcpy_fromfs(data+offset,buf,written = size); memcpy_fromfs(bh->b_data+offset,buf,written = size);
buf += size; buf += size;
} }
else { else {
written = left = SECTOR_SIZE-offset; written = left = SECTOR_SIZE-offset;
to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1)); to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
if (carry) { if (carry) {
*to++ = '\n'; *to++ = '\n';
left--; left--;
......
...@@ -172,20 +172,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data, ...@@ -172,20 +172,7 @@ struct super_block *msdos_read_super(struct super_block *s,void *data,
} }
cache_init(); cache_init();
lock_super(s); lock_super(s);
if (MAJOR(s->s_dev) == FLOPPY_MAJOR){ set_blocksize(s->s_dev, SECTOR_SIZE);
/* Patch for floppy which lacks a table ??? */
static int tbdef[]={
1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,
1024,1024,1024,1024,1024,
};
blksize_size[FLOPPY_MAJOR] = tbdef;
}
set_blocksize (s->s_dev,SECTOR_SIZE);
bh = bread(s->s_dev, 0, SECTOR_SIZE); bh = bread(s->s_dev, 0, SECTOR_SIZE);
unlock_super(s); unlock_super(s);
if (bh == NULL) { if (bh == NULL) {
......
...@@ -256,7 +256,6 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, ...@@ -256,7 +256,6 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
struct msdos_dir_entry **de) struct msdos_dir_entry **de)
{ {
int sector,offset; int sector,offset;
void *data;
while (1) { while (1) {
offset = *pos; offset = *pos;
...@@ -270,12 +269,12 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, ...@@ -270,12 +269,12 @@ int msdos_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh,
if (*bh) if (*bh)
brelse(*bh); brelse(*bh);
PRINTK (("get_entry sector apres brelse\n")); PRINTK (("get_entry sector apres brelse\n"));
if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) { if (!(*bh = msdos_sread(dir->i_dev,sector))) {
printk("Directory sread (sector %d) failed\n",sector); printk("Directory sread (sector %d) failed\n",sector);
continue; continue;
} }
PRINTK (("get_entry apres sread\n")); PRINTK (("get_entry apres sread\n"));
*de = (struct msdos_dir_entry *) (data+(offset & *de = (struct msdos_dir_entry *) ((*bh)->b_data+(offset &
(SECTOR_SIZE-1))); (SECTOR_SIZE-1)));
return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >> return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >>
MSDOS_DIR_BITS); MSDOS_DIR_BITS);
...@@ -344,7 +343,8 @@ static int raw_scan_sector(struct super_block *sb,int sector,char *name, ...@@ -344,7 +343,8 @@ static int raw_scan_sector(struct super_block *sb,int sector,char *name,
struct inode *inode; struct inode *inode;
int entry,start,done; int entry,start,done;
if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO; if (!(bh = msdos_sread(sb->s_dev,sector))) return -EIO;
data = (struct msdos_dir_entry *) bh->b_data;
for (entry = 0; entry < MSDOS_DPS; entry++) { for (entry = 0; entry < MSDOS_DPS; entry++) {
if (name) RSS_NAME if (name) RSS_NAME
else { else {
......
...@@ -33,7 +33,10 @@ asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int ...@@ -33,7 +33,10 @@ asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int
return -EBADF; return -EBADF;
error = -ENOTDIR; error = -ENOTDIR;
if (file->f_op && file->f_op->readdir) { if (file->f_op && file->f_op->readdir) {
error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent)); int size = count;
if (count == 1)
size = sizeof(*dirent);
error = verify_area(VERIFY_WRITE, dirent, size);
if (!error) if (!error)
error = file->f_op->readdir(inode,file,dirent,count); error = file->f_op->readdir(inode,file,dirent,count);
} }
......
...@@ -273,7 +273,13 @@ void UMSDOS_write_inode(struct inode *inode) ...@@ -273,7 +273,13 @@ void UMSDOS_write_inode(struct inode *inode)
newattrs.ia_atime = inode->i_atime; newattrs.ia_atime = inode->i_atime;
newattrs.ia_ctime = inode->i_ctime; newattrs.ia_ctime = inode->i_ctime;
newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME; newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
/*
UMSDOS_notify_change is convenient to call here
to update the EMD entry associated with this inode.
But it has the side effect to re"dirt" the inode.
*/
UMSDOS_notify_change (inode, &newattrs); UMSDOS_notify_change (inode, &newattrs);
inode->i_dirt = 0;
} }
int UMSDOS_notify_change(struct inode *inode, struct iattr *attr) int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
...@@ -319,6 +325,7 @@ int UMSDOS_notify_change(struct inode *inode, struct iattr *attr) ...@@ -319,6 +325,7 @@ int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
struct file filp; struct file filp;
struct umsdos_dirent entry; struct umsdos_dirent entry;
filp.f_pos = inode->u.umsdos_i.pos; filp.f_pos = inode->u.umsdos_i.pos;
filp.f_reada = 0;
PRINTK (("pos = %d ",filp.f_pos)); PRINTK (("pos = %d ",filp.f_pos));
/* Read only the start of the entry since we don't touch */ /* Read only the start of the entry since we don't touch */
/* the name */ /* the name */
......
...@@ -35,7 +35,6 @@ static int find_first_zero(struct buffer_head *bh, int start_bit, int end_bit) ...@@ -35,7 +35,6 @@ static int find_first_zero(struct buffer_head *bh, int start_bit, int end_bit)
int end, i, j, tmp; int end, i, j, tmp;
u_long *bmap; u_long *bmap;
char res;
bmap=(u_long *)bh->b_data; bmap=(u_long *)bh->b_data;
end = end_bit >> 5; end = end_bit >> 5;
......
...@@ -377,10 +377,16 @@ struct cdrom_read_audio ...@@ -377,10 +377,16 @@ struct cdrom_read_audio
/* read type-1 data */ /* read type-1 data */
/* /*
* preliminary extension for transferring audio frames * preliminary extension for transferring audio frames
* currently used by sbpcd.c * currently used by cdu31a.c and sbpcd.c
* (still may change if other drivers will use it, too): * (still may change if other drivers will use it, too):
*/ */
#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ #define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */
/*
* preliminary extension for enable (1) / disable (0) auto-ejecting
* currently used by sbpcd.c
* (still may change if other drivers will use it, too):
*/
#define CDROMEJECT_SW 0x530f /* arg: 0 or 1 */
#endif _LINUX_CDROM_H #endif _LINUX_CDROM_H
...@@ -39,7 +39,7 @@ struct ipc_perm ...@@ -39,7 +39,7 @@ struct ipc_perm
#define IPC_NOID ((void *) -2) /* being allocated/destroyed */ #define IPC_NOID ((void *) -2) /* being allocated/destroyed */
/* /*
* These are used to wrap system calls. See ipc/util.c, libipc.c * These are used to wrap system calls. See ipc/util.c.
*/ */
struct ipc_kludge { struct ipc_kludge {
struct msgbuf *msgp; struct msgbuf *msgp;
......
...@@ -110,13 +110,9 @@ struct fat_cache { ...@@ -110,13 +110,9 @@ struct fat_cache {
#ifdef __KERNEL__ #ifdef __KERNEL__
static inline struct buffer_head *msdos_sread(int dev,int sector,void **start) static inline struct buffer_head *msdos_sread(int dev,int sector)
{ {
struct buffer_head *bh = bread(dev,sector, 512); return bread(dev,sector,SECTOR_SIZE);
if (bh != NULL){
*start = bh->b_data; /* From the time of 1024 bytes block */
}
return bh;
} }
......
...@@ -6,15 +6,6 @@ ...@@ -6,15 +6,6 @@
#define MSG_NOERROR 010000 /* no error if message is too big */ #define MSG_NOERROR 010000 /* no error if message is too big */
#define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/ #define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/
/* one msg structure for each message */
struct msg {
struct msg *msg_next; /* next message on queue */
long msg_type;
char *msg_spot; /* message text address */
short msg_ts; /* message text size */
};
/* one msqid structure for each queue on the system */ /* one msqid structure for each queue on the system */
struct msqid_ds { struct msqid_ds {
struct ipc_perm msg_perm; struct ipc_perm msg_perm;
...@@ -32,14 +23,13 @@ struct msqid_ds { ...@@ -32,14 +23,13 @@ struct msqid_ds {
ushort msg_lrpid; /* last receive pid */ ushort msg_lrpid; /* last receive pid */
}; };
/* message buffer for msgsnd and msgrcv calls */ /* message buffer for msgsnd and msgrcv calls */
struct msgbuf { struct msgbuf {
long mtype; /* type of message */ long mtype; /* type of message */
char mtext[1]; /* message text */ char mtext[1]; /* message text */
}; };
/* buffer for msgctl calls IPC_INFO, MSG_INFO */
struct msginfo { struct msginfo {
int msgpool; int msgpool;
int msgmap; int msgmap;
...@@ -65,6 +55,14 @@ struct msginfo { ...@@ -65,6 +55,14 @@ struct msginfo {
#ifdef __KERNEL__ #ifdef __KERNEL__
/* one msg structure for each message */
struct msg {
struct msg *msg_next; /* next message on queue */
long msg_type;
char *msg_spot; /* message text address */
short msg_ts; /* message text size */
};
/* ipcs ctl commands */ /* ipcs ctl commands */
#define MSG_STAT 11 #define MSG_STAT 11
#define MSG_INFO 12 #define MSG_INFO 12
......
...@@ -290,7 +290,7 @@ struct task_struct { ...@@ -290,7 +290,7 @@ struct task_struct {
struct tty_struct *tty; /* NULL if no tty */ struct tty_struct *tty; /* NULL if no tty */
/* shm stuff */ /* shm stuff */
struct shm_desc *shm; struct shm_desc *shm;
struct sem_undo *semun; struct sem_undo *semundo;
/* ldt for this task - used by Wine. If NULL, default_ldt is used */ /* ldt for this task - used by Wine. If NULL, default_ldt is used */
struct desc_struct *ldt; struct desc_struct *ldt;
/* tss for this task */ /* tss for this task */
......
...@@ -26,16 +26,7 @@ struct semid_ds { ...@@ -26,16 +26,7 @@ struct semid_ds {
ushort sem_nsems; /* no. of semaphores in array */ ushort sem_nsems; /* no. of semaphores in array */
}; };
/* semop system calls takes an array of these. */
/* One semaphore structure for each semaphore in the system. */
struct sem {
short sempid; /* pid of last operation */
ushort semval; /* current value */
ushort semncnt; /* num procs awaiting increase in semval */
ushort semzcnt; /* num procs awaiting semval = 0 */
};
/* semop system calls takes an array of these.*/
struct sembuf { struct sembuf {
ushort sem_num; /* semaphore index in array */ ushort sem_num; /* semaphore index in array */
short sem_op; /* semaphore operation */ short sem_op; /* semaphore operation */
...@@ -44,12 +35,13 @@ struct sembuf { ...@@ -44,12 +35,13 @@ struct sembuf {
/* arg for semctl system calls. */ /* arg for semctl system calls. */
union semun { union semun {
int val; /* value for SETVAL */ int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
ushort *array; /* array for GETALL & SETALL */ ushort *array; /* array for GETALL & SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
void *__pad;
}; };
struct seminfo { struct seminfo {
int semmap; int semmap;
int semmni; int semmni;
...@@ -77,6 +69,15 @@ struct seminfo { ...@@ -77,6 +69,15 @@ struct seminfo {
#define SEMUSZ 20 /* sizeof struct sem_undo */ #define SEMUSZ 20 /* sizeof struct sem_undo */
#ifdef __KERNEL__ #ifdef __KERNEL__
/* One semaphore structure for each semaphore in the system. */
struct sem {
short sempid; /* pid of last operation */
ushort semval; /* current value */
ushort semncnt; /* num procs awaiting increase in semval */
ushort semzcnt; /* num procs awaiting semval = 0 */
};
/* ipcs ctl cmds */ /* ipcs ctl cmds */
#define SEM_STAT 18 #define SEM_STAT 18
#define SEM_INFO 19 #define SEM_INFO 19
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include <linux/ipc.h> #include <linux/ipc.h>
struct shmid_ds { struct shmid_ds {
struct ipc_perm shm_perm; /* operation perms */ struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */ int shm_segsz; /* size of segment (bytes) */
time_t shm_atime; /* last attach time */ time_t shm_atime; /* last attach time */
time_t shm_dtime; /* last detach time */ time_t shm_dtime; /* last detach time */
...@@ -12,9 +12,9 @@ struct shmid_ds { ...@@ -12,9 +12,9 @@ struct shmid_ds {
unsigned short shm_lpid; /* pid of last operator */ unsigned short shm_lpid; /* pid of last operator */
short shm_nattch; /* no. of current attaches */ short shm_nattch; /* no. of current attaches */
/* the following are private */ /* the following are private */
unsigned short shm_npages; /* size of segment (pages) */ unsigned short shm_npages; /* size of segment (pages) */
unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */
struct shm_desc *attaches; /* descriptors for attaches */ struct shm_desc *attaches; /* descriptors for attaches */
}; };
/* mode for attach */ /* mode for attach */
...@@ -34,34 +34,35 @@ struct shminfo { ...@@ -34,34 +34,35 @@ struct shminfo {
int shmall; int shmall;
}; };
/* address range for shared memory attaches if no address passed to shmat() */
#define SHM_RANGE_START 0x40000000 #define SHM_RANGE_START 0x40000000
#define SHM_RANGE_END 0x60000000 #define SHM_RANGE_END 0x60000000
/* _SHM_ID_BITS is a variable you can adjust to */ /* format of page table entries that correspond to shared memory pages
/* tune the kernel. It determines the value of */ currently out in swap space (see also mm/swap.c):
/* SHMMNI, which specifies the maximum no. of */ bit 0 (PAGE_PRESENT) is = 0
/* shared segments (system wide). SRB. */ bits 7..1 (SWP_TYPE) are = SHM_SWP_TYPE
#define _SHM_ID_BITS 7 /* keep as low as possible */ bits 31..8 are used like this:
/* a static array is declared */ bits 14..8 (SHM_ID) the id of the shared memory segment
/* using SHMMNI */ bits 29..15 (SHM_IDX) the index of the page within the shared memory segment
(actually only bits 24..15 get used since SHMMAX is so low)
bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
*/
#define __SHM_IDX_BITS (BITS_PER_PTR-2-SHM_IDX_SHIFT)
/* !!!!!!!?????
* Why reserve the two (2) high bits of the signature (shm_sgn) field?
* Since, as far as I can see, only the high bit is used (SHM_READ_ONLY).
* SRB.
*/
#define _SHM_IDX_BITS (__SHM_IDX_BITS+PAGE_SHIFT>=BITS_PER_PTR?\
BITS_PER_PTR-PAGE_SHIFT-1:__SHM_IDX_BITS) /* sanity check */
/* not present page table entry format bit 0 is 0, low byte defined in mm.h */
#define SHM_ID_SHIFT 8 #define SHM_ID_SHIFT 8
/* Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
there is a static array of size SHMMNI. */
#define _SHM_ID_BITS 7
#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) #define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1)
#define SHM_IDX_SHIFT (SHM_ID_SHIFT+_SHM_ID_BITS) #define SHM_IDX_SHIFT (SHM_ID_SHIFT+_SHM_ID_BITS)
#define _SHM_IDX_BITS 15
#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1) #define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1)
#define SHM_READ_ONLY (1<<(BITS_PER_PTR-1))
#define SHM_READ_ONLY (1<<31)
/* We must have SHM_ID_SHIFT + _SHM_ID_BITS + _SHM_IDX_BITS + 1 <= 32
and SHMMAX <= (PAGE_SIZE << _SHM_IDX_BITS). */
#define SHMMAX 0x3fa000 /* max shared seg size (bytes) */ #define SHMMAX 0x3fa000 /* max shared seg size (bytes) */
#define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */ #define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */
...@@ -106,4 +107,3 @@ struct shm_desc { ...@@ -106,4 +107,3 @@ struct shm_desc {
#endif /* _LINUX_SHM_H_ */ #endif /* _LINUX_SHM_H_ */
...@@ -29,7 +29,7 @@ void msg_init (void) ...@@ -29,7 +29,7 @@ void msg_init (void)
{ {
int id; int id;
for (id=0; id < MSGMNI; id++) for (id = 0; id < MSGMNI; id++)
msgque[id] = (struct msqid_ds *) IPC_UNUSED; msgque[id] = (struct msqid_ds *) IPC_UNUSED;
msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0; msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0;
msg_lock = NULL; msg_lock = NULL;
...@@ -53,14 +53,14 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg) ...@@ -53,14 +53,14 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
return err; return err;
if ((mtype = get_fs_long (&msgp->mtype)) < 1) if ((mtype = get_fs_long (&msgp->mtype)) < 1)
return -EINVAL; return -EINVAL;
id = msqid % MSGMNI; id = (unsigned int) msqid % MSGMNI;
msq = msgque [id]; msq = msgque [id];
if (msq == IPC_UNUSED || msq == IPC_NOID) if (msq == IPC_UNUSED || msq == IPC_NOID)
return -EINVAL; return -EINVAL;
ipcp = &msq->msg_perm; ipcp = &msq->msg_perm;
slept: slept:
if (ipcp->seq != (msqid / MSGMNI)) if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
return -EIDRM; return -EIDRM;
if (ipcperms(ipcp, S_IWUGO)) if (ipcperms(ipcp, S_IWUGO))
return -EACCES; return -EACCES;
...@@ -83,7 +83,7 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg) ...@@ -83,7 +83,7 @@ int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg)
memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz);
if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID
|| ipcp->seq != msqid / MSGMNI) { || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) {
kfree(msgh); kfree(msgh);
return -EIDRM; return -EIDRM;
} }
...@@ -125,7 +125,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, ...@@ -125,7 +125,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
if (err) if (err)
return err; return err;
id = msqid % MSGMNI; id = (unsigned int) msqid % MSGMNI;
msq = msgque [id]; msq = msgque [id];
if (msq == IPC_NOID || msq == IPC_UNUSED) if (msq == IPC_NOID || msq == IPC_UNUSED)
return -EINVAL; return -EINVAL;
...@@ -138,7 +138,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, ...@@ -138,7 +138,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
* msgtyp < 0 => get message with least type must be < abs(msgtype). * msgtyp < 0 => get message with least type must be < abs(msgtype).
*/ */
while (!nmsg) { while (!nmsg) {
if(ipcp->seq != msqid / MSGMNI) if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
return -EIDRM; return -EIDRM;
if (ipcperms (ipcp, S_IRUGO)) if (ipcperms (ipcp, S_IRUGO))
return -EACCES; return -EACCES;
...@@ -174,7 +174,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, ...@@ -174,7 +174,7 @@ int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
if (nmsg == msq->msg_first) if (nmsg == msq->msg_first)
msq->msg_first = nmsg->msg_next; msq->msg_first = nmsg->msg_next;
else { else {
for (tmsg= msq->msg_first; tmsg; for (tmsg = msq->msg_first; tmsg;
tmsg = tmsg->msg_next) tmsg = tmsg->msg_next)
if (tmsg->msg_next == nmsg) if (tmsg->msg_next == nmsg)
break; break;
...@@ -213,7 +213,7 @@ static int findkey (key_t key) ...@@ -213,7 +213,7 @@ static int findkey (key_t key)
int id; int id;
struct msqid_ds *msq; struct msqid_ds *msq;
for (id=0; id <= max_msqid; id++) { for (id = 0; id <= max_msqid; id++) {
while ((msq = msgque[id]) == IPC_NOID) while ((msq = msgque[id]) == IPC_NOID)
interruptible_sleep_on (&msg_lock); interruptible_sleep_on (&msg_lock);
if (msq == IPC_UNUSED) if (msq == IPC_UNUSED)
...@@ -230,7 +230,7 @@ static int newque (key_t key, int msgflg) ...@@ -230,7 +230,7 @@ static int newque (key_t key, int msgflg)
struct msqid_ds *msq; struct msqid_ds *msq;
struct ipc_perm *ipcp; struct ipc_perm *ipcp;
for (id=0; id < MSGMNI; id++) for (id = 0; id < MSGMNI; id++)
if (msgque[id] == IPC_UNUSED) { if (msgque[id] == IPC_UNUSED) {
msgque[id] = (struct msqid_ds *) IPC_NOID; msgque[id] = (struct msqid_ds *) IPC_NOID;
goto found; goto found;
...@@ -250,7 +250,7 @@ static int newque (key_t key, int msgflg) ...@@ -250,7 +250,7 @@ static int newque (key_t key, int msgflg)
ipcp->key = key; ipcp->key = key;
ipcp->cuid = ipcp->uid = current->euid; ipcp->cuid = ipcp->uid = current->euid;
ipcp->gid = ipcp->cgid = current->egid; ipcp->gid = ipcp->cgid = current->egid;
ipcp->seq = msg_seq; msq->msg_perm.seq = msg_seq;
msq->msg_first = msq->msg_last = NULL; msq->msg_first = msq->msg_last = NULL;
msq->rwait = msq->wwait = NULL; msq->rwait = msq->wwait = NULL;
msq->msg_cbytes = msq->msg_qnum = 0; msq->msg_cbytes = msq->msg_qnum = 0;
...@@ -264,7 +264,7 @@ static int newque (key_t key, int msgflg) ...@@ -264,7 +264,7 @@ static int newque (key_t key, int msgflg)
used_queues++; used_queues++;
if (msg_lock) if (msg_lock)
wake_up (&msg_lock); wake_up (&msg_lock);
return (int) msg_seq * MSGMNI + id; return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
} }
int sys_msgget (key_t key, int msgflg) int sys_msgget (key_t key, int msgflg)
...@@ -286,7 +286,7 @@ int sys_msgget (key_t key, int msgflg) ...@@ -286,7 +286,7 @@ int sys_msgget (key_t key, int msgflg)
return -EIDRM; return -EIDRM;
if (ipcperms(&msq->msg_perm, msgflg)) if (ipcperms(&msq->msg_perm, msgflg))
return -EACCES; return -EACCES;
return msq->msg_perm.seq * MSGMNI +id; return (unsigned int) msq->msg_perm.seq * MSGMNI + id;
} }
static void freeque (int id) static void freeque (int id)
...@@ -295,7 +295,7 @@ static void freeque (int id) ...@@ -295,7 +295,7 @@ static void freeque (int id)
struct msg *msgp, *msgh; struct msg *msgp, *msgh;
msq->msg_perm.seq++; msq->msg_perm.seq++;
msg_seq++; msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */
msgbytes -= msq->msg_cbytes; msgbytes -= msq->msg_cbytes;
if (id == max_msqid) if (id == max_msqid)
while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED));
...@@ -319,7 +319,8 @@ static void freeque (int id) ...@@ -319,7 +319,8 @@ static void freeque (int id)
int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
{ {
int id, err; int id, err;
struct msqid_ds *msq, tbuf; struct msqid_ds *msq;
struct msqid_ds tbuf;
struct ipc_perm *ipcp; struct ipc_perm *ipcp;
if (msqid < 0 || cmd < 0) if (msqid < 0 || cmd < 0)
...@@ -353,7 +354,7 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) ...@@ -353,7 +354,7 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
case MSG_STAT: case MSG_STAT:
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
err = verify_area (VERIFY_WRITE, buf, sizeof (*msq)); err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
if (err) if (err)
return err; return err;
if (msqid > max_msqid) if (msqid > max_msqid)
...@@ -363,46 +364,62 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) ...@@ -363,46 +364,62 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
return -EINVAL; return -EINVAL;
if (ipcperms (&msq->msg_perm, S_IRUGO)) if (ipcperms (&msq->msg_perm, S_IRUGO))
return -EACCES; return -EACCES;
id = msqid + msq->msg_perm.seq * MSGMNI; id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid;
memcpy_tofs (buf, msq, sizeof(*msq)); tbuf.msg_perm = msq->msg_perm;
tbuf.msg_stime = msq->msg_stime;
tbuf.msg_rtime = msq->msg_rtime;
tbuf.msg_ctime = msq->msg_ctime;
tbuf.msg_cbytes = msq->msg_cbytes;
tbuf.msg_qnum = msq->msg_qnum;
tbuf.msg_qbytes = msq->msg_qbytes;
tbuf.msg_lspid = msq->msg_lspid;
tbuf.msg_lrpid = msq->msg_lrpid;
memcpy_tofs (buf, &tbuf, sizeof(*buf));
return id; return id;
case IPC_SET: case IPC_SET:
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
err = verify_area (VERIFY_READ, buf, sizeof (*buf));
if (err)
return err;
memcpy_fromfs (&tbuf, buf, sizeof (*buf)); memcpy_fromfs (&tbuf, buf, sizeof (*buf));
break; break;
case IPC_STAT: case IPC_STAT:
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
err = verify_area (VERIFY_WRITE, buf, sizeof(*msq)); err = verify_area (VERIFY_WRITE, buf, sizeof(*buf));
if (err) if (err)
return err; return err;
break; break;
} }
id = msqid % MSGMNI; id = (unsigned int) msqid % MSGMNI;
msq = msgque [id]; msq = msgque [id];
if (msq == IPC_UNUSED || msq == IPC_NOID) if (msq == IPC_UNUSED || msq == IPC_NOID)
return -EINVAL; return -EINVAL;
ipcp = &msq->msg_perm; if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI)
if (ipcp->seq != msqid / MSGMNI)
return -EIDRM; return -EIDRM;
ipcp = &msq->msg_perm;
switch (cmd) { switch (cmd) {
case IPC_STAT: case IPC_STAT:
if (ipcperms (ipcp, S_IRUGO)) if (ipcperms (ipcp, S_IRUGO))
return -EACCES; return -EACCES;
memcpy_tofs (buf, msq, sizeof (*msq)); tbuf.msg_perm = msq->msg_perm;
tbuf.msg_stime = msq->msg_stime;
tbuf.msg_rtime = msq->msg_rtime;
tbuf.msg_ctime = msq->msg_ctime;
tbuf.msg_cbytes = msq->msg_cbytes;
tbuf.msg_qnum = msq->msg_qnum;
tbuf.msg_qbytes = msq->msg_qbytes;
tbuf.msg_lspid = msq->msg_lspid;
tbuf.msg_lrpid = msq->msg_lrpid;
memcpy_tofs (buf, &tbuf, sizeof (*buf));
return 0; return 0;
break; case IPC_SET:
case IPC_RMID: case IPC_SET:
if (!suser() && current->euid != ipcp->cuid && if (!suser() && current->euid != ipcp->cuid &&
current->euid != ipcp->uid) current->euid != ipcp->uid)
return -EPERM; return -EPERM;
if (cmd == IPC_RMID) {
freeque (id);
return 0;
}
if (tbuf.msg_qbytes > MSGMNB && !suser()) if (tbuf.msg_qbytes > MSGMNB && !suser())
return -EPERM; return -EPERM;
msq->msg_qbytes = tbuf.msg_qbytes; msq->msg_qbytes = tbuf.msg_qbytes;
...@@ -411,10 +428,14 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) ...@@ -411,10 +428,14 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf)
ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
(S_IRWXUGO & tbuf.msg_perm.mode); (S_IRWXUGO & tbuf.msg_perm.mode);
msq->msg_ctime = CURRENT_TIME; msq->msg_ctime = CURRENT_TIME;
break; return 0;
case IPC_RMID:
if (!suser() && current->euid != ipcp->cuid &&
current->euid != ipcp->uid)
return -EPERM;
freeque (id);
return 0;
default: default:
return -EINVAL; return -EINVAL;
break;
} }
return 0;
} }
...@@ -26,11 +26,11 @@ static unsigned short sem_seq = 0; ...@@ -26,11 +26,11 @@ static unsigned short sem_seq = 0;
void sem_init (void) void sem_init (void)
{ {
int i=0; int i;
sem_lock = NULL; sem_lock = NULL;
used_sems = used_semids = max_semid = sem_seq = 0; used_sems = used_semids = max_semid = sem_seq = 0;
for (i=0; i < SEMMNI; i++) for (i = 0; i < SEMMNI; i++)
semary[i] = (struct semid_ds *) IPC_UNUSED; semary[i] = (struct semid_ds *) IPC_UNUSED;
return; return;
} }
...@@ -40,7 +40,7 @@ static int findkey (key_t key) ...@@ -40,7 +40,7 @@ static int findkey (key_t key)
int id; int id;
struct semid_ds *sma; struct semid_ds *sma;
for (id=0; id <= max_semid; id++) { for (id = 0; id <= max_semid; id++) {
while ((sma = semary[id]) == IPC_NOID) while ((sma = semary[id]) == IPC_NOID)
interruptible_sleep_on (&sem_lock); interruptible_sleep_on (&sem_lock);
if (sma == IPC_UNUSED) if (sma == IPC_UNUSED)
...@@ -62,7 +62,7 @@ static int newary (key_t key, int nsems, int semflg) ...@@ -62,7 +62,7 @@ static int newary (key_t key, int nsems, int semflg)
return -EINVAL; return -EINVAL;
if (used_sems + nsems > SEMMNS) if (used_sems + nsems > SEMMNS)
return -ENOSPC; return -ENOSPC;
for (id=0; id < SEMMNI; id++) for (id = 0; id < SEMMNI; id++)
if (semary[id] == IPC_UNUSED) { if (semary[id] == IPC_UNUSED) {
semary[id] = (struct semid_ds *) IPC_NOID; semary[id] = (struct semid_ds *) IPC_NOID;
goto found; goto found;
...@@ -86,7 +86,7 @@ static int newary (key_t key, int nsems, int semflg) ...@@ -86,7 +86,7 @@ static int newary (key_t key, int nsems, int semflg)
ipcp->key = key; ipcp->key = key;
ipcp->cuid = ipcp->uid = current->euid; ipcp->cuid = ipcp->uid = current->euid;
ipcp->gid = ipcp->cgid = current->egid; ipcp->gid = ipcp->cgid = current->egid;
ipcp->seq = sem_seq; sma->sem_perm.seq = sem_seq;
sma->eventn = sma->eventz = NULL; sma->eventn = sma->eventz = NULL;
sma->sem_nsems = nsems; sma->sem_nsems = nsems;
sma->sem_ctime = CURRENT_TIME; sma->sem_ctime = CURRENT_TIME;
...@@ -96,7 +96,7 @@ static int newary (key_t key, int nsems, int semflg) ...@@ -96,7 +96,7 @@ static int newary (key_t key, int nsems, int semflg)
semary[id] = sma; semary[id] = sma;
if (sem_lock) if (sem_lock)
wake_up (&sem_lock); wake_up (&sem_lock);
return (int) sem_seq * SEMMNI + id; return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
} }
int sys_semget (key_t key, int nsems, int semflg) int sys_semget (key_t key, int nsems, int semflg)
...@@ -120,7 +120,7 @@ int sys_semget (key_t key, int nsems, int semflg) ...@@ -120,7 +120,7 @@ int sys_semget (key_t key, int nsems, int semflg)
return -EINVAL; return -EINVAL;
if (ipcperms(&sma->sem_perm, semflg)) if (ipcperms(&sma->sem_perm, semflg))
return -EACCES; return -EACCES;
return sma->sem_perm.seq*SEMMNI + id; return (unsigned int) sma->sem_perm.seq * SEMMNI + id;
} }
static void freeary (int id) static void freeary (int id)
...@@ -129,13 +129,13 @@ static void freeary (int id) ...@@ -129,13 +129,13 @@ static void freeary (int id)
struct sem_undo *un; struct sem_undo *un;
sma->sem_perm.seq++; sma->sem_perm.seq++;
sem_seq++; sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */
used_sems -= sma->sem_nsems; used_sems -= sma->sem_nsems;
if (id == max_semid) if (id == max_semid)
while (max_semid && (semary[--max_semid] == IPC_UNUSED)); while (max_semid && (semary[--max_semid] == IPC_UNUSED));
semary[id] = (struct semid_ds *) IPC_UNUSED; semary[id] = (struct semid_ds *) IPC_UNUSED;
used_semids--; used_semids--;
for (un=sma->undo; un; un=un->id_next) for (un = sma->undo; un; un = un->id_next)
un->semadj = 0; un->semadj = 0;
while (sma->eventz || sma->eventn) { while (sma->eventz || sma->eventn) {
if (sma->eventz) if (sma->eventz)
...@@ -148,16 +148,19 @@ static void freeary (int id) ...@@ -148,16 +148,19 @@ static void freeary (int id)
return; return;
} }
int sys_semctl (int semid, int semnum, int cmd, void *arg) int sys_semctl (int semid, int semnum, int cmd, union semun arg)
{ {
struct semid_ds *buf = NULL;
struct semid_ds tbuf;
int i, id, val = 0; int i, id, val = 0;
struct semid_ds *sma, *buf = NULL, tbuf; struct semid_ds *sma;
struct ipc_perm *ipcp; struct ipc_perm *ipcp;
struct sem *curr; struct sem *curr;
struct sem_undo *un; struct sem_undo *un;
ushort nsems, *array = NULL; unsigned int nsems;
ushort *array = NULL;
ushort sem_io[SEMMSL]; ushort sem_io[SEMMSL];
if (semid < 0 || semnum < 0 || cmd < 0) if (semid < 0 || semnum < 0 || cmd < 0)
return -EINVAL; return -EINVAL;
...@@ -165,9 +168,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -165,9 +168,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
case IPC_INFO: case IPC_INFO:
case SEM_INFO: case SEM_INFO:
{ {
struct seminfo seminfo, *tmp; struct seminfo seminfo, *tmp = arg.__buf;
if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg)))
return -EFAULT;
seminfo.semmni = SEMMNI; seminfo.semmni = SEMMNI;
seminfo.semmns = SEMMNS; seminfo.semmns = SEMMNS;
seminfo.semmsl = SEMMSL; seminfo.semmsl = SEMMSL;
...@@ -182,7 +183,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -182,7 +183,7 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
seminfo.semusz = used_semids; seminfo.semusz = used_semids;
seminfo.semaem = used_sems; seminfo.semaem = used_sems;
} }
i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo));
if (i) if (i)
return i; return i;
memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo)); memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo));
...@@ -190,9 +191,8 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -190,9 +191,8 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
} }
case SEM_STAT: case SEM_STAT:
if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg))) buf = arg.buf;
return -EFAULT; i = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
i = verify_area (VERIFY_WRITE, buf, sizeof (*sma));
if (i) if (i)
return i; return i;
if (semid > max_semid) if (semid > max_semid)
...@@ -202,18 +202,22 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -202,18 +202,22 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
return -EINVAL; return -EINVAL;
if (ipcperms (&sma->sem_perm, S_IRUGO)) if (ipcperms (&sma->sem_perm, S_IRUGO))
return -EACCES; return -EACCES;
id = semid + sma->sem_perm.seq * SEMMNI; id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid;
memcpy_tofs (buf, sma, sizeof(*sma)); tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
memcpy_tofs (buf, &tbuf, sizeof(*buf));
return id; return id;
} }
id = semid % SEMMNI; id = (unsigned int) semid % SEMMNI;
sma = semary [id]; sma = semary [id];
if (sma == IPC_UNUSED || sma == IPC_NOID) if (sma == IPC_UNUSED || sma == IPC_NOID)
return -EINVAL; return -EINVAL;
ipcp = &sma->sem_perm; ipcp = &sma->sem_perm;
nsems = sma->sem_nsems; nsems = sma->sem_nsems;
if (ipcp->seq != semid / SEMMNI) if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
return -EIDRM; return -EIDRM;
if (semnum >= nsems) if (semnum >= nsems)
return -EINVAL; return -EINVAL;
...@@ -233,17 +237,15 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -233,17 +237,15 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
case GETNCNT: return curr->semncnt; case GETNCNT: return curr->semncnt;
case GETZCNT: return curr->semzcnt; case GETZCNT: return curr->semzcnt;
case GETALL: case GETALL:
if (!arg || ! (array = (ushort *) get_fs_long((int *) arg))) array = arg.array;
return -EFAULT; i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort));
i = verify_area (VERIFY_WRITE, array, nsems*sizeof(short));
if (i) if (i)
return i; return i;
} }
break; break;
case SETVAL: case SETVAL:
if (!arg) val = arg.val;
return -EFAULT; if (val > SEMVMX || val < 0)
if ((val = (int) get_fs_long ((int *) arg)) > SEMVMX || val < 0)
return -ERANGE; return -ERANGE;
break; break;
case IPC_RMID: case IPC_RMID:
...@@ -254,40 +256,37 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -254,40 +256,37 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
} }
return -EPERM; return -EPERM;
case SETALL: /* arg is a pointer to an array of ushort */ case SETALL: /* arg is a pointer to an array of ushort */
if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) ) array = arg.array;
return -EFAULT; if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort))))
if ((i = verify_area (VERIFY_READ, array, sizeof tbuf)))
return i; return i;
memcpy_fromfs (sem_io, array, nsems*sizeof(ushort)); memcpy_fromfs (sem_io, array, nsems*sizeof(ushort));
for (i=0; i< nsems; i++) for (i = 0; i < nsems; i++)
if (sem_io[i] > SEMVMX) if (sem_io[i] > SEMVMX)
return -ERANGE; return -ERANGE;
break; break;
case IPC_STAT: case IPC_STAT:
if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) buf = arg.buf;
return -EFAULT; if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf))))
if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*sma))))
return i; return i;
break; break;
case IPC_SET: case IPC_SET:
if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) buf = arg.buf;
return -EFAULT; if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf))))
if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf)))
return i; return i;
memcpy_fromfs (&tbuf, buf, sizeof tbuf); memcpy_fromfs (&tbuf, buf, sizeof (*buf));
break; break;
} }
if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID) if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID)
return -EIDRM; return -EIDRM;
if (ipcp->seq != semid / SEMMNI) if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
return -EIDRM; return -EIDRM;
switch (cmd) { switch (cmd) {
case GETALL: case GETALL:
if (ipcperms (ipcp, S_IRUGO)) if (ipcperms (ipcp, S_IRUGO))
return -EACCES; return -EACCES;
for (i=0; i< sma->sem_nsems; i++) for (i = 0; i < sma->sem_nsems; i++)
sem_io[i] = sma->sem_base[i].semval; sem_io[i] = sma->sem_base[i].semval;
memcpy_tofs (array, sem_io, nsems*sizeof(ushort)); memcpy_tofs (array, sem_io, nsems*sizeof(ushort));
break; break;
...@@ -318,12 +317,16 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg) ...@@ -318,12 +317,16 @@ int sys_semctl (int semid, int semnum, int cmd, void *arg)
case IPC_STAT: case IPC_STAT:
if (ipcperms (ipcp, S_IRUGO)) if (ipcperms (ipcp, S_IRUGO))
return -EACCES; return -EACCES;
memcpy_tofs (buf, sma, sizeof (*sma)); tbuf.sem_perm = sma->sem_perm;
tbuf.sem_otime = sma->sem_otime;
tbuf.sem_ctime = sma->sem_ctime;
tbuf.sem_nsems = sma->sem_nsems;
memcpy_tofs (buf, &tbuf, sizeof(*buf));
break; break;
case SETALL: case SETALL:
if (ipcperms (ipcp, S_IWUGO)) if (ipcperms (ipcp, S_IWUGO))
return -EACCES; return -EACCES;
for (i=0; i<nsems; i++) for (i = 0; i < nsems; i++)
sma->sem_base[i].semval = sem_io[i]; sma->sem_base[i].semval = sem_io[i];
for (un = sma->undo; un; un = un->id_next) for (un = sma->undo; un; un = un->id_next)
un->semadj = 0; un->semadj = 0;
...@@ -354,11 +357,13 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -354,11 +357,13 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
return -E2BIG; return -E2BIG;
if (!tsops) if (!tsops)
return -EFAULT; return -EFAULT;
if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops))))
return i;
memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops)); memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops));
id = semid % SEMMNI; id = (unsigned int) semid % SEMMNI;
if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID)
return -EINVAL; return -EINVAL;
for (i=0; i<nsops; i++) { for (i = 0; i < nsops; i++) {
sop = &sops[i]; sop = &sops[i];
if (sop->sem_num > sma->sem_nsems) if (sop->sem_num > sma->sem_nsems)
return -EFBIG; return -EFBIG;
...@@ -376,10 +381,10 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -376,10 +381,10 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
* ensure every sop with undo gets an undo structure * ensure every sop with undo gets an undo structure
*/ */
if (undos) { if (undos) {
for (i=0; i<nsops; i++) { for (i = 0; i < nsops; i++) {
if (!(sops[i].sem_flg & SEM_UNDO)) if (!(sops[i].sem_flg & SEM_UNDO))
continue; continue;
for (un = current->semun; un; un = un->proc_next) for (un = current->semundo; un; un = un->proc_next)
if ((un->semid == semid) && if ((un->semid == semid) &&
(un->sem_num == sops[i].sem_num)) (un->sem_num == sops[i].sem_num))
break; break;
...@@ -392,17 +397,17 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -392,17 +397,17 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
un->semid = semid; un->semid = semid;
un->semadj = 0; un->semadj = 0;
un->sem_num = sops[i].sem_num; un->sem_num = sops[i].sem_num;
un->proc_next = current->semun; un->proc_next = current->semundo;
current->semun = un; current->semundo = un;
un->id_next = sma->undo; un->id_next = sma->undo;
sma->undo = un; sma->undo = un;
} }
} }
slept: slept:
if (sma->sem_perm.seq != semid / SEMMNI) if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
return -EIDRM; return -EIDRM;
for (i=0; i<nsops; i++) { for (i = 0; i < nsops; i++) {
sop = &sops[i]; sop = &sops[i];
curr = &sma->sem_base[sop->sem_num]; curr = &sma->sem_base[sop->sem_num];
if (sop->sem_op + curr->semval > SEMVMX) if (sop->sem_op + curr->semval > SEMVMX)
...@@ -429,7 +434,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -429,7 +434,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
} }
} }
for (i=0; i<nsops; i++) { for (i = 0; i < nsops; i++) {
sop = &sops[i]; sop = &sops[i];
curr = &sma->sem_base[sop->sem_num]; curr = &sma->sem_base[sop->sem_num];
curr->sempid = current->pid; curr->sempid = current->pid;
...@@ -437,7 +442,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) ...@@ -437,7 +442,7 @@ int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
semzcnt++; semzcnt++;
if (!(sop->sem_flg & SEM_UNDO)) if (!(sop->sem_flg & SEM_UNDO))
continue; continue;
for (un = current->semun; un; un = un->proc_next) for (un = current->semundo; un; un = un->proc_next)
if ((un->semid == semid) && if ((un->semid == semid) &&
(un->sem_num == sop->sem_num)) (un->sem_num == sop->sem_num))
break; break;
...@@ -466,11 +471,11 @@ void sem_exit (void) ...@@ -466,11 +471,11 @@ void sem_exit (void)
struct semid_ds *sma; struct semid_ds *sma;
struct sem *sem = NULL; struct sem *sem = NULL;
for (up = &current->semun; (u = *up); *up = u->proc_next, kfree(u)) { for (up = &current->semundo; (u = *up); *up = u->proc_next, kfree(u)) {
sma = semary[u->semid % SEMMNI]; sma = semary[(unsigned int) u->semid % SEMMNI];
if (sma == IPC_UNUSED || sma == IPC_NOID) if (sma == IPC_UNUSED || sma == IPC_NOID)
continue; continue;
if (sma->sem_perm.seq != u->semid / SEMMNI) if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI)
continue; continue;
for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
if (u == un) if (u == un)
...@@ -483,7 +488,7 @@ void sem_exit (void) ...@@ -483,7 +488,7 @@ void sem_exit (void)
if (!un->semadj) if (!un->semadj)
continue; continue;
while (1) { while (1) {
if (sma->sem_perm.seq != un->semid / SEMMNI) if (sma->sem_perm.seq != (unsigned int) un->semid / SEMMNI)
break; break;
sem = &sma->sem_base[un->sem_num]; sem = &sma->sem_base[un->sem_num];
if (sem->semval + un->semadj >= 0) { if (sem->semval + un->semadj >= 0) {
...@@ -503,6 +508,6 @@ void sem_exit (void) ...@@ -503,6 +508,6 @@ void sem_exit (void)
sem->semncnt--; sem->semncnt--;
} }
} }
current->semun = NULL; current->semundo = NULL;
return; return;
} }
/* /*
* linux/ipc/shm.c * linux/ipc/shm.c
* Copyright (C) 1992, 1993 Krishna Balasubramanian * Copyright (C) 1992, 1993 Krishna Balasubramanian
* Many improvements/fixes by Bruno Haible. * Many improvements/fixes by Bruno Haible.
* assume user segments start at 0x0
*/ */
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/ipc.h> #include <linux/ipc.h>
#include <linux/shm.h> #include <linux/shm.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/malloc.h> #include <linux/malloc.h>
extern int ipcperms (struct ipc_perm *ipcp, short semflg); extern int ipcperms (struct ipc_perm *ipcp, short shmflg);
extern unsigned int get_swap_page(void); extern unsigned int get_swap_page (void);
static int findkey (key_t key); static int findkey (key_t key);
static int newseg (key_t key, int shmflg, int size); static int newseg (key_t key, int shmflg, int size);
static int shm_map (struct shm_desc *shmd, int remap); static int shm_map (struct shm_desc *shmd, int remap);
static void killseg (int id); static void killseg (int id);
static unsigned long shm_swap_in(struct vm_area_struct *, unsigned long); static unsigned long shm_swap_in (struct vm_area_struct *, unsigned long);
static int shm_tot = 0; /* total number of shared memory pages */ static int shm_tot = 0; /* total number of shared memory pages */
static int shm_rss = 0; /* number of shared memory pages that are in memory */ static int shm_rss = 0; /* number of shared memory pages that are in memory */
static int shm_swp = 0; /* number of shared memory pages that are in swap */ static int shm_swp = 0; /* number of shared memory pages that are in swap */
static int max_shmid = 0; /* every used id is <= max_shmid */ static int max_shmid = 0; /* every used id is <= max_shmid */
static struct wait_queue *shm_lock = NULL; static struct wait_queue *shm_lock = NULL; /* calling findkey() may need to wait */
static struct shmid_ds *shm_segs[SHMMNI]; static struct shmid_ds *shm_segs[SHMMNI];
static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */ static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */
...@@ -38,31 +37,31 @@ static ulong used_segs = 0; ...@@ -38,31 +37,31 @@ static ulong used_segs = 0;
void shm_init (void) void shm_init (void)
{ {
int id; int id;
for (id = 0; id < SHMMNI; id++) for (id = 0; id < SHMMNI; id++)
shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0; shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0;
shm_lock = NULL; shm_lock = NULL;
return; return;
} }
static int findkey (key_t key) static int findkey (key_t key)
{ {
int id; int id;
struct shmid_ds *shp; struct shmid_ds *shp;
for (id=0; id <= max_shmid; id++) { for (id = 0; id <= max_shmid; id++) {
while ((shp = shm_segs[id]) == IPC_NOID) while ((shp = shm_segs[id]) == IPC_NOID)
sleep_on (&shm_lock); sleep_on (&shm_lock);
if (shp == IPC_UNUSED) if (shp == IPC_UNUSED)
continue; continue;
if (key == shp->shm_perm.key) if (key == shp->shm_perm.key)
return id; return id;
} }
return -1; return -1;
} }
/* /*
* allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID. * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID.
*/ */
static int newseg (key_t key, int shmflg, int size) static int newseg (key_t key, int shmflg, int size)
...@@ -75,7 +74,7 @@ static int newseg (key_t key, int shmflg, int size) ...@@ -75,7 +74,7 @@ static int newseg (key_t key, int shmflg, int size)
return -EINVAL; return -EINVAL;
if (shm_tot + numpages >= SHMALL) if (shm_tot + numpages >= SHMALL)
return -ENOSPC; return -ENOSPC;
for (id=0; id < SHMMNI; id++) for (id = 0; id < SHMMNI; id++)
if (shm_segs[id] == IPC_UNUSED) { if (shm_segs[id] == IPC_UNUSED) {
shm_segs[id] = (struct shmid_ds *) IPC_NOID; shm_segs[id] = (struct shmid_ds *) IPC_NOID;
goto found; goto found;
...@@ -100,7 +99,7 @@ static int newseg (key_t key, int shmflg, int size) ...@@ -100,7 +99,7 @@ static int newseg (key_t key, int shmflg, int size)
return -ENOMEM; return -ENOMEM;
} }
for (i=0; i< numpages; shp->shm_pages[i++] = 0); for (i = 0; i < numpages; shp->shm_pages[i++] = 0);
shm_tot += numpages; shm_tot += numpages;
shp->shm_perm.key = key; shp->shm_perm.key = key;
shp->shm_perm.mode = (shmflg & S_IRWXUGO); shp->shm_perm.mode = (shmflg & S_IRWXUGO);
...@@ -121,23 +120,23 @@ static int newseg (key_t key, int shmflg, int size) ...@@ -121,23 +120,23 @@ static int newseg (key_t key, int shmflg, int size)
used_segs++; used_segs++;
if (shm_lock) if (shm_lock)
wake_up (&shm_lock); wake_up (&shm_lock);
return id + (int)shm_seq*SHMMNI; return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
} }
int sys_shmget (key_t key, int size, int shmflg) int sys_shmget (key_t key, int size, int shmflg)
{ {
struct shmid_ds *shp; struct shmid_ds *shp;
int id = 0; int id = 0;
if (size < 0 || size > SHMMAX) if (size < 0 || size > SHMMAX)
return -EINVAL; return -EINVAL;
if (key == IPC_PRIVATE) if (key == IPC_PRIVATE)
return newseg(key, shmflg, size); return newseg(key, shmflg, size);
if ((id = findkey (key)) == -1) { if ((id = findkey (key)) == -1) {
if (!(shmflg & IPC_CREAT)) if (!(shmflg & IPC_CREAT))
return -ENOENT; return -ENOENT;
return newseg(key, shmflg, size); return newseg(key, shmflg, size);
} }
if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
return -EEXIST; return -EEXIST;
shp = shm_segs[id]; shp = shm_segs[id];
...@@ -147,10 +146,10 @@ int sys_shmget (key_t key, int size, int shmflg) ...@@ -147,10 +146,10 @@ int sys_shmget (key_t key, int size, int shmflg)
return -EINVAL; return -EINVAL;
if (ipcperms (&shp->shm_perm, shmflg)) if (ipcperms (&shp->shm_perm, shmflg))
return -EACCES; return -EACCES;
return shp->shm_perm.seq*SHMMNI + id; return (unsigned int) shp->shm_perm.seq * SHMMNI + id;
} }
/* /*
* Only called after testing nattch and SHM_DEST. * Only called after testing nattch and SHM_DEST.
* Here pages, pgtable and shmid_ds are freed. * Here pages, pgtable and shmid_ds are freed.
*/ */
...@@ -166,20 +165,20 @@ static void killseg (int id) ...@@ -166,20 +165,20 @@ static void killseg (int id)
return; return;
} }
shp->shm_perm.seq++; /* for shmat */ shp->shm_perm.seq++; /* for shmat */
numpages = shp->shm_npages; shm_seq = (shm_seq+1) % ((unsigned)(1<<31)/SHMMNI); /* increment, but avoid overflow */
shm_seq++;
shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; shm_segs[id] = (struct shmid_ds *) IPC_UNUSED;
used_segs--; used_segs--;
if (id == max_shmid) if (id == max_shmid)
while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED)); while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED));
if (!shp->shm_pages) { if (!shp->shm_pages) {
printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id); printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id);
return; return;
} }
for (i=0; i< numpages ; i++) { numpages = shp->shm_npages;
for (i = 0; i < numpages ; i++) {
if (!(page = shp->shm_pages[i])) if (!(page = shp->shm_pages[i]))
continue; continue;
if (page & 1) { if (page & PAGE_PRESENT) {
free_page (page & PAGE_MASK); free_page (page & PAGE_MASK);
shm_rss--; shm_rss--;
} else { } else {
...@@ -195,10 +194,11 @@ static void killseg (int id) ...@@ -195,10 +194,11 @@ static void killseg (int id)
int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
{ {
struct shmid_ds *shp, tbuf; struct shmid_ds tbuf;
struct shmid_ds *shp;
struct ipc_perm *ipcp; struct ipc_perm *ipcp;
int id, err; int id, err;
if (cmd < 0 || shmid < 0) if (cmd < 0 || shmid < 0)
return -EINVAL; return -EINVAL;
if (cmd == IPC_SET) { if (cmd == IPC_SET) {
...@@ -211,7 +211,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -211,7 +211,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
} }
switch (cmd) { /* replace with proc interface ? */ switch (cmd) { /* replace with proc interface ? */
case IPC_INFO: case IPC_INFO:
{ {
struct shminfo shminfo; struct shminfo shminfo;
if (!buf) if (!buf)
...@@ -227,15 +227,15 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -227,15 +227,15 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
memcpy_tofs (buf, &shminfo, sizeof(struct shminfo)); memcpy_tofs (buf, &shminfo, sizeof(struct shminfo));
return max_shmid; return max_shmid;
} }
case SHM_INFO: case SHM_INFO:
{ {
struct shm_info shm_info; struct shm_info shm_info;
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info)); err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info));
if (err) if (err)
return err; return err;
shm_info.used_ids = used_segs; shm_info.used_ids = used_segs;
shm_info.shm_rss = shm_rss; shm_info.shm_rss = shm_rss;
shm_info.shm_tot = shm_tot; shm_info.shm_tot = shm_tot;
shm_info.shm_swp = shm_swp; shm_info.shm_swp = shm_swp;
...@@ -247,7 +247,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -247,7 +247,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
case SHM_STAT: case SHM_STAT:
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
err = verify_area (VERIFY_WRITE, buf, sizeof (*shp)); err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
if (err) if (err)
return err; return err;
if (shmid > max_shmid) if (shmid > max_shmid)
...@@ -257,18 +257,26 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -257,18 +257,26 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
return -EINVAL; return -EINVAL;
if (ipcperms (&shp->shm_perm, S_IRUGO)) if (ipcperms (&shp->shm_perm, S_IRUGO))
return -EACCES; return -EACCES;
id = shmid + shp->shm_perm.seq * SHMMNI; id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid;
memcpy_tofs (buf, shp, sizeof(*shp)); tbuf.shm_perm = shp->shm_perm;
tbuf.shm_segsz = shp->shm_segsz;
tbuf.shm_atime = shp->shm_atime;
tbuf.shm_dtime = shp->shm_dtime;
tbuf.shm_ctime = shp->shm_ctime;
tbuf.shm_cpid = shp->shm_cpid;
tbuf.shm_lpid = shp->shm_lpid;
tbuf.shm_nattch = shp->shm_nattch;
memcpy_tofs (buf, &tbuf, sizeof(*buf));
return id; return id;
} }
shp = shm_segs[id = shmid % SHMMNI]; shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
if (shp == IPC_UNUSED || shp == IPC_NOID) if (shp == IPC_UNUSED || shp == IPC_NOID)
return -EINVAL; return -EINVAL;
ipcp = &shp->shm_perm; if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
if (ipcp->seq != shmid / SHMMNI)
return -EIDRM; return -EIDRM;
ipcp = &shp->shm_perm;
switch (cmd) { switch (cmd) {
case SHM_UNLOCK: case SHM_UNLOCK:
if (!suser()) if (!suser())
...@@ -292,10 +300,18 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -292,10 +300,18 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
return -EACCES; return -EACCES;
if (!buf) if (!buf)
return -EFAULT; return -EFAULT;
err = verify_area (VERIFY_WRITE, buf, sizeof (*shp)); err = verify_area (VERIFY_WRITE, buf, sizeof (*buf));
if (err) if (err)
return err; return err;
memcpy_tofs (buf, shp, sizeof(*shp)); tbuf.shm_perm = shp->shm_perm;
tbuf.shm_segsz = shp->shm_segsz;
tbuf.shm_atime = shp->shm_atime;
tbuf.shm_dtime = shp->shm_dtime;
tbuf.shm_ctime = shp->shm_ctime;
tbuf.shm_cpid = shp->shm_cpid;
tbuf.shm_lpid = shp->shm_lpid;
tbuf.shm_nattch = shp->shm_nattch;
memcpy_tofs (buf, &tbuf, sizeof(*buf));
break; break;
case IPC_SET: case IPC_SET:
if (suser() || current->euid == shp->shm_perm.uid || if (suser() || current->euid == shp->shm_perm.uid ||
...@@ -312,7 +328,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) ...@@ -312,7 +328,7 @@ int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
if (suser() || current->euid == shp->shm_perm.uid || if (suser() || current->euid == shp->shm_perm.uid ||
current->euid == shp->shm_perm.cuid) { current->euid == shp->shm_perm.cuid) {
shp->shm_perm.mode |= SHM_DEST; shp->shm_perm.mode |= SHM_DEST;
if (shp->shm_nattch <= 0) if (shp->shm_nattch <= 0)
killseg (id); killseg (id);
break; break;
} }
...@@ -334,9 +350,9 @@ static int shm_map (struct shm_desc *shmd, int remap) ...@@ -334,9 +350,9 @@ static int shm_map (struct shm_desc *shmd, int remap)
unsigned long *page_table; unsigned long *page_table;
unsigned long tmp, shm_sgn; unsigned long tmp, shm_sgn;
unsigned long page_dir = shmd->task->tss.cr3; unsigned long page_dir = shmd->task->tss.cr3;
/* check that the range is unmapped and has page_tables */ /* check that the range is unmapped and has page_tables */
for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) { for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) {
page_table = PAGE_DIR_OFFSET(page_dir,tmp); page_table = PAGE_DIR_OFFSET(page_dir,tmp);
if (*page_table & PAGE_PRESENT) { if (*page_table & PAGE_PRESENT) {
page_table = (ulong *) (PAGE_MASK & *page_table); page_table = (ulong *) (PAGE_MASK & *page_table);
...@@ -353,10 +369,10 @@ static int shm_map (struct shm_desc *shmd, int remap) ...@@ -353,10 +369,10 @@ static int shm_map (struct shm_desc *shmd, int remap)
invalid++; invalid++;
} }
continue; continue;
} }
{ {
unsigned long new_pt; unsigned long new_pt;
if(!(new_pt = get_free_page(GFP_KERNEL))) /* clearing needed? SRB. */ if (!(new_pt = get_free_page(GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
*page_table = new_pt | PAGE_TABLE; *page_table = new_pt | PAGE_TABLE;
tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE); tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE);
...@@ -366,8 +382,8 @@ static int shm_map (struct shm_desc *shmd, int remap) ...@@ -366,8 +382,8 @@ static int shm_map (struct shm_desc *shmd, int remap)
/* map page range */ /* map page range */
shm_sgn = shmd->shm_sgn; shm_sgn = shmd->shm_sgn;
for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE,
shm_sgn += (1 << SHM_IDX_SHIFT)) { shm_sgn += (1 << SHM_IDX_SHIFT)) {
page_table = PAGE_DIR_OFFSET(page_dir,tmp); page_table = PAGE_DIR_OFFSET(page_dir,tmp);
page_table = (ulong *) (PAGE_MASK & *page_table); page_table = (ulong *) (PAGE_MASK & *page_table);
page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
...@@ -404,7 +420,7 @@ static int add_vm_area(unsigned long addr, unsigned long len, int readonly) ...@@ -404,7 +420,7 @@ static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
vma->vm_task = current; vma->vm_task = current;
vma->vm_start = addr; vma->vm_start = addr;
vma->vm_end = addr + len; vma->vm_end = addr + len;
vma->vm_flags = VM_SHM | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC; vma->vm_flags = VM_SHM | VM_SHARED | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC;
if (readonly) if (readonly)
vma->vm_page_prot = PAGE_READONLY; vma->vm_page_prot = PAGE_READONLY;
else { else {
...@@ -420,10 +436,9 @@ static int add_vm_area(unsigned long addr, unsigned long len, int readonly) ...@@ -420,10 +436,9 @@ static int add_vm_area(unsigned long addr, unsigned long len, int readonly)
return 0; return 0;
} }
/* /*
* Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
* raddr is needed to return addresses above 2Gig. * raddr is needed to return addresses above 2Gig.
* Specific attaches are allowed over the executable....
*/ */
int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
{ {
...@@ -432,17 +447,17 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -432,17 +447,17 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
int err; int err;
unsigned int id; unsigned int id;
unsigned long addr; unsigned long addr;
if (shmid < 0) if (shmid < 0)
return -EINVAL; return -EINVAL;
if (raddr) { if (raddr) {
err = verify_area(VERIFY_WRITE, raddr, sizeof(long)); err = verify_area(VERIFY_WRITE, raddr, sizeof(ulong));
if (err) if (err)
return err; return err;
} }
shp = shm_segs[id = shmid % SHMMNI]; shp = shm_segs[id = (unsigned int) shmid % SHMMNI];
if (shp == IPC_UNUSED || shp == IPC_NOID) if (shp == IPC_UNUSED || shp == IPC_NOID)
return -EINVAL; return -EINVAL;
...@@ -450,7 +465,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -450,7 +465,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
if (shmflg & SHM_REMAP) if (shmflg & SHM_REMAP)
return -EINVAL; return -EINVAL;
/* set addr below all current unspecified attaches */ /* set addr below all current unspecified attaches */
addr = SHM_RANGE_END; addr = SHM_RANGE_END;
for (shmd = current->shm; shmd; shmd = shmd->task_next) { for (shmd = current->shm; shmd; shmd = shmd->task_next) {
if (shmd->start < SHM_RANGE_START) if (shmd->start < SHM_RANGE_START)
continue; continue;
...@@ -459,7 +474,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -459,7 +474,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
} }
addr = (addr - shp->shm_segsz) & PAGE_MASK; addr = (addr - shp->shm_segsz) & PAGE_MASK;
} else if (addr & (SHMLBA-1)) { } else if (addr & (SHMLBA-1)) {
if (shmflg & SHM_RND) if (shmflg & SHM_RND)
addr &= ~(SHMLBA-1); /* round down */ addr &= ~(SHMLBA-1); /* round down */
else else
return -EINVAL; return -EINVAL;
...@@ -470,26 +485,26 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -470,26 +485,26 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
for (shmd = current->shm; shmd; shmd = shmd->task_next) { for (shmd = current->shm; shmd; shmd = shmd->task_next) {
if (addr >= shmd->start && addr < shmd->end) if (addr >= shmd->start && addr < shmd->end)
return -EINVAL; return -EINVAL;
if (addr + shp->shm_segsz >= shmd->start && if (addr + shp->shm_segsz >= shmd->start &&
addr + shp->shm_segsz < shmd->end) addr + shp->shm_segsz < shmd->end)
return -EINVAL; return -EINVAL;
} }
if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO)) if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO))
return -EACCES; return -EACCES;
if (shp->shm_perm.seq != shmid / SHMMNI) if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)
return -EIDRM; return -EIDRM;
shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL); shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL);
if (!shmd) if (!shmd)
return -ENOMEM; return -ENOMEM;
if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) { if ((shp != shm_segs[id]) || (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI)) {
kfree(shmd); kfree(shmd);
return -EIDRM; return -EIDRM;
} }
shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) | shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) |
(shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0); (shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0);
shmd->start = addr; shmd->start = addr;
shmd->end = addr + shp->shm_npages * PAGE_SIZE; shmd->end = addr + shp->shm_npages * PAGE_SIZE;
shmd->task = current; shmd->task = current;
...@@ -506,7 +521,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -506,7 +521,7 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
kfree(shmd); kfree(shmd);
return err; return err;
} }
shmd->task_next = current->shm; shmd->task_next = current->shm;
current->shm = shmd; current->shm = shmd;
shmd->seg_next = shp->attaches; shmd->seg_next = shp->attaches;
...@@ -526,28 +541,28 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) ...@@ -526,28 +541,28 @@ int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
*/ */
static void detach (struct shm_desc **shmdp) static void detach (struct shm_desc **shmdp)
{ {
struct shm_desc *shmd = *shmdp; struct shm_desc *shmd = *shmdp;
struct shmid_ds *shp; struct shmid_ds *shp;
int id; int id;
id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK; id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK;
shp = shm_segs[id]; shp = shm_segs[id];
*shmdp = shmd->task_next; *shmdp = shmd->task_next;
for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next) for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next)
if (*shmdp == shmd) { if (*shmdp == shmd) {
*shmdp = shmd->seg_next; *shmdp = shmd->seg_next;
goto found; goto found;
} }
printk("detach: shm segment (id=%d) attach list inconsistent\n",id); printk("detach: shm segment (id=%d) attach list inconsistent\n",id);
found: found:
do_munmap(shmd->start, shp->shm_segsz); do_munmap(shmd->start, shp->shm_segsz);
kfree(shmd); kfree(shmd);
shp->shm_lpid = current->pid; shp->shm_lpid = current->pid;
shp->shm_dtime = CURRENT_TIME; shp->shm_dtime = CURRENT_TIME;
if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST) if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST)
killseg (id); /* sleeps */ killseg (id); /* sleeps */
return; return;
} }
/* /*
...@@ -556,9 +571,9 @@ static void detach (struct shm_desc **shmdp) ...@@ -556,9 +571,9 @@ static void detach (struct shm_desc **shmdp)
*/ */
int sys_shmdt (char *shmaddr) int sys_shmdt (char *shmaddr)
{ {
struct shm_desc *shmd, **shmdp; struct shm_desc *shmd, **shmdp;
for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { for (shmdp = &current->shm; (shmd = *shmdp); shmdp=&shmd->task_next) {
if (shmd->start == (ulong) shmaddr) { if (shmd->start == (ulong) shmaddr) {
detach (shmdp); detach (shmdp);
return 0; return 0;
...@@ -567,17 +582,17 @@ int sys_shmdt (char *shmaddr) ...@@ -567,17 +582,17 @@ int sys_shmdt (char *shmaddr)
return -EINVAL; return -EINVAL;
} }
/* /*
* detach all attached segments. * detach all attached segments.
*/ */
void shm_exit (void) void shm_exit (void)
{ {
while (current->shm) while (current->shm)
detach(&current->shm); detach(&current->shm);
return; return;
} }
/* /*
* copy the parent shm descriptors and update nattch * copy the parent shm descriptors and update nattch
* parent is stuck in fork so an attach on each segment is assured. * parent is stuck in fork so an attach on each segment is assured.
* copy_page_tables does the mapping. * copy_page_tables does the mapping.
...@@ -588,17 +603,17 @@ int shm_fork (struct task_struct *p1, struct task_struct *p2) ...@@ -588,17 +603,17 @@ int shm_fork (struct task_struct *p1, struct task_struct *p2)
struct shmid_ds *shp; struct shmid_ds *shp;
int id; int id;
p2->semun = NULL; p2->semundo = NULL;
p2->shm = NULL; p2->shm = NULL;
if (!p1->shm) if (!p1->shm)
return 0; return 0;
for (shmd = p1->shm; shmd; shmd = shmd->task_next) { for (shmd = p1->shm; shmd; shmd = shmd->task_next) {
tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL); tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp) { if (!tmp) {
while (new_desc) { while (new_desc) {
tmp = new_desc->task_next; tmp = new_desc->task_next;
kfree(new_desc); kfree(new_desc);
new_desc = tmp; new_desc = tmp;
} }
free_page_tables (p2); free_page_tables (p2);
return -ENOMEM; return -ENOMEM;
...@@ -670,7 +685,7 @@ static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code ...@@ -670,7 +685,7 @@ static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code
} }
shm_rss++; shm_rss++;
shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY); shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY);
} else } else
--current->mm->maj_flt; /* was incremented in do_no_page */ --current->mm->maj_flt; /* was incremented in do_no_page */
done: done:
...@@ -683,7 +698,7 @@ static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code ...@@ -683,7 +698,7 @@ static unsigned long shm_swap_in(struct vm_area_struct * vma, unsigned long code
} }
/* /*
* Goes through counter = (shm_rss << prio) present shm pages. * Goes through counter = (shm_rss << prio) present shm pages.
*/ */
static unsigned long swap_id = 0; /* currently being swapped */ static unsigned long swap_id = 0; /* currently being swapped */
static unsigned long swap_idx = 0; /* next to swap */ static unsigned long swap_idx = 0; /* next to swap */
...@@ -704,7 +719,7 @@ int shm_swap (int prio) ...@@ -704,7 +719,7 @@ int shm_swap (int prio)
check_id: check_id:
shp = shm_segs[swap_id]; shp = shm_segs[swap_id];
if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) { if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) {
swap_idx = 0; swap_idx = 0;
if (++swap_id > max_shmid) if (++swap_id > max_shmid)
swap_id = 0; swap_id = 0;
goto check_id; goto check_id;
...@@ -712,8 +727,8 @@ int shm_swap (int prio) ...@@ -712,8 +727,8 @@ int shm_swap (int prio)
id = swap_id; id = swap_id;
check_table: check_table:
idx = swap_idx++; idx = swap_idx++;
if (idx >= shp->shm_npages) { if (idx >= shp->shm_npages) {
swap_idx = 0; swap_idx = 0;
if (++swap_id > max_shmid) if (++swap_id > max_shmid)
swap_id = 0; swap_id = 0;
...@@ -743,12 +758,12 @@ int shm_swap (int prio) ...@@ -743,12 +758,12 @@ int shm_swap (int prio)
continue; continue;
} }
pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp); pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp);
if (!(*pte & 1)) { if (!(*pte & PAGE_PRESENT)) {
printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n",
id, shmd->start, idx); id, shmd->start, idx);
*pte = 0; *pte = 0;
continue; continue;
} }
pte = (ulong *) (PAGE_MASK & *pte); pte = (ulong *) (PAGE_MASK & *pte);
pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1)); pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1));
tmp = *pte; tmp = *pte;
...@@ -756,7 +771,7 @@ int shm_swap (int prio) ...@@ -756,7 +771,7 @@ int shm_swap (int prio)
continue; continue;
if (tmp & PAGE_ACCESSED) { if (tmp & PAGE_ACCESSED) {
*pte &= ~PAGE_ACCESSED; *pte &= ~PAGE_ACCESSED;
continue; continue;
} }
tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT; tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT;
*pte = tmp; *pte = tmp;
...@@ -765,7 +780,7 @@ int shm_swap (int prio) ...@@ -765,7 +780,7 @@ int shm_swap (int prio)
invalid++; invalid++;
} }
if (mem_map[MAP_NR(page)] != 1) if (mem_map[MAP_NR(page)] != 1)
goto check_table; goto check_table;
page &= PAGE_MASK; page &= PAGE_MASK;
shp->shm_pages[idx] = swap_nr; shp->shm_pages[idx] = swap_nr;
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
#include <linux/stat.h> #include <linux/stat.h>
void ipc_init (void); void ipc_init (void);
asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr); asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr);
#ifdef CONFIG_SYSVIPC #ifdef CONFIG_SYSVIPC
...@@ -21,16 +21,16 @@ int ipcperms (struct ipc_perm *ipcp, short flag); ...@@ -21,16 +21,16 @@ int ipcperms (struct ipc_perm *ipcp, short flag);
extern void sem_init (void), msg_init (void), shm_init (void); extern void sem_init (void), msg_init (void), shm_init (void);
extern int sys_semget (key_t key, int nsems, int semflg); extern int sys_semget (key_t key, int nsems, int semflg);
extern int sys_semop (int semid, struct sembuf *sops, unsigned nsops); extern int sys_semop (int semid, struct sembuf *sops, unsigned nsops);
extern int sys_semctl (int semid, int semnum, int cmd, void *arg); extern int sys_semctl (int semid, int semnum, int cmd, union semun arg);
extern int sys_msgget (key_t key, int msgflg); extern int sys_msgget (key_t key, int msgflg);
extern int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg); extern int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg);
extern int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, extern int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp,
int msgflg); int msgflg);
extern int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); extern int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
extern int sys_shmget (key_t key, int size, int flag); extern int sys_shmget (key_t key, int size, int flag);
extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr); extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr);
extern int sys_shmdt (char *shmaddr); extern int sys_shmdt (char *shmaddr);
extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
void ipc_init (void) void ipc_init (void)
{ {
...@@ -71,8 +71,16 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) ...@@ -71,8 +71,16 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
return sys_semop (first, (struct sembuf *)ptr, second); return sys_semop (first, (struct sembuf *)ptr, second);
case SEMGET: case SEMGET:
return sys_semget (first, second, third); return sys_semget (first, second, third);
case SEMCTL: case SEMCTL: {
return sys_semctl (first, second, third, ptr); union semun fourth;
int err;
if (!ptr)
return -EINVAL;
if ((err = verify_area (VERIFY_READ, ptr, sizeof(long))))
return err;
fourth.__pad = (void *) get_fs_long(ptr);
return sys_semctl (first, second, third, fourth);
}
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -82,10 +90,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) ...@@ -82,10 +90,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
return sys_msgsnd (first, (struct msgbuf *) ptr, return sys_msgsnd (first, (struct msgbuf *) ptr,
second, third); second, third);
case MSGRCV: { case MSGRCV: {
struct ipc_kludge tmp; struct ipc_kludge tmp;
int err;
if (!ptr) if (!ptr)
return -EINVAL; return -EINVAL;
memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, if ((err = verify_area (VERIFY_READ, ptr, sizeof(tmp))))
return err;
memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr,
sizeof (tmp)); sizeof (tmp));
return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp,
third); third);
...@@ -93,14 +104,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) ...@@ -93,14 +104,13 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
case MSGGET: case MSGGET:
return sys_msgget ((key_t) first, second); return sys_msgget ((key_t) first, second);
case MSGCTL: case MSGCTL:
return sys_msgctl (first, second, return sys_msgctl (first, second, (struct msqid_ds *) ptr);
(struct msqid_ds *) ptr);
default: default:
return -EINVAL; return -EINVAL;
} }
if (call <= SHMCTL) if (call <= SHMCTL)
switch (call) { switch (call) {
case SHMAT: /* returning shmaddr > 2G will screw up */ case SHMAT:
return sys_shmat (first, (char *) ptr, second, return sys_shmat (first, (char *) ptr, second,
(ulong *) third); (ulong *) third);
case SHMDT: case SHMDT:
...@@ -108,8 +118,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) ...@@ -108,8 +118,7 @@ asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr)
case SHMGET: case SHMGET:
return sys_shmget (first, second, third); return sys_shmget (first, second, third);
case SHMCTL: case SHMCTL:
return sys_shmctl (first, second, return sys_shmctl (first, second, (struct shmid_ds *) ptr);
(struct shmid_ds *) ptr);
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -411,7 +411,7 @@ NORET_TYPE void do_exit(long code) ...@@ -411,7 +411,7 @@ NORET_TYPE void do_exit(long code)
intr_count = 0; intr_count = 0;
} }
fake_volatile: fake_volatile:
if (current->semun) if (current->semundo)
sem_exit(); sem_exit();
if (current->shm) if (current->shm)
shm_exit(); shm_exit();
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/locks.h> #include <linux/locks.h>
#include <linux/string.h>
#ifdef CONFIG_INET #ifdef CONFIG_INET
#include <linux/net.h> #include <linux/net.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
...@@ -46,7 +47,6 @@ extern void (*do_floppy)(void); ...@@ -46,7 +47,6 @@ extern void (*do_floppy)(void);
#endif #endif
extern int sys_tz; extern int sys_tz;
extern int ___strtok;
extern int request_dma(unsigned int dmanr, char * deviceID); extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr); extern void free_dma(unsigned int dmanr);
...@@ -92,6 +92,13 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */ ...@@ -92,6 +92,13 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(open_namei), X(open_namei),
X(inode_setattr), X(inode_setattr),
X(inode_change_ok), X(inode_change_ok),
X(generic_mmap),
X(set_blocksize),
X(getblk),
X(bread),
X(brelse),
X(ll_rw_block),
X(__wait_on_buffer),
/* device registration */ /* device registration */
X(register_chrdev), X(register_chrdev),
...@@ -156,6 +163,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */ ...@@ -156,6 +163,7 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(printk), X(printk),
X(sprintf), X(sprintf),
X(vsprintf), X(vsprintf),
X(simple_strtoul),
X(system_utsname), X(system_utsname),
X(sys_call_table), X(sys_call_table),
...@@ -206,26 +214,16 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */ ...@@ -206,26 +214,16 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
#endif #endif
/* Added to make file system as module */ /* Added to make file system as module */
X(set_writetime), X(set_writetime),
X(getblk),
X(inode_setattr),
X(sys_tz), X(sys_tz),
X(inode_change_ok),
X(__wait_on_super), X(__wait_on_super),
X(file_fsync), X(file_fsync),
X(simple_strtoul),
X(generic_mmap),
X(set_blocksize),
X(clear_inode), X(clear_inode),
X(refile_buffer), X(refile_buffer),
X(___strtok), X(___strtok),
X(brelse),
X(bread),
X(init_fifo), X(init_fifo),
X(super_blocks), X(super_blocks),
X(chrdev_inode_operations), X(chrdev_inode_operations),
X(blkdev_inode_operations), X(blkdev_inode_operations),
X(ll_rw_block),
X(__wait_on_buffer),
X(read_ahead), X(read_ahead),
/******************************************************** /********************************************************
* Do not add anything below this line, * Do not add anything below this line,
......
...@@ -319,7 +319,7 @@ int unmap_page_range(unsigned long from, unsigned long size) ...@@ -319,7 +319,7 @@ int unmap_page_range(unsigned long from, unsigned long size)
for (pc = pcnt; pc--; page_table++) { for (pc = pcnt; pc--; page_table++) {
if ((page = *page_table) != 0) { if ((page = *page_table) != 0) {
*page_table = 0; *page_table = 0;
if (1 & page) { if (PAGE_PRESENT & page) {
if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)) if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED))
if (current->mm->rss > 0) if (current->mm->rss > 0)
--current->mm->rss; --current->mm->rss;
......
...@@ -624,7 +624,7 @@ static int inet_create(struct socket *sock, int protocol) ...@@ -624,7 +624,7 @@ static int inet_create(struct socket *sock, int protocol)
sk->prot = prot; sk->prot = prot;
sk->sleep = sock->wait; sk->sleep = sock->wait;
sk->daddr = 0; sk->daddr = 0;
sk->saddr = ip_my_addr(); sk->saddr = 0 /* ip_my_addr() */;
sk->err = 0; sk->err = 0;
sk->next = NULL; sk->next = NULL;
sk->pair = NULL; sk->pair = NULL;
...@@ -749,6 +749,7 @@ static int inet_release(struct socket *sock, struct socket *peer) ...@@ -749,6 +749,7 @@ static int inet_release(struct socket *sock, struct socket *peer)
/* This will destroy it. */ /* This will destroy it. */
release_sock(sk); release_sock(sk);
sock->data = NULL; sock->data = NULL;
sk->socket = NULL;
return(0); return(0);
} }
...@@ -1261,6 +1262,10 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ...@@ -1261,6 +1262,10 @@ static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
/* /*
* This routine must find a socket given a TCP or UDP header. * This routine must find a socket given a TCP or UDP header.
* Everything is assumed to be in net order. * Everything is assumed to be in net order.
*
* We give priority to more closely bound ports: if some socket
* is bound to a particular foreign address, it will get the packet
* rather than somebody listening to any address..
*/ */
struct sock *get_sock(struct proto *prot, unsigned short num, struct sock *get_sock(struct proto *prot, unsigned short num,
...@@ -1268,6 +1273,8 @@ struct sock *get_sock(struct proto *prot, unsigned short num, ...@@ -1268,6 +1273,8 @@ struct sock *get_sock(struct proto *prot, unsigned short num,
unsigned short rnum, unsigned long laddr) unsigned short rnum, unsigned long laddr)
{ {
struct sock *s; struct sock *s;
struct sock *result = NULL;
int badness = -1;
unsigned short hnum; unsigned short hnum;
hnum = ntohs(num); hnum = ntohs(num);
...@@ -1284,21 +1291,41 @@ struct sock *get_sock(struct proto *prot, unsigned short num, ...@@ -1284,21 +1291,41 @@ struct sock *get_sock(struct proto *prot, unsigned short num,
for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)]; for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
s != NULL; s = s->next) s != NULL; s = s->next)
{ {
int score = 0;
if (s->num != hnum) if (s->num != hnum)
continue; continue;
if(s->dead && (s->state == TCP_CLOSE)) if(s->dead && (s->state == TCP_CLOSE))
continue; continue;
if(ip_addr_match(s->saddr,laddr) == 0) /* local address matches? */
continue; if (s->saddr) {
if(prot == &udp_prot) if (s->saddr != laddr)
continue;
score++;
}
/* remote address matches? */
if (s->daddr) {
if (s->daddr != raddr)
continue;
score++;
}
/* remote port matches? */
if (s->dummy_th.dest) {
if (s->dummy_th.dest != rnum)
continue;
score++;
}
/* perfect match? */
if (score == 3)
return s; return s;
if(ip_addr_match(s->daddr,raddr)==0) /* no, check if this is the best so far.. */
continue; if (score <= badness)
if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
continue; continue;
return(s); result = s;
badness = score;
} }
return(NULL); return result;
} }
static struct proto_ops inet_proto_ops = { static struct proto_ops inet_proto_ops = {
......
...@@ -200,13 +200,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -200,13 +200,6 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
int tmp; int tmp;
unsigned long src; unsigned long src;
/*
* If there is no 'from' address as yet, then make it our loopback
*/
if (saddr == 0)
saddr = ip_my_addr();
buff = skb->data; buff = skb->data;
/* /*
...@@ -255,6 +248,12 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd ...@@ -255,6 +248,12 @@ int ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long dadd
raddr = (rt == NULL) ? 0 : rt->rt_gateway; raddr = (rt == NULL) ? 0 : rt->rt_gateway;
} }
/*
* No source addr so make it our addr
*/
if (saddr == 0)
saddr = src;
/* /*
* No gateway so aim at the real destination * No gateway so aim at the real destination
*/ */
......
...@@ -95,7 +95,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of ...@@ -95,7 +95,7 @@ get__netinfo(struct proto *pro, char *buffer, int format, char **start, off_t of
format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc,
format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
timer_active, sp->timer.expires, (unsigned) sp->retransmits, timer_active, sp->timer.expires, (unsigned) sp->retransmits,
sp->dead?0:SOCK_INODE(sp->socket)->i_uid); sp->socket?SOCK_INODE(sp->socket)->i_uid:0);
if (timer_active) if (timer_active)
add_timer(&sp->timer); add_timer(&sp->timer);
/* /*
......
...@@ -542,9 +542,9 @@ struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned l ...@@ -542,9 +542,9 @@ struct rtable * ip_rt_route(unsigned long daddr, struct options *opt, unsigned l
/* /*
* broadcast addresses can be special cases.. * broadcast addresses can be special cases..
*/ */
if (rt->rt_flags & RTF_GATEWAY)
if ((rt->rt_gateway == 0) && continue;
(rt->rt_dev->flags & IFF_BROADCAST) && if ((rt->rt_dev->flags & IFF_BROADCAST) &&
(rt->rt_dev->pa_brdaddr == daddr)) (rt->rt_dev->pa_brdaddr == daddr))
break; break;
} }
......
...@@ -89,6 +89,10 @@ ...@@ -89,6 +89,10 @@
* Michael Pall : Undo the last fix in tcp_read_urg() (multi URG PUSH broke rlogin). * Michael Pall : Undo the last fix in tcp_read_urg() (multi URG PUSH broke rlogin).
* Michael Pall : Fix the multi URG PUSH problem in tcp_readable(), select() after URG works now. * Michael Pall : Fix the multi URG PUSH problem in tcp_readable(), select() after URG works now.
* Michael Pall : recv(...,MSG_OOB) never blocks in the BSD api. * Michael Pall : recv(...,MSG_OOB) never blocks in the BSD api.
* Alan Cox : Changed the semantics of sk->socket to
* fix a race and a signal problem with
* accept() and async I/O.
* Alan Cox : Relaxed the rules on tcp_sendto().
* *
* *
* To Fix: * To Fix:
...@@ -1227,7 +1231,7 @@ static int tcp_sendto(struct sock *sk, unsigned char *from, ...@@ -1227,7 +1231,7 @@ static int tcp_sendto(struct sock *sk, unsigned char *from,
{ {
if (flags & ~(MSG_OOB|MSG_DONTROUTE)) if (flags & ~(MSG_OOB|MSG_DONTROUTE))
return -EINVAL; return -EINVAL;
if (!tcp_connected(sk->state)) if (sk->state == TCP_CLOSE)
return -ENOTCONN; return -ENOTCONN;
if (addr_len < sizeof(*addr)) if (addr_len < sizeof(*addr))
return -EINVAL; return -EINVAL;
...@@ -2084,6 +2088,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, ...@@ -2084,6 +2088,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->dummy_th.res2 = 0; newsk->dummy_th.res2 = 0;
newsk->acked_seq = skb->h.th->seq + 1; newsk->acked_seq = skb->h.th->seq + 1;
newsk->copied_seq = skb->h.th->seq; newsk->copied_seq = skb->h.th->seq;
newsk->socket = NULL;
/* /*
* Grab the ttl and tos values and use them * Grab the ttl and tos values and use them
......
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