diff -u --recursive --new-file v1.1.60/linux/CREDITS linux/CREDITS --- v1.1.60/linux/CREDITS Wed Nov 2 12:03:44 1994 +++ linux/CREDITS Tue Nov 1 19:50:44 1994 @@ -64,7 +64,7 @@ S: The Netherlands 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 S: The Netherlands diff -u --recursive --new-file v1.1.60/linux/Makefile linux/Makefile --- v1.1.60/linux/Makefile Wed Nov 2 12:03:44 1994 +++ linux/Makefile Tue Nov 1 19:50:44 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 60 +SUBLEVEL = 61 ARCH = i386 diff -u --recursive --new-file v1.1.60/linux/drivers/block/README.sbpcd linux/drivers/block/README.sbpcd --- v1.1.60/linux/drivers/block/README.sbpcd Tue Aug 30 08:16:13 1994 +++ linux/drivers/block/README.sbpcd Wed Nov 2 11:51:13 1994 @@ -1,4 +1,4 @@ -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. The driver is able to drive the whole family of "traditional" IDE-style (that @@ -6,6 +6,14 @@ Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The 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. The matter that some other brand's drives work with newer sound card interfaces does NOT make the drives compatible. :-) @@ -49,8 +57,8 @@ 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. -Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE -accordingly. +Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE (at top +of sbpcd2.c) accordingly. 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 @@ -72,9 +80,10 @@ The software interface possibly may change a bit the day the SCSI driver supports it too. -MultiSession is supported, "ManySession" (not recommended, see below) -alternatively. -Photo CDs work, too (even with my "old" CR-521). +With the CR-562 and CR-563 drives, MultiSession is supported, "ManySession" +(not recommended, see below) alternatively. +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 photo CD image files. @@ -188,6 +197,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; 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 + * 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 +#include +#include + +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: diff -u --recursive --new-file v1.1.60/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c --- v1.1.60/linux/drivers/block/cdu31a.c Wed Nov 2 12:03:45 1994 +++ linux/drivers/block/cdu31a.c Tue Nov 1 19:50:44 1994 @@ -2856,8 +2856,8 @@ { 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); + irq_used = 0; } } diff -u --recursive --new-file v1.1.60/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.1.60/linux/drivers/block/floppy.c Sun Oct 23 13:04:29 1994 +++ linux/drivers/block/floppy.c Wed Nov 2 13:19:42 1994 @@ -348,6 +348,7 @@ struct floppy_struct user_params[N_DRIVE]; static int floppy_sizes[256]; +static int floppy_blocksizes[256] = { 0, }; /* * The driver is trying to determine the correct media format @@ -2848,7 +2849,7 @@ if (floppy_grab_irq_and_dma()) return -EBUSY; - if(filp->f_flags & O_EXCL) + if (filp->f_flags & O_EXCL) UDRS->fd_ref = -1; else UDRS->fd_ref++; @@ -2956,7 +2957,10 @@ UDRS->generation++; if(!current_type[drive] && !TYPE(dev)){ /* 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(); return 1; } @@ -3062,6 +3066,7 @@ floppy_sizes[i] = MAX_DISK_SIZE; blk_size[MAJOR_NR] = floppy_sizes; + blksize_size[MAJOR_NR] = floppy_blocksizes; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; timer_table[FLOPPY_TIMER].fn = floppy_shutdown; timer_active &= ~(1 << FLOPPY_TIMER); diff -u --recursive --new-file v1.1.60/linux/drivers/block/mcd.c linux/drivers/block/mcd.c --- v1.1.60/linux/drivers/block/mcd.c Wed Aug 10 20:06:59 1994 +++ linux/drivers/block/mcd.c Tue Nov 1 19:50:44 1994 @@ -1182,7 +1182,6 @@ mcd_invalidate_buffers(); mcdPresent = 1; - printk("\n"); return mem_start; } diff -u --recursive --new-file v1.1.60/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c --- v1.1.60/linux/drivers/block/sbpcd.c Tue Aug 30 08:16:13 1994 +++ linux/drivers/block/sbpcd.c Wed Nov 2 11:51:13 1994 @@ -5,7 +5,7 @@ * and for "no-sound" interfaces like Lasermate and the * 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 * and with the new CR-562-B V0.75 on a "naked" Panasonic * CI-101P interface. And vice versa. @@ -128,6 +128,10 @@ * * 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 * * disk change detection @@ -203,7 +207,7 @@ #include "blk.h" -#define VERSION "2.6 Eberhard Moenkeberg " +#define VERSION "2.7 Eberhard Moenkeberg " #define SBPCD_DEBUG @@ -303,6 +307,9 @@ 0x320, 2, /* SPEA Media FX */ 0x340, 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 /* some "hazardous" locations (ethernet cards) */ 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */ @@ -310,9 +317,6 @@ 0x370, 0, /* Lasermate, CI-101P */ 0x290, 1, /* Soundblaster 16 */ 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 }; @@ -390,6 +394,7 @@ #else static int sbpcd_debug = (1< +#include -/* skip this driver if not required for this configuration */ -#if CONFIG_QIC02_TAPE /* #define TDEBUG @@ -233,8 +233,8 @@ */ #ifdef CONFIG_QIC02_DYNCONF -/* This may hold the dynamic configuration info for the interface - * card+drive info in future versions. +/* This holds the dynamic configuration info for the interface + * card+drive info if runtime configuration has been selected. */ struct mtconfiginfo qic02_tape_dynconf = { 0, }; /* user settable */ struct qic02_ccb qic02_tape_ccb = { 0, }; /* private stuff */ @@ -256,8 +256,8 @@ static volatile struct tpstatus tperror; /* last drive status */ -static char rcs_revision[] = "$Revision: 0.4.1.4 $"; -static char rcs_date[] = "$Date: 1994/07/21 02:15:45 $"; +static char rcs_revision[] = "$Revision: 0.4.1.5 $"; +static char rcs_date[] = "$Date: 1994/10/29 02:46:13 $"; /* Flag bits for status and outstanding requests. * (Could all be put in one bit-field-struct.) @@ -285,7 +285,7 @@ static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */ 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; @@ -570,7 +570,9 @@ #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) { if (exnr==EXC_NCART) { @@ -1358,9 +1360,7 @@ return do_qic_cmd(QCMD_REWIND, TIM_R); case MTOFFL: - tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline"); /*---*/ - /******* What exactly are we supposed to do, to take it offline???? - *****/ + tpqputs(TPQD_IOCTLS, "MTOFFL rewinding & going offline"); /* Doing a drive select will clear (unlock) the current drive. * But that requires support for multiple drives and locking. */ @@ -1927,8 +1927,9 @@ } 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", - 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. */ tpqputs(TPQD_BLKSZ, "Wrong block size"); @@ -2100,8 +2101,9 @@ } 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", - 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 */ tpqputs(TPQD_BLKSZ, "Wrong block size"); @@ -2587,7 +2589,7 @@ if (!suser()) return -EPERM; verify_area(VERIFY_READ, (int *) ioarg, sizeof(int)); - c = get_fs_long((int *) ioarg); + c = get_user_long((int *) ioarg); if (c==0) { QIC02_TAPE_DEBUG = 0; return 0; @@ -2619,7 +2621,7 @@ stp = (char *) &qic02_tape_dynconf; argp = (char *) ioarg; for (i=0; i 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 diff -u --recursive --new-file v1.1.60/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.1.60/linux/drivers/net/Space.c Fri Aug 19 08:53:24 1994 +++ linux/drivers/net/Space.c Wed Nov 2 11:38:34 1994 @@ -49,6 +49,7 @@ extern int at1500_probe(struct device *); extern int at1700_probe(struct device *); extern int depca_probe(struct device *); +extern int ewrk3_probe(struct device *); extern int el1_probe(struct device *); extern int el16_probe(struct device *); extern int elplus_probe(struct device *); @@ -107,6 +108,9 @@ #endif #ifdef CONFIG_DEPCA /* DEC DEPCA */ && depca_probe(dev) +#endif +#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */ + && ewrk3_probe(dev) #endif #ifdef CONFIG_EL1 /* 3c501 */ && el1_probe(dev) diff -u --recursive --new-file v1.1.60/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v1.1.60/linux/drivers/net/ewrk3.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ewrk3.c Wed Nov 2 11:38:34 1994 @@ -0,0 +1,1835 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#ifdef MODULE +#include +#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>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;pagemPage;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; ilen; 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; ilen; 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; ipktStats.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> 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 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=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;jbase_addr; + + if (chipType == LeMAC2) { + for (crc=0x6a, j=0; j>= 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; idev_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; idev_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;jlen = 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: + */ + + + diff -u --recursive --new-file v1.1.60/linux/drivers/net/ewrk3.h linux/drivers/net/ewrk3.h --- v1.1.60/linux/drivers/net/ewrk3.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ewrk3.h Wed Nov 2 11:38:34 1994 @@ -0,0 +1,319 @@ +/* + 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 + +#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 */ diff -u --recursive --new-file v1.1.60/linux/fs/block_dev.c linux/fs/block_dev.c --- v1.1.60/linux/fs/block_dev.c Sun Sep 18 05:26:48 1994 +++ linux/fs/block_dev.c Wed Nov 2 13:47:52 1994 @@ -24,7 +24,7 @@ loff_t offset; int chars; int written = 0; - int cluster_list[4]; + int cluster_list[8]; struct buffer_head * bhlist[NBUF]; int blocks_per_cluster; unsigned int size; @@ -159,7 +159,7 @@ int blocksize_bits, i; unsigned int blocks, rblocks, left; int bhrequest, uptodate; - int cluster_list[4]; + int cluster_list[8]; int blocks_per_cluster; struct buffer_head ** bhb, ** bhe; struct buffer_head * buflist[NBUF]; diff -u --recursive --new-file v1.1.60/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v1.1.60/linux/fs/minix/inode.c Mon Apr 18 11:38:18 1994 +++ linux/fs/minix/inode.c Wed Nov 2 12:47:08 1994 @@ -122,6 +122,7 @@ if (32 != sizeof (struct minix_inode)) panic("bad i-node size"); lock_super(s); + set_blocksize(dev, BLOCK_SIZE); if (!(bh = bread(dev,1,BLOCK_SIZE))) { s->s_dev=0; unlock_super(s); diff -u --recursive --new-file v1.1.60/linux/fs/msdos/fat.c linux/fs/msdos/fat.c --- v1.1.60/linux/fs/msdos/fat.c Sat Apr 30 13:02:26 1994 +++ linux/fs/msdos/fat.c Wed Nov 2 11:43:48 1994 @@ -20,7 +20,6 @@ { struct buffer_head *bh,*bh2,*c_bh,*c_bh2; unsigned char *p_first,*p_last; - void *data,*data2,*c_data,*c_data2; int first,last,next,copy; if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0; @@ -30,17 +29,15 @@ last = first+1; } 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"); return 0; } - if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) { + if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) bh2 = bh; - data2 = data; - } else { if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last - >> SECTOR_BITS),&data2))) { + >> SECTOR_BITS)))) { brelse(bh); printk("bread in fat_access failed\n"); return 0; @@ -48,13 +45,13 @@ } if (MSDOS_SB(sb)->fat_bits == 16) { 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]); if (next >= 0xfff7) next = -1; } else { - p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)]; - p_last = &((unsigned char *) data2)[(first+1) & + p_first = &((unsigned char *) bh->b_data)[first & (SECTOR_SIZE-1)]; + p_last = &((unsigned char *) bh2->b_data)[(first+1) & (SECTOR_SIZE-1)]; if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff; else next = (*p_first+(*p_last << 8)) & 0xfff; @@ -62,7 +59,7 @@ } if (new_value != -1) { 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); else { if (nr & 1) { @@ -79,25 +76,25 @@ for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)-> fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> - fat_length*copy,&c_data))) break; - memcpy(c_data,data,SECTOR_SIZE); + fat_length*copy))) break; + memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE); mark_buffer_dirty(c_bh, 1); - if (data != data2 || bh != bh2) { + if (bh != bh2) { if (!(c_bh2 = msdos_sread(sb->s_dev, MSDOS_SB(sb)->fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy - +1,&c_data2))) { + +1))) { brelse(c_bh); break; } - memcpy(c_data2,data2,SECTOR_SIZE); + memcpy(c_bh2->b_data,bh2->b_data,SECTOR_SIZE); brelse(c_bh2); } brelse(c_bh); } } brelse(bh); - if (data != data2) brelse(bh2); + if (bh != bh2) brelse(bh2); return next; } diff -u --recursive --new-file v1.1.60/linux/fs/msdos/file.c linux/fs/msdos/file.c --- v1.1.60/linux/fs/msdos/file.c Wed Nov 2 12:03:46 1994 +++ linux/fs/msdos/file.c Wed Nov 2 11:43:48 1994 @@ -30,7 +30,7 @@ NULL, /* readdir - bad */ NULL, /* select - default */ NULL, /* ioctl - default */ - generic_mmap, /* mmap */ + generic_mmap, /* mmap */ NULL, /* no special open is needed */ NULL, /* release */ file_fsync /* fsync */ @@ -52,7 +52,7 @@ msdos_bmap, /* bmap */ msdos_truncate, /* truncate */ NULL, /* permission */ - NULL /* smap */ + NULL /* smap */ }; /* @@ -127,12 +127,11 @@ int sector; if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) break; - if (!(bh = msdos_sread(inode->i_dev,sector,&data))) + if (!(bh = msdos_sread(inode->i_dev,sector))) break; }else{ bh = pre.bhlist[pre.nolist]; pre.bhlist[pre.nolist++] = NULL; - data = bh->b_data; wait_on_buffer(bh); if (!bh->b_uptodate){ /* read error ? */ @@ -140,6 +139,7 @@ break; } } + data = bh->b_data; offset = filp->f_pos & (SECTOR_SIZE-1); filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left)); if (MSDOS_I(inode)->i_binary) { @@ -183,7 +183,6 @@ int error,carry; char *start,*to,ch; struct buffer_head *bh; - void *data; int binary_mode = MSDOS_I(inode)->i_binary; if (!inode) { @@ -211,25 +210,28 @@ } offset = filp->f_pos & (SECTOR_SIZE-1); 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 */ /* completely overwrite it */ + /* or at least write past the end of file */ if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){ error = -EIO; break; } - data = bh->b_data; - }else if (!(bh = msdos_sread(inode->i_dev,sector,&data))) { + }else if (!(bh = msdos_sread(inode->i_dev,sector))) { error = -EIO; break; } if (binary_mode) { - memcpy_fromfs(data+offset,buf,written = size); + memcpy_fromfs(bh->b_data+offset,buf,written = size); buf += size; } else { 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) { *to++ = '\n'; left--; diff -u --recursive --new-file v1.1.60/linux/fs/msdos/inode.c linux/fs/msdos/inode.c --- v1.1.60/linux/fs/msdos/inode.c Wed Nov 2 12:03:46 1994 +++ linux/fs/msdos/inode.c Wed Nov 2 13:20:18 1994 @@ -172,20 +172,7 @@ } cache_init(); lock_super(s); - if (MAJOR(s->s_dev) == FLOPPY_MAJOR){ - /* 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); + set_blocksize(s->s_dev, SECTOR_SIZE); bh = bread(s->s_dev, 0, SECTOR_SIZE); unlock_super(s); if (bh == NULL) { diff -u --recursive --new-file v1.1.60/linux/fs/msdos/misc.c linux/fs/msdos/misc.c --- v1.1.60/linux/fs/msdos/misc.c Wed Nov 2 12:03:46 1994 +++ linux/fs/msdos/misc.c Wed Nov 2 11:43:48 1994 @@ -256,7 +256,6 @@ struct msdos_dir_entry **de) { int sector,offset; - void *data; while (1) { offset = *pos; @@ -270,12 +269,12 @@ if (*bh) brelse(*bh); 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); continue; } 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))); return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >> MSDOS_DIR_BITS); @@ -344,7 +343,8 @@ struct inode *inode; 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++) { if (name) RSS_NAME else { diff -u --recursive --new-file v1.1.60/linux/fs/read_write.c linux/fs/read_write.c --- v1.1.60/linux/fs/read_write.c Sun Oct 23 19:20:36 1994 +++ linux/fs/read_write.c Tue Nov 1 19:50:44 1994 @@ -33,7 +33,10 @@ return -EBADF; error = -ENOTDIR; 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) error = file->f_op->readdir(inode,file,dirent,count); } diff -u --recursive --new-file v1.1.60/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c --- v1.1.60/linux/fs/umsdos/inode.c Wed Nov 2 12:03:47 1994 +++ linux/fs/umsdos/inode.c Wed Nov 2 11:16:02 1994 @@ -273,7 +273,13 @@ newattrs.ia_atime = inode->i_atime; newattrs.ia_ctime = inode->i_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); + inode->i_dirt = 0; } int UMSDOS_notify_change(struct inode *inode, struct iattr *attr) @@ -319,6 +325,7 @@ struct file filp; struct umsdos_dirent entry; filp.f_pos = inode->u.umsdos_i.pos; + filp.f_reada = 0; PRINTK (("pos = %d ",filp.f_pos)); /* Read only the start of the entry since we don't touch */ /* the name */ diff -u --recursive --new-file v1.1.60/linux/fs/xiafs/bitmap.c linux/fs/xiafs/bitmap.c --- v1.1.60/linux/fs/xiafs/bitmap.c Sat Oct 22 16:24:03 1994 +++ linux/fs/xiafs/bitmap.c Tue Nov 1 19:50:45 1994 @@ -35,7 +35,6 @@ int end, i, j, tmp; u_long *bmap; - char res; bmap=(u_long *)bh->b_data; end = end_bit >> 5; diff -u --recursive --new-file v1.1.60/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v1.1.60/linux/include/linux/cdrom.h Wed Aug 10 19:26:42 1994 +++ linux/include/linux/cdrom.h Wed Nov 2 11:51:13 1994 @@ -377,10 +377,16 @@ /* read type-1 data */ /* * 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): */ #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 diff -u --recursive --new-file v1.1.60/linux/include/linux/ipc.h linux/include/linux/ipc.h --- v1.1.60/linux/include/linux/ipc.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/ipc.h Tue Nov 1 19:50:45 1994 @@ -39,7 +39,7 @@ #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 msgbuf *msgp; diff -u --recursive --new-file v1.1.60/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v1.1.60/linux/include/linux/msdos_fs.h Wed Nov 2 12:03:47 1994 +++ linux/include/linux/msdos_fs.h Wed Nov 2 11:43:48 1994 @@ -110,13 +110,9 @@ #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); - if (bh != NULL){ - *start = bh->b_data; /* From the time of 1024 bytes block */ - } - return bh; + return bread(dev,sector,SECTOR_SIZE); } diff -u --recursive --new-file v1.1.60/linux/include/linux/msg.h linux/include/linux/msg.h --- v1.1.60/linux/include/linux/msg.h Sun Mar 6 16:10:53 1994 +++ linux/include/linux/msg.h Tue Nov 1 19:50:45 1994 @@ -6,15 +6,6 @@ #define MSG_NOERROR 010000 /* no error if message is too big */ #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 */ struct msqid_ds { struct ipc_perm msg_perm; @@ -32,14 +23,13 @@ ushort msg_lrpid; /* last receive pid */ }; - /* message buffer for msgsnd and msgrcv calls */ struct msgbuf { long mtype; /* type of message */ char mtext[1]; /* message text */ }; - +/* buffer for msgctl calls IPC_INFO, MSG_INFO */ struct msginfo { int msgpool; int msgmap; @@ -64,6 +54,14 @@ #define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff) #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 */ #define MSG_STAT 11 diff -u --recursive --new-file v1.1.60/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.1.60/linux/include/linux/sched.h Tue Oct 18 14:14:42 1994 +++ linux/include/linux/sched.h Tue Nov 1 19:50:45 1994 @@ -290,7 +290,7 @@ struct tty_struct *tty; /* NULL if no tty */ /* shm stuff */ 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 */ struct desc_struct *ldt; /* tss for this task */ diff -u --recursive --new-file v1.1.60/linux/include/linux/sem.h linux/include/linux/sem.h --- v1.1.60/linux/include/linux/sem.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/sem.h Tue Nov 1 19:50:45 1994 @@ -26,16 +26,7 @@ ushort sem_nsems; /* no. of semaphores in array */ }; - -/* 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.*/ +/* semop system calls takes an array of these. */ struct sembuf { ushort sem_num; /* semaphore index in array */ short sem_op; /* semaphore operation */ @@ -44,12 +35,13 @@ /* arg for semctl system calls. */ union semun { - int val; /* value for SETVAL */ - struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ - ushort *array; /* array for GETALL & SETALL */ + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ + ushort *array; /* array for GETALL & SETALL */ + struct seminfo *__buf; /* buffer for IPC_INFO */ + void *__pad; }; - struct seminfo { int semmap; int semmni; @@ -77,6 +69,15 @@ #define SEMUSZ 20 /* sizeof struct sem_undo */ #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 */ #define SEM_STAT 18 #define SEM_INFO 19 diff -u --recursive --new-file v1.1.60/linux/include/linux/shm.h linux/include/linux/shm.h --- v1.1.60/linux/include/linux/shm.h Tue Jan 4 13:08:23 1994 +++ linux/include/linux/shm.h Tue Nov 1 19:50:45 1994 @@ -3,7 +3,7 @@ #include struct shmid_ds { - struct ipc_perm shm_perm; /* operation perms */ + struct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* size of segment (bytes) */ time_t shm_atime; /* last attach time */ time_t shm_dtime; /* last detach time */ @@ -12,9 +12,9 @@ unsigned short shm_lpid; /* pid of last operator */ short shm_nattch; /* no. of current attaches */ /* the following are private */ - unsigned short shm_npages; /* size of segment (pages) */ - unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ - struct shm_desc *attaches; /* descriptors for attaches */ + unsigned short shm_npages; /* size of segment (pages) */ + unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ + struct shm_desc *attaches; /* descriptors for attaches */ }; /* mode for attach */ @@ -34,34 +34,35 @@ int shmall; }; +/* address range for shared memory attaches if no address passed to shmat() */ #define SHM_RANGE_START 0x40000000 #define SHM_RANGE_END 0x60000000 - /* _SHM_ID_BITS is a variable you can adjust to */ - /* tune the kernel. It determines the value of */ - /* SHMMNI, which specifies the maximum no. of */ - /* shared segments (system wide). SRB. */ -#define _SHM_ID_BITS 7 /* keep as low as possible */ - /* a static array is declared */ - /* using SHMMNI */ - -#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 */ +/* format of page table entries that correspond to shared memory pages + currently out in swap space (see also mm/swap.c): + bit 0 (PAGE_PRESENT) is = 0 + bits 7..1 (SWP_TYPE) are = SHM_SWP_TYPE + bits 31..8 are used like this: + bits 14..8 (SHM_ID) the id of the shared memory segment + 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 +*/ -/* not present page table entry format bit 0 is 0, low byte defined in mm.h */ #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_IDX_SHIFT (SHM_ID_SHIFT+_SHM_ID_BITS) +#define _SHM_IDX_BITS 15 #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 SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */ @@ -105,5 +106,4 @@ #endif /* __KERNEL__ */ #endif /* _LINUX_SHM_H_ */ - diff -u --recursive --new-file v1.1.60/linux/ipc/msg.c linux/ipc/msg.c --- v1.1.60/linux/ipc/msg.c Wed Apr 27 08:05:16 1994 +++ linux/ipc/msg.c Tue Nov 1 19:50:45 1994 @@ -29,7 +29,7 @@ { int id; - for (id=0; id < MSGMNI; id++) + for (id = 0; id < MSGMNI; id++) msgque[id] = (struct msqid_ds *) IPC_UNUSED; msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0; msg_lock = NULL; @@ -53,14 +53,14 @@ return err; if ((mtype = get_fs_long (&msgp->mtype)) < 1) return -EINVAL; - id = msqid % MSGMNI; + id = (unsigned int) msqid % MSGMNI; msq = msgque [id]; if (msq == IPC_UNUSED || msq == IPC_NOID) return -EINVAL; ipcp = &msq->msg_perm; slept: - if (ipcp->seq != (msqid / MSGMNI)) + if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) return -EIDRM; if (ipcperms(ipcp, S_IWUGO)) return -EACCES; @@ -83,7 +83,7 @@ memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID - || ipcp->seq != msqid / MSGMNI) { + || msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) { kfree(msgh); return -EIDRM; } @@ -125,7 +125,7 @@ if (err) return err; - id = msqid % MSGMNI; + id = (unsigned int) msqid % MSGMNI; msq = msgque [id]; if (msq == IPC_NOID || msq == IPC_UNUSED) return -EINVAL; @@ -138,7 +138,7 @@ * msgtyp < 0 => get message with least type must be < abs(msgtype). */ while (!nmsg) { - if(ipcp->seq != msqid / MSGMNI) + if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) return -EIDRM; if (ipcperms (ipcp, S_IRUGO)) return -EACCES; @@ -174,7 +174,7 @@ if (nmsg == msq->msg_first) msq->msg_first = nmsg->msg_next; else { - for (tmsg= msq->msg_first; tmsg; + for (tmsg = msq->msg_first; tmsg; tmsg = tmsg->msg_next) if (tmsg->msg_next == nmsg) break; @@ -213,7 +213,7 @@ int id; struct msqid_ds *msq; - for (id=0; id <= max_msqid; id++) { + for (id = 0; id <= max_msqid; id++) { while ((msq = msgque[id]) == IPC_NOID) interruptible_sleep_on (&msg_lock); if (msq == IPC_UNUSED) @@ -230,7 +230,7 @@ struct msqid_ds *msq; struct ipc_perm *ipcp; - for (id=0; id < MSGMNI; id++) + for (id = 0; id < MSGMNI; id++) if (msgque[id] == IPC_UNUSED) { msgque[id] = (struct msqid_ds *) IPC_NOID; goto found; @@ -250,7 +250,7 @@ ipcp->key = key; ipcp->cuid = ipcp->uid = current->euid; ipcp->gid = ipcp->cgid = current->egid; - ipcp->seq = msg_seq; + msq->msg_perm.seq = msg_seq; msq->msg_first = msq->msg_last = NULL; msq->rwait = msq->wwait = NULL; msq->msg_cbytes = msq->msg_qnum = 0; @@ -264,7 +264,7 @@ used_queues++; if (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) @@ -286,7 +286,7 @@ return -EIDRM; if (ipcperms(&msq->msg_perm, msgflg)) return -EACCES; - return msq->msg_perm.seq * MSGMNI +id; + return (unsigned int) msq->msg_perm.seq * MSGMNI + id; } static void freeque (int id) @@ -295,7 +295,7 @@ struct msg *msgp, *msgh; msq->msg_perm.seq++; - msg_seq++; + msg_seq = (msg_seq+1) % ((unsigned)(1<<31)/MSGMNI); /* increment, but avoid overflow */ msgbytes -= msq->msg_cbytes; if (id == max_msqid) while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); @@ -319,7 +319,8 @@ int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { int id, err; - struct msqid_ds *msq, tbuf; + struct msqid_ds *msq; + struct msqid_ds tbuf; struct ipc_perm *ipcp; if (msqid < 0 || cmd < 0) @@ -353,7 +354,7 @@ case MSG_STAT: if (!buf) return -EFAULT; - err = verify_area (VERIFY_WRITE, buf, sizeof (*msq)); + err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (err) return err; if (msqid > max_msqid) @@ -363,46 +364,62 @@ return -EINVAL; if (ipcperms (&msq->msg_perm, S_IRUGO)) return -EACCES; - id = msqid + msq->msg_perm.seq * MSGMNI; - memcpy_tofs (buf, msq, sizeof(*msq)); + id = (unsigned int) msq->msg_perm.seq * MSGMNI + msqid; + 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; case IPC_SET: if (!buf) return -EFAULT; + err = verify_area (VERIFY_READ, buf, sizeof (*buf)); + if (err) + return err; memcpy_fromfs (&tbuf, buf, sizeof (*buf)); break; case IPC_STAT: if (!buf) return -EFAULT; - err = verify_area (VERIFY_WRITE, buf, sizeof(*msq)); + err = verify_area (VERIFY_WRITE, buf, sizeof(*buf)); if (err) return err; break; } - id = msqid % MSGMNI; + id = (unsigned int) msqid % MSGMNI; msq = msgque [id]; if (msq == IPC_UNUSED || msq == IPC_NOID) return -EINVAL; - ipcp = &msq->msg_perm; - if (ipcp->seq != msqid / MSGMNI) + if (msq->msg_perm.seq != (unsigned int) msqid / MSGMNI) return -EIDRM; + ipcp = &msq->msg_perm; switch (cmd) { case IPC_STAT: if (ipcperms (ipcp, S_IRUGO)) 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; - break; - case IPC_RMID: case IPC_SET: + case IPC_SET: if (!suser() && current->euid != ipcp->cuid && current->euid != ipcp->uid) return -EPERM; - if (cmd == IPC_RMID) { - freeque (id); - return 0; - } if (tbuf.msg_qbytes > MSGMNB && !suser()) return -EPERM; msq->msg_qbytes = tbuf.msg_qbytes; @@ -411,10 +428,14 @@ ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | (S_IRWXUGO & tbuf.msg_perm.mode); 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: return -EINVAL; - break; } - return 0; } diff -u --recursive --new-file v1.1.60/linux/ipc/sem.c linux/ipc/sem.c --- v1.1.60/linux/ipc/sem.c Wed Apr 27 08:06:06 1994 +++ linux/ipc/sem.c Tue Nov 1 19:50:45 1994 @@ -26,11 +26,11 @@ void sem_init (void) { - int i=0; + int i; sem_lock = NULL; 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; return; } @@ -40,7 +40,7 @@ int id; struct semid_ds *sma; - for (id=0; id <= max_semid; id++) { + for (id = 0; id <= max_semid; id++) { while ((sma = semary[id]) == IPC_NOID) interruptible_sleep_on (&sem_lock); if (sma == IPC_UNUSED) @@ -62,7 +62,7 @@ return -EINVAL; if (used_sems + nsems > SEMMNS) return -ENOSPC; - for (id=0; id < SEMMNI; id++) + for (id = 0; id < SEMMNI; id++) if (semary[id] == IPC_UNUSED) { semary[id] = (struct semid_ds *) IPC_NOID; goto found; @@ -86,7 +86,7 @@ ipcp->key = key; ipcp->cuid = ipcp->uid = current->euid; ipcp->gid = ipcp->cgid = current->egid; - ipcp->seq = sem_seq; + sma->sem_perm.seq = sem_seq; sma->eventn = sma->eventz = NULL; sma->sem_nsems = nsems; sma->sem_ctime = CURRENT_TIME; @@ -96,7 +96,7 @@ semary[id] = sma; if (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) @@ -120,7 +120,7 @@ return -EINVAL; if (ipcperms(&sma->sem_perm, semflg)) return -EACCES; - return sma->sem_perm.seq*SEMMNI + id; + return (unsigned int) sma->sem_perm.seq * SEMMNI + id; } static void freeary (int id) @@ -129,13 +129,13 @@ struct sem_undo *un; sma->sem_perm.seq++; - sem_seq++; + sem_seq = (sem_seq+1) % ((unsigned)(1<<31)/SEMMNI); /* increment, but avoid overflow */ used_sems -= sma->sem_nsems; if (id == max_semid) while (max_semid && (semary[--max_semid] == IPC_UNUSED)); semary[id] = (struct semid_ds *) IPC_UNUSED; used_semids--; - for (un=sma->undo; un; un=un->id_next) + for (un = sma->undo; un; un = un->id_next) un->semadj = 0; while (sma->eventz || sma->eventn) { if (sma->eventz) @@ -148,16 +148,19 @@ 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; - struct semid_ds *sma, *buf = NULL, tbuf; + struct semid_ds *sma; struct ipc_perm *ipcp; struct sem *curr; struct sem_undo *un; - ushort nsems, *array = NULL; + unsigned int nsems; + ushort *array = NULL; ushort sem_io[SEMMSL]; - + if (semid < 0 || semnum < 0 || cmd < 0) return -EINVAL; @@ -165,9 +168,7 @@ case IPC_INFO: case SEM_INFO: { - struct seminfo seminfo, *tmp; - if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg))) - return -EFAULT; + struct seminfo seminfo, *tmp = arg.__buf; seminfo.semmni = SEMMNI; seminfo.semmns = SEMMNS; seminfo.semmsl = SEMMSL; @@ -182,7 +183,7 @@ seminfo.semusz = used_semids; seminfo.semaem = used_sems; } - i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); + i = verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); if (i) return i; memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo)); @@ -190,9 +191,8 @@ } case SEM_STAT: - if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg))) - return -EFAULT; - i = verify_area (VERIFY_WRITE, buf, sizeof (*sma)); + buf = arg.buf; + i = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (i) return i; if (semid > max_semid) @@ -202,18 +202,22 @@ return -EINVAL; if (ipcperms (&sma->sem_perm, S_IRUGO)) return -EACCES; - id = semid + sma->sem_perm.seq * SEMMNI; - memcpy_tofs (buf, sma, sizeof(*sma)); + id = (unsigned int) sma->sem_perm.seq * SEMMNI + semid; + 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; } - id = semid % SEMMNI; + id = (unsigned int) semid % SEMMNI; sma = semary [id]; if (sma == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; ipcp = &sma->sem_perm; nsems = sma->sem_nsems; - if (ipcp->seq != semid / SEMMNI) + if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) return -EIDRM; if (semnum >= nsems) return -EINVAL; @@ -233,17 +237,15 @@ case GETNCNT: return curr->semncnt; case GETZCNT: return curr->semzcnt; case GETALL: - if (!arg || ! (array = (ushort *) get_fs_long((int *) arg))) - return -EFAULT; - i = verify_area (VERIFY_WRITE, array, nsems*sizeof(short)); + array = arg.array; + i = verify_area (VERIFY_WRITE, array, nsems*sizeof(ushort)); if (i) return i; } break; - case SETVAL: - if (!arg) - return -EFAULT; - if ((val = (int) get_fs_long ((int *) arg)) > SEMVMX || val < 0) + case SETVAL: + val = arg.val; + if (val > SEMVMX || val < 0) return -ERANGE; break; case IPC_RMID: @@ -254,40 +256,37 @@ } return -EPERM; case SETALL: /* arg is a pointer to an array of ushort */ - if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) ) - return -EFAULT; - if ((i = verify_area (VERIFY_READ, array, sizeof tbuf))) + array = arg.array; + if ((i = verify_area (VERIFY_READ, array, nsems*sizeof(ushort)))) return i; 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) return -ERANGE; break; case IPC_STAT: - if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) - return -EFAULT; - if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*sma)))) + buf = arg.buf; + if ((i = verify_area (VERIFY_WRITE, buf, sizeof(*buf)))) return i; break; case IPC_SET: - if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) - return -EFAULT; - if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf))) + buf = arg.buf; + if ((i = verify_area (VERIFY_READ, buf, sizeof (*buf)))) return i; - memcpy_fromfs (&tbuf, buf, sizeof tbuf); + memcpy_fromfs (&tbuf, buf, sizeof (*buf)); break; } if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID) return -EIDRM; - if (ipcp->seq != semid / SEMMNI) + if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) return -EIDRM; switch (cmd) { case GETALL: if (ipcperms (ipcp, S_IRUGO)) 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; memcpy_tofs (array, sem_io, nsems*sizeof(ushort)); break; @@ -318,12 +317,16 @@ case IPC_STAT: if (ipcperms (ipcp, S_IRUGO)) 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; case SETALL: if (ipcperms (ipcp, S_IWUGO)) return -EACCES; - for (i=0; isem_base[i].semval = sem_io[i]; for (un = sma->undo; un; un = un->id_next) un->semadj = 0; @@ -354,11 +357,13 @@ return -E2BIG; if (!tsops) return -EFAULT; + if ((i = verify_area (VERIFY_READ, tsops, nsops * sizeof(*tsops)))) + return i; memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops)); - id = semid % SEMMNI; + id = (unsigned int) semid % SEMMNI; if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) return -EINVAL; - for (i=0; isem_num > sma->sem_nsems) return -EFBIG; @@ -376,10 +381,10 @@ * ensure every sop with undo gets an undo structure */ if (undos) { - for (i=0; isemun; un; un = un->proc_next) + for (un = current->semundo; un; un = un->proc_next) if ((un->semid == semid) && (un->sem_num == sops[i].sem_num)) break; @@ -392,17 +397,17 @@ un->semid = semid; un->semadj = 0; un->sem_num = sops[i].sem_num; - un->proc_next = current->semun; - current->semun = un; + un->proc_next = current->semundo; + current->semundo = un; un->id_next = sma->undo; sma->undo = un; } } slept: - if (sma->sem_perm.seq != semid / SEMMNI) + if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI) return -EIDRM; - for (i=0; isem_base[sop->sem_num]; if (sop->sem_op + curr->semval > SEMVMX) @@ -429,7 +434,7 @@ } } - for (i=0; isem_base[sop->sem_num]; curr->sempid = current->pid; @@ -437,7 +442,7 @@ semzcnt++; if (!(sop->sem_flg & SEM_UNDO)) continue; - for (un = current->semun; un; un = un->proc_next) + for (un = current->semundo; un; un = un->proc_next) if ((un->semid == semid) && (un->sem_num == sop->sem_num)) break; @@ -466,11 +471,11 @@ struct semid_ds *sma; struct sem *sem = NULL; - for (up = ¤t->semun; (u = *up); *up = u->proc_next, kfree(u)) { - sma = semary[u->semid % SEMMNI]; + for (up = ¤t->semundo; (u = *up); *up = u->proc_next, kfree(u)) { + sma = semary[(unsigned int) u->semid % SEMMNI]; if (sma == IPC_UNUSED || sma == IPC_NOID) continue; - if (sma->sem_perm.seq != u->semid / SEMMNI) + if (sma->sem_perm.seq != (unsigned int) u->semid / SEMMNI) continue; for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { if (u == un) @@ -483,7 +488,7 @@ if (!un->semadj) continue; while (1) { - if (sma->sem_perm.seq != un->semid / SEMMNI) + if (sma->sem_perm.seq != (unsigned int) un->semid / SEMMNI) break; sem = &sma->sem_base[un->sem_num]; if (sem->semval + un->semadj >= 0) { @@ -503,6 +508,6 @@ sem->semncnt--; } } - current->semun = NULL; + current->semundo = NULL; return; } diff -u --recursive --new-file v1.1.60/linux/ipc/shm.c linux/ipc/shm.c --- v1.1.60/linux/ipc/shm.c Tue Aug 9 09:33:00 1994 +++ linux/ipc/shm.c Tue Nov 1 19:50:45 1994 @@ -1,31 +1,30 @@ /* * linux/ipc/shm.c - * Copyright (C) 1992, 1993 Krishna Balasubramanian + * Copyright (C) 1992, 1993 Krishna Balasubramanian * Many improvements/fixes by Bruno Haible. - * assume user segments start at 0x0 */ #include #include #include -#include +#include #include #include #include -extern int ipcperms (struct ipc_perm *ipcp, short semflg); -extern unsigned int get_swap_page(void); +extern int ipcperms (struct ipc_perm *ipcp, short shmflg); +extern unsigned int get_swap_page (void); static int findkey (key_t key); static int newseg (key_t key, int shmflg, int size); static int shm_map (struct shm_desc *shmd, int remap); 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_swp = 0; /* number of shared memory pages that are in swap */ 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 unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */ @@ -38,31 +37,31 @@ void shm_init (void) { int id; - - for (id = 0; id < SHMMNI; id++) + + for (id = 0; id < SHMMNI; id++) shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0; shm_lock = NULL; return; } -static int findkey (key_t key) +static int findkey (key_t key) { int id; struct shmid_ds *shp; - - for (id=0; id <= max_shmid; id++) { - while ((shp = shm_segs[id]) == IPC_NOID) + + for (id = 0; id <= max_shmid; id++) { + while ((shp = shm_segs[id]) == IPC_NOID) sleep_on (&shm_lock); if (shp == IPC_UNUSED) continue; - if (key == shp->shm_perm.key) + if (key == shp->shm_perm.key) return id; } return -1; } -/* +/* * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID. */ static int newseg (key_t key, int shmflg, int size) @@ -75,7 +74,7 @@ return -EINVAL; if (shm_tot + numpages >= SHMALL) return -ENOSPC; - for (id=0; id < SHMMNI; id++) + for (id = 0; id < SHMMNI; id++) if (shm_segs[id] == IPC_UNUSED) { shm_segs[id] = (struct shmid_ds *) IPC_NOID; goto found; @@ -100,7 +99,7 @@ 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; shp->shm_perm.key = key; shp->shm_perm.mode = (shmflg & S_IRWXUGO); @@ -121,23 +120,23 @@ used_segs++; if (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) { struct shmid_ds *shp; int id = 0; - + if (size < 0 || size > SHMMAX) return -EINVAL; - if (key == IPC_PRIVATE) + if (key == IPC_PRIVATE) return newseg(key, shmflg, size); if ((id = findkey (key)) == -1) { if (!(shmflg & IPC_CREAT)) return -ENOENT; return newseg(key, shmflg, size); - } + } if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) return -EEXIST; shp = shm_segs[id]; @@ -147,10 +146,10 @@ return -EINVAL; if (ipcperms (&shp->shm_perm, shmflg)) 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. * Here pages, pgtable and shmid_ds are freed. */ @@ -166,20 +165,20 @@ return; } shp->shm_perm.seq++; /* for shmat */ - numpages = shp->shm_npages; - shm_seq++; + shm_seq = (shm_seq+1) % ((unsigned)(1<<31)/SHMMNI); /* increment, but avoid overflow */ shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; used_segs--; - if (id == max_shmid) + if (id == max_shmid) while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED)); if (!shp->shm_pages) { printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id); return; } - for (i=0; i< numpages ; i++) { + numpages = shp->shm_npages; + for (i = 0; i < numpages ; i++) { if (!(page = shp->shm_pages[i])) continue; - if (page & 1) { + if (page & PAGE_PRESENT) { free_page (page & PAGE_MASK); shm_rss--; } else { @@ -195,10 +194,11 @@ 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; int id, err; - + if (cmd < 0 || shmid < 0) return -EINVAL; if (cmd == IPC_SET) { @@ -211,7 +211,7 @@ } switch (cmd) { /* replace with proc interface ? */ - case IPC_INFO: + case IPC_INFO: { struct shminfo shminfo; if (!buf) @@ -227,15 +227,15 @@ memcpy_tofs (buf, &shminfo, sizeof(struct shminfo)); return max_shmid; } - case SHM_INFO: - { + case SHM_INFO: + { struct shm_info shm_info; if (!buf) return -EFAULT; err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info)); if (err) return err; - shm_info.used_ids = used_segs; + shm_info.used_ids = used_segs; shm_info.shm_rss = shm_rss; shm_info.shm_tot = shm_tot; shm_info.shm_swp = shm_swp; @@ -247,7 +247,7 @@ case SHM_STAT: if (!buf) return -EFAULT; - err = verify_area (VERIFY_WRITE, buf, sizeof (*shp)); + err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (err) return err; if (shmid > max_shmid) @@ -257,18 +257,26 @@ return -EINVAL; if (ipcperms (&shp->shm_perm, S_IRUGO)) return -EACCES; - id = shmid + shp->shm_perm.seq * SHMMNI; - memcpy_tofs (buf, shp, sizeof(*shp)); + id = (unsigned int) shp->shm_perm.seq * SHMMNI + shmid; + 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; } - - shp = shm_segs[id = shmid % SHMMNI]; + + shp = shm_segs[id = (unsigned int) shmid % SHMMNI]; if (shp == IPC_UNUSED || shp == IPC_NOID) return -EINVAL; - ipcp = &shp->shm_perm; - if (ipcp->seq != shmid / SHMMNI) + if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI) return -EIDRM; - + ipcp = &shp->shm_perm; + switch (cmd) { case SHM_UNLOCK: if (!suser()) @@ -292,10 +300,18 @@ return -EACCES; if (!buf) return -EFAULT; - err = verify_area (VERIFY_WRITE, buf, sizeof (*shp)); + err = verify_area (VERIFY_WRITE, buf, sizeof (*buf)); if (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; case IPC_SET: if (suser() || current->euid == shp->shm_perm.uid || @@ -312,7 +328,7 @@ if (suser() || current->euid == shp->shm_perm.uid || current->euid == shp->shm_perm.cuid) { shp->shm_perm.mode |= SHM_DEST; - if (shp->shm_nattch <= 0) + if (shp->shm_nattch <= 0) killseg (id); break; } @@ -334,9 +350,9 @@ unsigned long *page_table; unsigned long tmp, shm_sgn; unsigned long page_dir = shmd->task->tss.cr3; - + /* 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); if (*page_table & PAGE_PRESENT) { page_table = (ulong *) (PAGE_MASK & *page_table); @@ -353,10 +369,10 @@ invalid++; } continue; - } + } { 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; *page_table = new_pt | PAGE_TABLE; tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE); @@ -366,8 +382,8 @@ /* map page range */ shm_sgn = shmd->shm_sgn; - for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, - shm_sgn += (1 << SHM_IDX_SHIFT)) { + for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, + shm_sgn += (1 << SHM_IDX_SHIFT)) { page_table = PAGE_DIR_OFFSET(page_dir,tmp); page_table = (ulong *) (PAGE_MASK & *page_table); page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); @@ -404,7 +420,7 @@ vma->vm_task = current; vma->vm_start = addr; 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) vma->vm_page_prot = PAGE_READONLY; else { @@ -420,10 +436,9 @@ return 0; } -/* +/* * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. * 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) { @@ -432,17 +447,17 @@ int err; unsigned int id; unsigned long addr; - + if (shmid < 0) return -EINVAL; if (raddr) { - err = verify_area(VERIFY_WRITE, raddr, sizeof(long)); + err = verify_area(VERIFY_WRITE, raddr, sizeof(ulong)); if (err) return err; } - shp = shm_segs[id = shmid % SHMMNI]; + shp = shm_segs[id = (unsigned int) shmid % SHMMNI]; if (shp == IPC_UNUSED || shp == IPC_NOID) return -EINVAL; @@ -450,7 +465,7 @@ if (shmflg & SHM_REMAP) return -EINVAL; /* set addr below all current unspecified attaches */ - addr = SHM_RANGE_END; + addr = SHM_RANGE_END; for (shmd = current->shm; shmd; shmd = shmd->task_next) { if (shmd->start < SHM_RANGE_START) continue; @@ -459,7 +474,7 @@ } addr = (addr - shp->shm_segsz) & PAGE_MASK; } else if (addr & (SHMLBA-1)) { - if (shmflg & SHM_RND) + if (shmflg & SHM_RND) addr &= ~(SHMLBA-1); /* round down */ else return -EINVAL; @@ -470,26 +485,26 @@ for (shmd = current->shm; shmd; shmd = shmd->task_next) { if (addr >= shmd->start && addr < shmd->end) return -EINVAL; - if (addr + shp->shm_segsz >= shmd->start && + if (addr + shp->shm_segsz >= shmd->start && addr + shp->shm_segsz < shmd->end) return -EINVAL; } if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO)) return -EACCES; - if (shp->shm_perm.seq != shmid / SHMMNI) + if (shp->shm_perm.seq != (unsigned int) shmid / SHMMNI) return -EIDRM; shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL); if (!shmd) 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); return -EIDRM; } shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) | (shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0); - shmd->start = addr; + shmd->start = addr; shmd->end = addr + shp->shm_npages * PAGE_SIZE; shmd->task = current; @@ -506,7 +521,7 @@ kfree(shmd); return err; } - + shmd->task_next = current->shm; current->shm = shmd; shmd->seg_next = shp->attaches; @@ -526,28 +541,28 @@ */ static void detach (struct shm_desc **shmdp) { - struct shm_desc *shmd = *shmdp; - struct shmid_ds *shp; - int id; - + struct shm_desc *shmd = *shmdp; + struct shmid_ds *shp; + int id; + id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK; - shp = shm_segs[id]; - *shmdp = shmd->task_next; - for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next) + shp = shm_segs[id]; + *shmdp = shmd->task_next; + for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next) if (*shmdp == shmd) { - *shmdp = shmd->seg_next; - goto found; + *shmdp = shmd->seg_next; + 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: do_munmap(shmd->start, shp->shm_segsz); kfree(shmd); - shp->shm_lpid = current->pid; + shp->shm_lpid = current->pid; shp->shm_dtime = CURRENT_TIME; if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST) killseg (id); /* sleeps */ - return; + return; } /* @@ -556,9 +571,9 @@ */ int sys_shmdt (char *shmaddr) { - struct shm_desc *shmd, **shmdp; - - for (shmdp = ¤t->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { + struct shm_desc *shmd, **shmdp; + + for (shmdp = ¤t->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { if (shmd->start == (ulong) shmaddr) { detach (shmdp); return 0; @@ -567,17 +582,17 @@ return -EINVAL; } -/* - * detach all attached segments. +/* + * detach all attached segments. */ void shm_exit (void) { - while (current->shm) + while (current->shm) detach(¤t->shm); - return; + return; } -/* +/* * copy the parent shm descriptors and update nattch * parent is stuck in fork so an attach on each segment is assured. * copy_page_tables does the mapping. @@ -588,17 +603,17 @@ struct shmid_ds *shp; int id; - p2->semun = NULL; + p2->semundo = NULL; p2->shm = NULL; if (!p1->shm) return 0; for (shmd = p1->shm; shmd; shmd = shmd->task_next) { tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL); if (!tmp) { - while (new_desc) { - tmp = new_desc->task_next; + while (new_desc) { + tmp = new_desc->task_next; kfree(new_desc); - new_desc = tmp; + new_desc = tmp; } free_page_tables (p2); return -ENOMEM; @@ -670,7 +685,7 @@ } shm_rss++; shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY); - } else + } else --current->mm->maj_flt; /* was incremented in do_no_page */ done: @@ -683,7 +698,7 @@ } /* - * 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_idx = 0; /* next to swap */ @@ -704,7 +719,7 @@ check_id: shp = shm_segs[swap_id]; if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) { - swap_idx = 0; + swap_idx = 0; if (++swap_id > max_shmid) swap_id = 0; goto check_id; @@ -712,8 +727,8 @@ id = swap_id; check_table: - idx = swap_idx++; - if (idx >= shp->shm_npages) { + idx = swap_idx++; + if (idx >= shp->shm_npages) { swap_idx = 0; if (++swap_id > max_shmid) swap_id = 0; @@ -743,12 +758,12 @@ continue; } pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp); - if (!(*pte & 1)) { - printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", + if (!(*pte & PAGE_PRESENT)) { + printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", id, shmd->start, idx); *pte = 0; continue; - } + } pte = (ulong *) (PAGE_MASK & *pte); pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1)); tmp = *pte; @@ -756,7 +771,7 @@ continue; if (tmp & PAGE_ACCESSED) { *pte &= ~PAGE_ACCESSED; - continue; + continue; } tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT; *pte = tmp; @@ -765,7 +780,7 @@ invalid++; } - if (mem_map[MAP_NR(page)] != 1) + if (mem_map[MAP_NR(page)] != 1) goto check_table; page &= PAGE_MASK; shp->shm_pages[idx] = swap_nr; diff -u --recursive --new-file v1.1.60/linux/ipc/util.c linux/ipc/util.c --- v1.1.60/linux/ipc/util.c Fri Feb 18 16:20:22 1994 +++ linux/ipc/util.c Tue Nov 1 19:50:45 1994 @@ -13,7 +13,7 @@ #include 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 @@ -21,16 +21,16 @@ 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_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_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg); extern int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg); 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_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr); extern int sys_shmdt (char *shmaddr); +extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); void ipc_init (void) { @@ -71,8 +71,16 @@ return sys_semop (first, (struct sembuf *)ptr, second); case SEMGET: return sys_semget (first, second, third); - case SEMCTL: - return sys_semctl (first, second, third, ptr); + case SEMCTL: { + 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: return -EINVAL; } @@ -82,10 +90,13 @@ return sys_msgsnd (first, (struct msgbuf *) ptr, second, third); case MSGRCV: { - struct ipc_kludge tmp; + struct ipc_kludge tmp; + int err; if (!ptr) 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)); return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); @@ -93,14 +104,13 @@ case MSGGET: return sys_msgget ((key_t) first, second); case MSGCTL: - return sys_msgctl (first, second, - (struct msqid_ds *) ptr); + return sys_msgctl (first, second, (struct msqid_ds *) ptr); default: return -EINVAL; } if (call <= SHMCTL) switch (call) { - case SHMAT: /* returning shmaddr > 2G will screw up */ + case SHMAT: return sys_shmat (first, (char *) ptr, second, (ulong *) third); case SHMDT: @@ -108,8 +118,7 @@ case SHMGET: return sys_shmget (first, second, third); case SHMCTL: - return sys_shmctl (first, second, - (struct shmid_ds *) ptr); + return sys_shmctl (first, second, (struct shmid_ds *) ptr); default: return -EINVAL; } diff -u --recursive --new-file v1.1.60/linux/kernel/exit.c linux/kernel/exit.c --- v1.1.60/linux/kernel/exit.c Tue Aug 9 09:34:45 1994 +++ linux/kernel/exit.c Tue Nov 1 19:50:45 1994 @@ -411,7 +411,7 @@ intr_count = 0; } fake_volatile: - if (current->semun) + if (current->semundo) sem_exit(); if (current->shm) shm_exit(); diff -u --recursive --new-file v1.1.60/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.1.60/linux/kernel/ksyms.c Wed Nov 2 12:03:47 1994 +++ linux/kernel/ksyms.c Tue Nov 1 19:50:45 1994 @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef CONFIG_INET #include #include @@ -46,7 +47,6 @@ #endif extern int sys_tz; -extern int ___strtok; extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); @@ -92,6 +92,13 @@ X(open_namei), X(inode_setattr), 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 */ X(register_chrdev), @@ -156,6 +163,7 @@ X(printk), X(sprintf), X(vsprintf), + X(simple_strtoul), X(system_utsname), X(sys_call_table), @@ -206,26 +214,16 @@ #endif /* Added to make file system as module */ X(set_writetime), - X(getblk), - X(inode_setattr), X(sys_tz), - X(inode_change_ok), X(__wait_on_super), X(file_fsync), - X(simple_strtoul), - X(generic_mmap), - X(set_blocksize), X(clear_inode), X(refile_buffer), X(___strtok), - X(brelse), - X(bread), X(init_fifo), X(super_blocks), X(chrdev_inode_operations), X(blkdev_inode_operations), - X(ll_rw_block), - X(__wait_on_buffer), X(read_ahead), /******************************************************** * Do not add anything below this line, diff -u --recursive --new-file v1.1.60/linux/mm/memory.c linux/mm/memory.c --- v1.1.60/linux/mm/memory.c Sun Oct 23 12:33:58 1994 +++ linux/mm/memory.c Tue Nov 1 19:50:45 1994 @@ -319,7 +319,7 @@ for (pc = pcnt; pc--; page_table++) { if ((page = *page_table) != 0) { *page_table = 0; - if (1 & page) { + if (PAGE_PRESENT & page) { if (!(mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)) if (current->mm->rss > 0) --current->mm->rss; diff -u --recursive --new-file v1.1.60/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.60/linux/net/inet/af_inet.c Wed Nov 2 12:03:47 1994 +++ linux/net/inet/af_inet.c Wed Nov 2 11:32:03 1994 @@ -624,7 +624,7 @@ sk->prot = prot; sk->sleep = sock->wait; sk->daddr = 0; - sk->saddr = ip_my_addr(); + sk->saddr = 0 /* ip_my_addr() */; sk->err = 0; sk->next = NULL; sk->pair = NULL; @@ -749,6 +749,7 @@ /* This will destroy it. */ release_sock(sk); sock->data = NULL; + sk->socket = NULL; return(0); } @@ -1261,6 +1262,10 @@ /* * This routine must find a socket given a TCP or UDP header. * 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, @@ -1268,6 +1273,8 @@ unsigned short rnum, unsigned long laddr) { struct sock *s; + struct sock *result = NULL; + int badness = -1; unsigned short hnum; hnum = ntohs(num); @@ -1284,21 +1291,41 @@ for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)]; s != NULL; s = s->next) { + int score = 0; + if (s->num != hnum) continue; + if(s->dead && (s->state == TCP_CLOSE)) continue; - if(ip_addr_match(s->saddr,laddr) == 0) - continue; - if(prot == &udp_prot) + /* local address matches? */ + if (s->saddr) { + 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; - if(ip_addr_match(s->daddr,raddr)==0) - continue; - if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) + /* no, check if this is the best so far.. */ + if (score <= badness) continue; - return(s); + result = s; + badness = score; } - return(NULL); + return result; } static struct proto_ops inet_proto_ops = { diff -u --recursive --new-file v1.1.60/linux/net/inet/ip.c linux/net/inet/ip.c --- v1.1.60/linux/net/inet/ip.c Wed Oct 12 15:35:00 1994 +++ linux/net/inet/ip.c Tue Nov 1 19:50:45 1994 @@ -200,13 +200,6 @@ int tmp; 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; /* @@ -254,6 +247,12 @@ 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 diff -u --recursive --new-file v1.1.60/linux/net/inet/proc.c linux/net/inet/proc.c --- v1.1.60/linux/net/inet/proc.c Wed Jul 13 01:01:40 1994 +++ linux/net/inet/proc.c Wed Nov 2 12:33:50 1994 @@ -95,7 +95,7 @@ format==0?sp->write_seq-sp->rcv_ack_seq:sp->rmem_alloc, format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc, 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) add_timer(&sp->timer); /* diff -u --recursive --new-file v1.1.60/linux/net/inet/route.c linux/net/inet/route.c --- v1.1.60/linux/net/inet/route.c Wed Nov 2 12:03:47 1994 +++ linux/net/inet/route.c Tue Nov 1 19:50:45 1994 @@ -542,9 +542,9 @@ /* * broadcast addresses can be special cases.. */ - - if ((rt->rt_gateway == 0) && - (rt->rt_dev->flags & IFF_BROADCAST) && + if (rt->rt_flags & RTF_GATEWAY) + continue; + if ((rt->rt_dev->flags & IFF_BROADCAST) && (rt->rt_dev->pa_brdaddr == daddr)) break; } diff -u --recursive --new-file v1.1.60/linux/net/inet/tcp.c linux/net/inet/tcp.c --- v1.1.60/linux/net/inet/tcp.c Fri Oct 28 12:54:32 1994 +++ linux/net/inet/tcp.c Tue Nov 1 19:50:46 1994 @@ -89,6 +89,10 @@ * 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 : 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: @@ -1227,7 +1231,7 @@ { if (flags & ~(MSG_OOB|MSG_DONTROUTE)) return -EINVAL; - if (!tcp_connected(sk->state)) + if (sk->state == TCP_CLOSE) return -ENOTCONN; if (addr_len < sizeof(*addr)) return -EINVAL; @@ -2084,6 +2088,7 @@ newsk->dummy_th.res2 = 0; newsk->acked_seq = skb->h.th->seq + 1; newsk->copied_seq = skb->h.th->seq; + newsk->socket = NULL; /* * Grab the ttl and tos values and use them