]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.19pre17 2.2.19pre17
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:30 +0000 (15:23 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:23:30 +0000 (15:23 -0500)
o Fix missing tcp init (Alexey Kuznetsov)
| Should fix the odd resets people still saw
o Fix DVD read physical bug (Jens Axboe)
o Fix break handling on sx driver (Rogier Wolff)
o Fix starfire bogus error messages (Ion Badulescu)
o Fix off by one in cpia driver (Andrew Morton)
o Armin Schindler as eicnon maintainer (Armin Schindler)
o Update bluetooth driver to match 2.4.2 (Greg Kroah-Hartman)
o Update dc2xx to match 2.4.2 (Greg Kroah-Hartman)
o Update empeg to match 2.4.2 (Greg Kroah-Hartman)
o Update keyspan driver to match 2.4.2 (Greg Kroah-Hartman)
o Update usb serial core/generic to match 2.4,2 (Greg Kroah-Hartman)
o Update usb visor to match 2.4.2 (Greg Kroah-Hartman)
o binfmt_misc fixups (Al Viro)
o Update 3c527 driver (Richard Procter)
o IRDA crash fix from 2.4 (Michael McConnell)
o Fix misc device busy locking (Philipp Rumpf)
o Further dumpable fix (Solar Designer)
o Fix ide pmac oops on resume (Benjamin Herrenschmidt)
o 3ware small updates/7000 series support (Adam Radford)

26 files changed:
Documentation/Configure.help
Documentation/isdn/README.eicon
MAINTAINERS
Makefile
drivers/block/ide-pmac.c
drivers/cdrom/cdrom.c
drivers/char/Makefile
drivers/char/cpia.c
drivers/char/misc.c
drivers/char/sx.c
drivers/net/3c527.c
drivers/net/3c527.h
drivers/net/irda/irtty.c
drivers/net/starfire.c
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h
drivers/usb/bluetooth.c
drivers/usb/dc2xx.c
drivers/usb/serial/empeg.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/usbserial.c
drivers/usb/serial/visor.c
fs/binfmt_misc.c
fs/exec.c
include/linux/cdrom.h
net/ipv4/tcp_input.c

index ba218abac6609bb7b0183c5fdc8f3e9673cbe250..22c2d083c81dd8c2debca68514fda5310f931e56 100644 (file)
@@ -11910,7 +11910,7 @@ CONFIG_ISDN_DRV_SC
   called sc.o. See Documentation/isdn/README.sc and
   http://www.spellcast.com for more information.
 
-Eicon.Diehl active card support
+Eicon active card support
 CONFIG_ISDN_DRV_EICON
   Say Y here if you have an Eicon active ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
@@ -11918,6 +11918,16 @@ CONFIG_ISDN_DRV_EICON
   latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
   
+Eicon legacy driver
+CONFIG_ISDN_DRV_EICON_OLD
+  Say Y here to use your Eicon active ISDN card with ISDN4Linux
+  isdn module.
+
+Eicon Diva Server card support
+CONFIG_ISDN_DRV_EICON_PCI
+  Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card.
+  Please read Documentation/isdn/README.eicon for more information.
+
 Eicon old-type card support
 CONFIG_ISDN_DRV_EICON_ISA
   Say Y here if you have an old-type Eicon active ISDN card. In order
@@ -11926,6 +11936,14 @@ CONFIG_ISDN_DRV_EICON_ISA
   the latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
 
+Eicon driver type standalone
+CONFIG_ISDN_DRV_EICON_DIVAS
+  Enable this option if you want the eicon driver as standalone
+  version with no interface to the ISDN4Linux isdn module. If you
+  say Y here, the eicon module only supports the Diva Server PCI
+  cards and will provide its own IDI interface. You should say N
+  here.
+
 Support AT-Fax Class 2 commands
 CONFIG_ISDN_TTY_FAX
   If you say Y here, the modem-emulator will support a subset of the
index 16dd09eb9e1c8d7d2c868e369c0607d3c57937f2..2e36d442b3d3705ee263e99ca82844bb254d3961 100644 (file)
@@ -100,17 +100,6 @@ Just use "eiconctrl isdnlog on" and the driver will generate
 the necessary D-Channel traces for isdnlog.
 
 
-FILECHECK:
-A part of the eicon driver source code files are provided
-by Eicon Technology. In order to get the best support from Eicon,
-these files are tested with a checksum, just to know if the files
-were modified. This does *not* mean, you are not allowed to modify the
-driver. If you want to improve the driver or you fix a bug, please do
-so and let me (or Eicon) know, about the necessary changes. So
-every user knows, if the driver he uses is modified or checked with
-Eicon files. When the driver has been loaded, in the syslog you will
-find something like "verified" or "modified" right after the version.
-
 
 Thanks to 
        Deutsche Mailbox Saar-Lor-Lux GmbH
index 3d584b77623cac0d79f4e0bd19d42fa31cf8d330..f7f992325e2467ba20249e46ddae47451626115d 100644 (file)
@@ -545,6 +545,13 @@ M: keil@isdn4linux.de
 L:     isdn4linux@listserv.isdn4linux.de
 S:     Maintained
 
+ISDN SUBSYSTEM (Eicon active card driver)
+P:     Armin Schindler
+M:     mac@melware.de
+L:     isdn4linux@listserv.isdn4linux.de
+W:     http://www.melware.net
+S:     Maintained
+
 JOYSTICK DRIVER
 P:     Vojtech Pavlik
 M:     vojtech@suse.cz
index 43ada2a25469f0d0b789710d176fd905980b8dc6..d435daf20dd5560f3ae21d35af6a5abc8db72af0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 19
-EXTRAVERSION = pre16
+EXTRAVERSION = pre17
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index ac2230abe9f7e6ea588ab08314c0e674d9fe0814..13a7c4684b093c37a1871d89dfb69a3e3bb73d92 100644 (file)
@@ -905,7 +905,8 @@ static void idepmac_wake_device(ide_drive_t *drive, int used_dma)
         * Problem: This can schedule. I moved the block device
         * wakeup almost late by priority because of that.
         */
-       DRIVER(drive)->media_change(drive);
+       if (DRIVER(drive))
+               DRIVER(drive)->media_change(drive);
 
        /* We kick the VFS too (see fix in ide.c revalidate) */
        check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
index 0ae2740ebb1c5ad7ee10ab4c1652ee8d76deb366..f3556499103747713a02ea8af58cd0b2c8cacd82 100644 (file)
@@ -1140,15 +1140,18 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai)
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-       int ret, i;
-       u_char buf[4 + 4 * 20], *base;
+       unsigned char buf[20], *base;
        struct dvd_layer *layer;
        struct cdrom_generic_command cgc;
        struct cdrom_device_ops *cdo = cdi->ops;
+       int ret, layer_num = s->physical.layer_num;
+
+       if (layer_num >= DVD_LAYERS)
+               return -EINVAL;
 
        init_cdrom_command(&cgc, buf, sizeof(buf));
        cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-       cgc.cmd[6] = s->physical.layer_num;
+       cgc.cmd[6] = layer_num;
        cgc.cmd[7] = s->type;
        cgc.cmd[9] = cgc.buflen & 0xff;
 
@@ -1156,26 +1159,26 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
                return ret;
 
        base = &buf[4];
-       layer = &s->physical.layer[0];
-
-       /* place the data... really ugly, but at least we won't have to
-          worry about endianess in userspace or here. */
-       for (i = 0; i < 4; ++i, base += 20, ++layer) {
-               memset(layer, 0, sizeof(*layer));
-               layer->book_version = base[0] & 0xf;
-               layer->book_type = base[0] >> 4;
-               layer->min_rate = base[1] & 0xf;
-               layer->disc_size = base[1] >> 4;
-               layer->layer_type = base[2] & 0xf;
-               layer->track_path = (base[2] >> 4) & 1;
-               layer->nlayers = (base[2] >> 5) & 3;
-               layer->track_density = base[3] & 0xf;
-               layer->linear_density = base[3] >> 4;
-               layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
-               layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
-               layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
-               layer->bca = base[16] >> 7;
-       }
+       layer = &s->physical.layer[layer_num];
+
+       /*
+        * place the data... really ugly, but at least we won't have to
+        * worry about endianess in userspace.
+        */
+       memset(layer, 0, sizeof(*layer));
+       layer->book_version = base[0] & 0xf;
+       layer->book_type = base[0] >> 4;
+       layer->min_rate = base[1] & 0xf;
+       layer->disc_size = base[1] >> 4;
+       layer->layer_type = base[2] & 0xf;
+       layer->track_path = (base[2] >> 4) & 1;
+       layer->nlayers = (base[2] >> 5) & 3;
+       layer->track_density = base[3] & 0xf;
+       layer->linear_density = base[3] >> 4;
+       layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
+       layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
+       layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
+       layer->bca = base[16] >> 7;
 
        return 0;
 }
index acc8e533e7c673a1a54ece4029fad309a598d527..12beadf6b13c69b384f3ce11e98ca6cfd6453ed1 100644 (file)
@@ -200,7 +200,13 @@ else
   endif
 endif
 
-obj-$(CONFIG_SX) += sx.o generic_serial.o
+ifeq ($(CONFIG_SX),y)
+O_OBJS += sx.o generic_serial.o
+else
+  ifeq ($(CONFIG_SX),m)
+  M_OBJS += sx.o generic_serial.o
+  endif
+endif
 
 ifeq ($(CONFIG_RIO),y)
 O_OBJS += rio/rio.o generic_serial.o
index f810498a905998b087238e70d21090ea58e5751b..0a666fc460c805d6bedffa29ddd04a8056630639 100644 (file)
@@ -3211,7 +3211,7 @@ static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
                DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
                    vm.width, vm.height);
 #endif
-               if (vm.frame<0||vm.frame>FRAME_NUM) {
+               if (vm.frame<0||vm.frame>=FRAME_NUM) {
                        retval = -EINVAL;
                        break;
                }
index 05a8f3b5748fe9c4806b795f4cbf1710dac14ca4..d1f7a09c975bb314c6d62a8c60a3ab3bb4d2d7d9 100644 (file)
@@ -139,8 +139,17 @@ static struct file_operations misc_fops = {
 
 int misc_register(struct miscdevice * misc)
 {
+       struct miscdevice *c;
+
        if (misc->next || misc->prev)
                return -EBUSY;
+       c = misc_list.next;
+
+       while ((c != &misc_list) && (c->minor != misc->minor))
+               c = c->next;
+       if (c != &misc_list)
+               return -EBUSY;
+
        if (misc->minor == MISC_DYNAMIC_MINOR) {
                int i = DYNAMIC_MINORS;
                while (--i >= 0)
index aef6223d0bfb0d10799e31c8b1507883ddf36dfe..fc4ab9699a4add88cfa60e96c09444072609f2ca 100644 (file)
@@ -1799,6 +1799,20 @@ static int sx_fw_ioctl (struct inode *inode, struct file *filp,
 }
 
 
+static void sx_break (struct tty_struct * tty, int flag)
+{
+       struct sx_port *port = tty->driver_data;
+       int rv;
+
+       if (flag) 
+               rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
+       else 
+               rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
+       if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
+                       read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+}
+
+
 static int sx_ioctl (struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -1867,7 +1881,6 @@ static int sx_ioctl (struct tty_struct * tty, struct file * filp,
                        sx_reconfigure_port(port);
                }
                break;
-
        default:
                rc = -ENOIOCTLCMD;
                break;
@@ -2247,6 +2260,7 @@ static int sx_init_drivers(void)
        sx_driver.table = sx_table;
        sx_driver.termios = sx_termios;
        sx_driver.termios_locked = sx_termios_locked;
+       sx_driver.break_ctl = sx_break;
 
        sx_driver.open  = sx_open;
        sx_driver.close = gs_close;
index 5ff404b72b18ebc2976fa0864f20cb4586f4b19f..5a155d45b18b1e253c11c48c84a375aec7a70554 100644 (file)
@@ -1,7 +1,8 @@
-/* 3c527.c: 3Com Etherlink/MC32 driver for Linux
+/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.2
  *
  *     (c) Copyright 1998 Red Hat Software Inc
- *     Written by Alan Cox.
+ *     Written by Alan Cox. 
+ *      Modified by Richard Procter (rnp@netlink.co.nz)
  *
  *     Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
  *     (for the MCA stuff) written by Wim Dumon.
  *     documentation.
  *
  *     This software may be used and distributed according to the terms
- *     of the GNU Public License, incorporated herein by reference.
+ *     of the GNU General Public License, incorporated herein by reference.
  *
  */
 
 static const char *version =
-       "3c527.c:v0.06 1999/09/16 Alan Cox (alan@redhat.com)\n";
+       "3c527.c:v0.5 1999/09/16 Alan Cox (alan@redhat.com)\n";
 
-/* Modified by Richard Procter (rprocter@mcs.vuw.ac.nz, rnp@netlink.co.nz) */
-
-/*
- *     Things you need
- *     o       The databook.
- *
- *     Traps for the unwary
+/**
+ * DOC: Traps for the unwary
  *
  *     The diagram (Figure 1-1) and the POS summary disagree with the
  *     "Interrupt Level" section in the manual.
  *
+ *     The manual contradicts itself when describing the minimum number 
+ *     buffers in the 'configure lists' command. 
+ *     My card accepts a buffer config of 4/4. 
+ *
+ *     Setting the SAV BP bit does not save bad packets, but
+ *     only enables RX on-card stats collection. 
+ *
  *     The documentation in places seems to miss things. In actual fact
  *     I've always eventually found everything is documented, it just
  *     requires careful study.
  *
- *      The manual contradicts itself when describing the minimum number 
- *      buffers in the 'configure lists' command. 
- *      My card accepts a buffer config of 4/4. 
+ * DOC: Theory Of Operation
  *
- */
+ *     The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
+ *     amount of on board intelligence that housekeeps a somewhat dumber
+ *     Intel NIC. For performance we want to keep the transmit queue deep
+ *     as the card can transmit packets while fetching others from main
+ *     memory by bus master DMA. Transmission and reception are driven by
+ *     circular buffer queues.
+ *
+ *     The mailboxes can be used for controlling how the card traverses
+ *     its buffer rings, but are used only for inital setup in this
+ *     implementation.  The exec mailbox allows a variety of commands to
+ *     be executed. Each command must complete before the next is
+ *     executed. Primarily we use the exec mailbox for controlling the
+ *     multicast lists.  We have to do a certain amount of interesting
+ *     hoop jumping as the multicast list changes can occur in interrupt
+ *     state when the card has an exec command pending. We defer such
+ *     events until the command completion interrupt.
+ *
+ *     A copy break scheme (taken from 3c59x.c) is employed whereby
+ *     received frames exceeding a configurable length are passed
+ *     directly to the higher networking layers without incuring a copy,
+ *     in what amounts to a time/space trade-off.
+ *      
+ *     The card also keeps a large amount of statistical information
+ *     on-board. In a perfect world, these could be used safely at no
+ *     cost. However, lacking information to the contrary, processing
+ *     them without races would involve so much extra complexity as to
+ *     make it unworthwhile to do so. In the end, a hybrid SW/HW
+ *     implementation was made necessary --- see mc32_update_stats().  
+ *
+ * DOC: Notes
+ *     
+ *     It should be possible to use two or more cards, but at this stage
+ *     only by loading two copies of the same module.
+ *
+ *     The on-board 82586 NIC has trouble receiving multiple
+ *     back-to-back frames and so is likely to drop packets from fast
+ *     senders.
+**/
 
 #include <linux/module.h>
 
@@ -61,8 +99,7 @@ static const char *version =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-
-#include <linux/proc_fs.h>
+#include <linux/if_ether.h>
 
 #include "3c527.h"
 
@@ -82,15 +119,20 @@ static const char* cardname = "3c527";
 static unsigned int mc32_debug = NET_DEBUG;
 
 /* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT      8
+#define MC32_IO_EXTENT 8
 
 /* As implemented, values must be a power-of-2 -- 4/8/16/32 */ 
-
-#define TX_RING_LEN     16       /* Typically the card supports 37  */
+#define TX_RING_LEN     32       /* Typically the card supports 37  */
 #define RX_RING_LEN     8        /*     "       "        "          */
 
+/* Copy break point, see above for details. 
+ * Setting to > 1512 effectively disables this feature.        */          
 #define RX_COPYBREAK    200      /* Value from 3c59x.c */
 
+/* Issue the 82586 workaround command - this is for "busy lans", but
+ * basically means for all lans now days - has a performance (latency) 
+ * cost, but best set. */ 
+static const int WORKAROUND_82586=1;
 
 /* Pointers to buffers and their on-card records */
 struct mc32_ring_desc 
@@ -113,14 +155,16 @@ struct mc32_local
        u16 rx_chain;           /* Receive list start offset */
         u16 tx_len;             /* Transmit list count */ 
         u16 rx_len;             /* Receive list count */
+
        u32 base;
-       u16 rx_halted;
-       u16 tx_halted;
        u16 exec_pending;
        u16 mc_reload_wait;     /* a multicast load request is pending */
+       u32 mc_list_valid;      /* True when the mclist is set */
+       u16 xceiver_state;      /* Current transceiver state. bitmapped */ 
+       u16 desired_state;      /* The state we want the transceiver to be in */ 
        atomic_t tx_count;      /* buffers left */
        struct wait_queue *event;
-       
+
        struct mc32_ring_desc tx_ring[TX_RING_LEN];     /* Host Transmit ring */
        struct mc32_ring_desc rx_ring[RX_RING_LEN];     /* Host Receive ring */
 
@@ -128,8 +172,6 @@ struct mc32_local
        u16 tx_ring_head;       /* index to tx en-queue end */
 
        u16 rx_ring_tail;       /* index to rx de-queue end */ 
-
-       u32 mc_list_valid;      /* True when the mclist is set */
 };
 
 /* The station (ethernet) address prefix, used for a sanity check. */
@@ -149,8 +191,14 @@ const struct mca_adapters_t mc32_adapters[] = {
 };
 
 
-/* Index to functions, as function prototypes. */
+/* Macros for ring index manipulations */ 
+static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
+
+static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
 
+
+/* Index to functions, as function prototypes. */
 extern int mc32_probe(struct device *dev);
 
 static int     mc32_probe1(struct device *dev, int ioaddr);
@@ -162,14 +210,15 @@ static int        mc32_close(struct device *dev);
 static struct  net_device_stats *mc32_get_stats(struct device *dev);
 static void    mc32_set_multicast_list(struct device *dev);
 static void    mc32_reset_multicast_list(struct device *dev);
-static void     mc32_flush_tx_ring(struct mc32_local *lp);
 
-/*
- * Check for a network adaptor of this type, and return '0' iff one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
+/**
+ * mc32_probe:
+ * @dev: device to probe
+ *
+ * Because MCA bus is a real bus and we can scan for cards we could do a
+ * single scan for all boards here. Right now we use the passed in device
+ * structure and scan for only one board. This needs fixing for modules
+ * in paticular.
  */
 
 __initfunc(int mc32_probe(struct device *dev))
@@ -203,15 +252,21 @@ __initfunc(int mc32_probe(struct device *dev))
        return -ENODEV;
 }
 
-/*
- * This is the real probe routine. Linux has a history of friendly device
- * probes on the ISA bus. A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
+/**
+ * mc32_probe1:
+ * @dev:  Device structure to fill in
+ * @slot: The MCA bus slot being used by this card
+ *
+ * Decode the slot data and configure the card structures. Having done this we
+ * can reset the card and configure it. The card does a full self test cycle
+ * in firmware so we have to wait for it to return and post us either a 
+ * failure case or some addresses we use to find the board internals.
  */
+
 __initfunc(static int mc32_probe1(struct device *dev, int slot))
 {
        static unsigned version_printed = 0;
-       int i;
+       int i, err;
        u8 POS;
        u32 base;
        struct mc32_local *lp;
@@ -347,20 +402,21 @@ __initfunc(static int mc32_probe1(struct device *dev, int slot))
         *      Grab the IRQ
         */
 
-       if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev))
-       {
-               printk("%s: unable to get IRQ %d.\n",
-                                  dev->name, dev->irq);
-               return -EAGAIN;
+       i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); 
+       if(i) {
+               printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+               return i; 
        }
 
+       request_region(dev->base_addr, MC32_IO_EXTENT, cardname);
+
        /* Initialize the device structure. */
        if (dev->priv == NULL) {
                dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
-               if (dev->priv == NULL)
+               if (dev->priv == NULL)  
                {
-                       free_irq(dev->irq, dev);
-                       return -ENOMEM;
+                       err = -ENOMEM;
+                       goto err_exit_irq; 
                }
        }
 
@@ -378,8 +434,8 @@ __initfunc(static int mc32_probe1(struct device *dev, int slot))
                if(i==1000)
                {
                        printk("%s: failed to boot adapter.\n", dev->name);
-                       free_irq(dev->irq, dev);
-                       return -ENODEV;
+                       err = -ENODEV; 
+                       goto err_exit_free;
                }
                udelay(1000);
                if(inb(dev->base_addr+2)&(1<<5))
@@ -393,8 +449,8 @@ __initfunc(static int mc32_probe1(struct device *dev, int slot))
                                base<0x0A?" test failure":"");
                else
                        printk("%s: unknown failure %d.\n", dev->name, base);
-               free_irq(dev->irq, dev);
-               return -ENODEV;
+               err = -ENODEV; 
+               goto err_exit_free;
        }
        
        base=0;
@@ -409,8 +465,8 @@ __initfunc(static int mc32_probe1(struct device *dev, int slot))
                        if(n>100)
                        {
                                printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i);
-                               free_irq(dev->irq, dev);
-                               return -ENODEV;
+                               err = -ENODEV;
+                               goto err_exit_free;
                        }
                }
 
@@ -446,56 +502,63 @@ __initfunc(static int mc32_probe1(struct device *dev, int slot))
        dev->get_stats          = mc32_get_stats;
        dev->set_multicast_list = mc32_set_multicast_list;
        
-       lp->rx_halted           = 1;
-       lp->tx_halted           = 1;
+       lp->xceiver_state = HALTED; 
+       
+       lp->tx_ring_tail=lp->tx_ring_head=0;
 
        /* Fill in the fields of the device structure with ethernet values. */
        ether_setup(dev);
        
        return 0;
+
+err_exit_free:
+       kfree(dev->priv);
+err_exit_irq:
+       free_irq(dev->irq, dev);
+       release_region(dev->base_addr, MC32_IO_EXTENT);
+       return err;
 }
 
-/*
- *     Polled command stuff 
+
+/**
+ *     mc32_ready_poll:
+ *     @dev:   The device to wait for
+ *     
+ *     Wait until the card becomes ready to accept a command via the
+ *     command register. This tells us nothing about the completion
+ *     status of any pending commands and takes very little time at all.
  */
  
-static void mc32_ring_poll(struct device *dev)
+static void mc32_ready_poll(struct device *dev)
 {
        int ioaddr = dev->base_addr;
        while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 }
 
 
-/*
- *     Send exec commands. This requires a bit of explaining.
+/**
+ *     mc32_command_nowait:
+ *     @dev: The 3c527 to issue the command to
+ *     @cmd: The command word to write to the mailbox
+ *     @data: A data block if the command expects one
+ *     @len: Length of the data block
  *
- *     You feed the card a command, you wait, it interrupts you get a 
- *     reply. All well and good. The complication arises because you use
- *     commands for filter list changes which come in at bh level from things
- *     like IPV6 group stuff.
- *
- *     We have a simple state machine
- *
- *     0       - nothing issued
- *     1       - command issued, wait reply
- *     2       - reply waiting - reader then goes to state 0
- *     3       - command issued, trash reply. In which case the irq
- *               takes it back to state 0
- */
-
-/*
- *     Send command from interrupt state
+ *     Send a command from interrupt state. If there is a command
+ *     currently being executed then we return an error of -1. It simply
+ *     isn't viable to wait around as commands may be slow. Providing we
+ *     get in, we busy wait for the board to become ready to accept the
+ *     command and issue it. We do not wait for the command to complete
+ *     --- the card will interrupt us when it's done.
  */
 
 static int mc32_command_nowait(struct device *dev, u16 cmd, void *data, int len)
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
        int ioaddr = dev->base_addr;
-       
+
        if(lp->exec_pending)
                return -1;
-               
+       
        lp->exec_pending=3;
        lp->exec_box->mbox=0;
        lp->exec_box->mbox=cmd;
@@ -509,9 +572,35 @@ static int mc32_command_nowait(struct device *dev, u16 cmd, void *data, int len)
 }
 
 
-/*
- *     Send command and block for results. On completion spot and reissue
- *     multicasts
+/**
+ *     mc32_command: 
+ *     @dev: The 3c527 card to issue the command to
+ *     @cmd: The command word to write to the mailbox
+ *     @data: A data block if the command expects one
+ *     @len: Length of the data block
+ *
+ *     Sends exec commands in a user context. This permits us to wait around
+ *     for the replies and also to wait for the command buffer to complete
+ *     from a previous command before we execute our command. After our 
+ *     command completes we will complete any pending multicast reload
+ *     we blocked off by hogging the exec buffer.
+ *
+ *     You feed the card a command, you wait, it interrupts you get a 
+ *     reply. All well and good. The complication arises because you use
+ *     commands for filter list changes which come in at bh level from things
+ *     like IPV6 group stuff.
+ *
+ *     We have a simple state machine
+ *
+ *     0       - nothing issued
+ *
+ *     1       - command issued, wait reply
+ *
+ *     2       - reply waiting - reader then goes to state 0
+ *
+ *     3       - command issued, trash reply. In which case the irq
+ *               takes it back to state 0
+ *
  */
   
 static int mc32_command(struct device *dev, u16 cmd, void *data, int len)
@@ -552,7 +641,7 @@ static int mc32_command(struct device *dev, u16 cmd, void *data, int len)
        cli();
 
        while(lp->exec_pending!=2)
-         sleep_on(&lp->event);
+               sleep_on(&lp->event);
        lp->exec_pending=0;
        restore_flags(flags);
        
@@ -564,89 +653,111 @@ static int mc32_command(struct device *dev, u16 cmd, void *data, int len)
         */
                
        if(lp->mc_reload_wait)
+       {
                mc32_reset_multicast_list(dev);
+       }
 
        return ret;
 }
 
 
-/*
- *     RX abort
- */
-static void mc32_rx_abort(struct device *dev)
-{
-       struct mc32_local *lp = (struct mc32_local *)dev->priv;
-       int ioaddr = dev->base_addr;
+/**
+ *     mc32_start_transceiver: 
+ *     @dev: The 3c527 card to issue the command to
+ *
+ *     This may be called from the interrupt state, where it is used
+ *     to restart the rx ring if the card runs out of rx buffers. 
+ *     
+ *     First, we check if it's ok to start the transceiver. We then show
+ *     the card where to start in the rx ring and issue the
+ *     commands to start reception and transmission. We don't wait
+ *     around for these to complete.
+ */ 
 
-       mc32_ring_poll(dev);    
-       
-       lp->rx_box->mbox=0;
-       outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);      /* Suspend reception */
-       
-       mc32_ring_poll(dev);    
-}
+static void mc32_start_transceiver(struct device *dev) {
 
-/*
- *     RX enable
- */
-static void mc32_rx_begin(struct device *dev)
-{
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
        int ioaddr = dev->base_addr;
 
-       /* Tell the card start reception at the first descriptor */ 
-       lp->rx_box->data[0]=lp->rx_chain; 
-       mc32_ring_poll(dev);    
-       
-       lp->rx_box->mbox=0;
-       outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);       /* GO */
+       /* Ignore RX overflow on device closure */ 
+       if (lp->desired_state==HALTED)  
+               return; 
 
-       mc32_ring_poll(dev);
-       lp->rx_halted=0;
-}
+       mc32_ready_poll(dev); 
 
-static void mc32_tx_abort(struct device *dev)
-{
-       struct mc32_local *lp = (struct mc32_local *)dev->priv;
-       int ioaddr = dev->base_addr;
-               
-       mc32_ring_poll(dev);
-       
        lp->tx_box->mbox=0;
-       outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);      /* Suspend */
+       lp->rx_box->mbox=0;
+
+       /* Give the card the offset to the post-EOL-bit RX descriptor */ 
+       lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; 
 
-       mc32_flush_tx_ring(lp); 
+       outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);      
 
-       mc32_ring_poll(dev);
+       mc32_ready_poll(dev); 
+       outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */ 
+       
+       /* We are not interrupted on start completion */ 
+       lp->xceiver_state=RUNNING; 
 }
 
-/*
- *     TX enable
- */
-static void mc32_tx_begin(struct device *dev)
+
+/**
+ *     mc32_halt_transceiver: 
+ *     @dev: The 3c527 card to issue the command to
+ *
+ *     We issue the commands to halt the card's transceiver. In fact,
+ *     after some experimenting we now simply tell the card to
+ *     suspend. When issuing aborts occasionally odd things happened.
+ *
+ *     We then sleep until the card has notified us that both rx and
+ *     tx have been suspended.
+ */ 
+
+static void mc32_halt_transceiver(struct device *dev) 
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
        int ioaddr = dev->base_addr;
-       
-       mc32_ring_poll(dev);
+       unsigned long flags;
+
+       mc32_ready_poll(dev);   
 
        lp->tx_box->mbox=0;
-       outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);      /* GO */
+       lp->rx_box->mbox=0;
 
-       mc32_ring_poll(dev);    
-       lp->tx_halted=0;
-}
+       outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);                      
+       mc32_ready_poll(dev); 
+       outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);      
+               
+       save_flags(flags);
+       cli();
+               
+       while(lp->xceiver_state!=HALTED) 
+               sleep_on(&lp->event); 
+               
+       restore_flags(flags);   
+} 
 
-       
-/*
- *     Load the rx ring.
+
+/**
+ *     mc32_load_rx_ring:
+ *     @dev: 3c527 to build the ring for
+ *
+ *     This initalises the on-card and driver datastructures to
+ *     the point where mc32_start_transceiver() can be called.
+ *
+ *     The card sets up the receive ring for us. We are required to use the
+ *     ring it provides although we can change the size of the ring.
+ *
+ *     We allocate an sk_buff for each ring entry in turn and
+ *     initalise its house-keeping info. At the same time, we read
+ *     each 'next' pointer in our rx_ring array. This reduces slow
+ *     shared-memory reads and makes it easy to access predecessor
+ *     descriptors.
+ *
+ *     We then set the end-of-list bit for the last entry so that the
+ *     card will know when it has run out of buffers.
  */
+        
 static int mc32_load_rx_ring(struct device *dev)
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
@@ -681,23 +792,55 @@ static int mc32_load_rx_ring(struct device *dev)
 
        lp->rx_ring[i-1].p->control |= CONTROL_EOL;
 
-       lp->rx_ring_tail=0; 
+       lp->rx_ring_tail=0;
 
-       lp->rx_box->mbox=0;   /* check: needed ? */
        return 0;
 }      
 
-static void mc32_flush_rx_ring(struct mc32_local *lp)
+
+/**
+ *     mc32_flush_rx_ring:
+ *     @lp: Local data of 3c527 to flush the rx ring of
+ *
+ *     Free the buffer for each ring slot. This may be called 
+ *      before mc32_load_rx_ring(), eg. on error in mc32_open().
+ */
+
+static void mc32_flush_rx_ring(struct device *dev)
 {
+       struct mc32_local *lp = (struct mc32_local *)dev->priv;
+       
+       struct sk_buff *skb;
        int i; 
-       for(i=0; i < RX_RING_LEN; i++) { 
-               kfree_skb(lp->rx_ring[i].skb);
+
+       for(i=0; i < RX_RING_LEN; i++) 
+       { 
+               skb = lp->rx_ring[i].skb;
+               if (skb!=NULL) {
+                       kfree_skb(skb);
+                       skb=NULL; 
+               }
                lp->rx_ring[i].p=NULL; 
        } 
 }
 
 
-/* Load the addresses of the on-card buffer descriptors into main memory */ 
+/**
+ *     mc32_load_tx_ring: 
+ *     @dev: The 3c527 card to issue the command to
+ *
+ *     This sets up the host transmit data-structures. 
+ *
+ *     First, we obtain from the card it's current postion in the tx
+ *     ring, so that we will know where to begin transmitting
+ *     packets.
+ *     
+ *     Then, we read the 'next' pointers from the on-card tx ring into
+ *     our tx_ring array to reduce slow shared-mem reads. Finally, we
+ *     intitalise the tx house keeping variables.
+ * 
+ */ 
+
 static void mc32_load_tx_ring(struct device *dev)
 { 
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
@@ -707,9 +850,6 @@ static void mc32_load_tx_ring(struct device *dev)
 
        tx_base=lp->tx_box->data[0]; 
 
-       /* Read the 'next' pointers from the on-card list into      */
-       /* our tx_ring array so we can reduce slow shared-mem reads */ 
-
        for(i=0;i<lp->tx_len;i++) 
        {
                p=bus_to_virt(lp->base+tx_base);
@@ -719,16 +859,31 @@ static void mc32_load_tx_ring(struct device *dev)
                tx_base=p->next;
        }
 
+       /* -1 so that tx_ring_head cannot "lap" tx_ring_tail,           */
+       /* which would be bad news for mc32_tx_ring as cur. implemented */ 
+
+       atomic_set(&lp->tx_count, TX_RING_LEN-1); 
        lp->tx_ring_head=lp->tx_ring_tail=0; 
 } 
 
-static void mc32_flush_tx_ring(struct mc32_local *lp)
+
+/**
+ *     mc32_flush_tx_ring:
+ *     @lp: Local data of 3c527 to flush the tx ring of
+ *
+ *     We have to consider two cases here. We want to free the pending
+ *     buffers only. If the ring buffer head is past the start then the
+ *     ring segment we wish to free wraps through zero. The tx ring 
+ *     house-keeping variables are then reset.
+ */
+
+static void mc32_flush_tx_ring(struct device *dev)
 {
+       struct mc32_local *lp = (struct mc32_local *)dev->priv;
        
        if(lp->tx_ring_tail!=lp->tx_ring_head)
        {
-               int i;
-       
+               int i;  
                if(lp->tx_ring_tail < lp->tx_ring_head)
                {
                        for(i=lp->tx_ring_tail;i<lp->tx_ring_head;i++)
@@ -755,29 +910,37 @@ static void mc32_flush_tx_ring(struct mc32_local *lp)
                }
        }
        
-       /* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */
-       /* which would be bad news for mc32_tx_ring as cur. implemented */ 
-       atomic_set(&lp->tx_count, TX_RING_LEN-1); 
+       atomic_set(&lp->tx_count, 0); 
        lp->tx_ring_tail=lp->tx_ring_head=0;
 }
        
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
+
+/**
+ *     mc32_open
+ *     @dev: device to open
+ *
+ *     The user is trying to bring the card into ready state. This requires
+ *     a brief dialogue with the card. Firstly we enable interrupts and then
+ *     'indications'. Without these enabled the card doesn't bother telling
+ *     us what it has done. This had me puzzled for a week.
+ *
+ *     We configure the number of card descriptors, then load the network
+ *     address and multicast filters. Turn on the workaround mode. This
+ *     works around a bug in the 82586 - it asks the firmware to do
+ *     so. It has a performance (latency) hit but is needed on busy
+ *     [read most] lans. We load the ring with buffers then we kick it
+ *     all off.
  */
 
 static int mc32_open(struct device *dev)
 {
        int ioaddr = dev->base_addr;
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
-       u16 zero_word=0;
        u8 one=1;
        u8 regs;
        u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
-       
-       dev->tbusy = 0;
-       dev->interrupt = 0;
-       dev->start = 1;
+
+       MOD_INC_USE_COUNT;
 
        /*
         *      Interrupts enabled
@@ -795,18 +958,20 @@ static int mc32_open(struct device *dev)
        mc32_command(dev, 4, &one, 2);
 
        /*
-        *      Send the command sequence "abort, resume" for RX and TX.
-        *      The abort cleans up the buffer chains if needed.
+        *      Poke it to make sure it's really dead. 
         */
 
-       mc32_rx_abort(dev);
-       mc32_tx_abort(dev);
-       
-       /* Ask card to set up on-card descriptors to our spec */ 
+       mc32_halt_transceiver(dev); 
+       mc32_flush_tx_ring(dev); 
+
+       /* 
+        *      Ask card to set up on-card descriptors to our spec 
+        */ 
 
        if(mc32_command(dev, 8, descnumbuffs, 4)) { 
                printk("%s: %s rejected our buffer configuration!\n",
                       dev->name, cardname);
+               mc32_close(dev); 
                return -ENOBUFS; 
        }
        
@@ -823,34 +988,50 @@ static int mc32_open(struct device *dev)
        
        /* Set the filters */
        mc32_set_multicast_list(dev);
-       
-       /* Issue the 82586 workaround command - this is for "busy lans",
-          but basically means for all lans now days - has a performance
-          cost but best set */
-          
-       /* mc32_command(dev, 0x0D, &zero_word, 2); */   /* 82586 bug workaround on  */
-
-       /* Load the ring we just initialised */
+                  
+       if (WORKAROUND_82586) { 
+               u16 zero_word=0;
+               mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */
+       }
 
        mc32_load_tx_ring(dev);
        
-       if(mc32_load_rx_ring(dev))
+       if(mc32_load_rx_ring(dev)) 
        {
                mc32_close(dev);
                return -ENOBUFS;
        }
-       
-       /* And the resume command goes last */
 
-       mc32_rx_begin(dev);
-       mc32_tx_begin(dev);
+       lp->desired_state = RUNNING; 
        
-       MOD_INC_USE_COUNT;
+       /* And finally, set the ball rolling... */
+
+       mc32_start_transceiver(dev);
+
+       dev->tbusy = 0;
+       dev->interrupt = 0;
+       dev->start = 1;
 
        return 0;
 }
 
 
+/**
+ *     mc32_send_packet:
+ *     @skb: buffer to transmit
+ *     @dev: 3c527 to send it out of
+ *
+ *     Transmit a buffer. This normally means throwing the buffer onto
+ *     the transmit queue as the queue is quite large. If the queue is
+ *     full then we set tx_busy and return. Once the interrupt handler
+ *     gets messages telling it to reclaim transmit queue entries we will
+ *     clear tx_busy and the kernel will start calling this again.
+ *
+ *     We use cli rather than spinlocks. Since I have no access to an SMP
+ *     MCA machine I don't plan to change it. It is probably the top 
+ *     performance hit for this driver on SMP however.
+ */
+
 static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
@@ -898,8 +1079,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
                /* P is the last sending/sent buffer as a pointer */
                p=lp->tx_ring[lp->tx_ring_head].p; 
                
-               lp->tx_ring_head++;
-               lp->tx_ring_head&=(TX_RING_LEN-1); 
+               lp->tx_ring_head=next_tx(lp->tx_ring_head); 
 
                /* NP is the buffer we will be loading */
                np=lp->tx_ring[lp->tx_ring_head].p; 
@@ -907,7 +1087,7 @@ static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
                /* We will need this to flush the buffer out */
                lp->tx_ring[lp->tx_ring_head].skb=skb;
           
-               np->length = (skb->len < 60) ? 60 : skb->len; 
+               np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; 
                        
                np->data        = virt_to_bus(skb->data);
                np->status      = 0;
@@ -923,58 +1103,76 @@ static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
        return 0;
 }
 
+
+/**
+ *     mc32_update_stats:
+ *     @dev: 3c527 to service
+ *
+ * 
+ *     Query and reset the on-card stats. There's the small possibility
+ *     of a race here, which would result in an underestimation of
+ *     actual errors. As such, we'd prefer to keep all our stats
+ *     collection in software. As a rule, we do. However it can't be
+ *     used for rx errors and collisions as, by default, the card discards
+ *     bad rx packets. 
+ *
+ *     Setting the SAV BP in the rx filter command supposedly
+ *     stops this behaviour. However, testing shows that it only seems to
+ *     enable the collation of on-card rx statistics --- the driver
+ *     never sees an RX descriptor with an error status set.
+ *
+ */
+
 static void mc32_update_stats(struct device *dev)
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
        volatile struct mc32_stats *st = lp->stats; 
-       
-        u32 rx_errors=0; 
-
-       /* The databook isn't at all clear about whether      */ 
-        /* the host should suspend rx/tx here to avoid races. */
-        /* Assuming that it should, my code here is probably  */
-        /* a bit dodgey - RP                                  */
-
-       /* TO DO: count rx_errors, tx_errors, figure out how to measure colisions */     
-
-       /* RX */ 
 
-       rx_errors += lp->net_stats.rx_crc_errors += st->rx_crc_errors;
-       st->rx_crc_errors = 0; 
-
-       rx_errors += lp->net_stats.rx_length_errors += st->rx_tooshort_errors;
-       st->rx_tooshort_errors = 0; 
-
-       rx_errors += lp->net_stats.rx_length_errors += st->rx_toolong_errors;
-       st->rx_toolong_errors = 0; 
-
-       rx_errors += lp->net_stats.rx_fifo_errors += st->rx_overrun_errors; 
-       st->rx_overrun_errors = 0; 
-
-       rx_errors += lp->net_stats.rx_frame_errors += st->rx_alignment_errors;
-       st->rx_alignment_errors = 0; 
-
-       rx_errors += lp->net_stats.rx_missed_errors += st->rx_outofresource_errors;
-       st->rx_outofresource_errors = 0; 
-
-       lp->net_stats.rx_errors = rx_errors;
-       
-        /* TX */ 
-
-       /* How to count collisions when you're only 
-           told frames which had 1 or 2-15? - RP */
-       
-       lp->net_stats.collisions += (st->tx_max_collisions * 16); 
-       st->tx_max_collisions = 0;  
-
-       lp->net_stats.tx_carrier_errors += st->tx_carrier_errors; 
-       st->tx_carrier_errors = 0; 
+       u32 rx_errors=0; 
+      
+       rx_errors+=lp->net_stats.rx_crc_errors   +=st->rx_crc_errors;         
+                                                  st->rx_crc_errors=0;
+       rx_errors+=lp->net_stats.rx_fifo_errors  +=st->rx_overrun_errors;   
+                                                  st->rx_overrun_errors=0; 
+       rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; 
+                                                  st->rx_alignment_errors=0;
+       rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; 
+                                                  st->rx_tooshort_errors=0;
+       rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
+                                                  st->rx_outofresource_errors=0; 
+        lp->net_stats.rx_errors=rx_errors; 
+                                                  
+       /* Number of packets which saw one collision */
+       lp->net_stats.collisions+=st->dataC[10];
+       st->dataC[10]=0; 
+
+       /* Number of packets which saw 2--15 collisions */ 
+       lp->net_stats.collisions+=st->dataC[11]; 
+       st->dataC[11]=0; 
+}      
 
-       lp->net_stats.tx_fifo_errors += st->tx_underrun_errors; 
-       st->tx_underrun_errors = 0; 
-       
-}
 
+/**
+ *     mc32_rx_ring:
+ *     @dev: 3c527 that needs its receive ring processing
+ *
+ *
+ *     We have received one or more indications from the card that a
+ *     receive has completed. The buffer ring thus contains dirty
+ *     entries. We walk the ring by iterating over the circular rx_ring
+ *     array, starting at the next dirty buffer (which happens to be the
+ *     one we finished up at last time around).
+ *
+ *     For each completed packet, we will either copy it and pass it up
+ *     the stack or, if the packet is near MTU sized, we allocate
+ *     another buffer and flip the old one up the stack.
+ * 
+ *     We must succeed in keeping a buffer on the ring. If neccessary we
+ *     will toss a received packet rather than lose a ring entry. Once
+ *     the first uncompleted descriptor is found, we move the
+ *     End-Of-List bit to include the buffers just processed.
+ *
+ */
 
 static void mc32_rx_ring(struct device *dev)
 {
@@ -999,10 +1197,6 @@ static void mc32_rx_ring(struct device *dev)
                        struct sk_buff *skb; 
                        struct sk_buff *newskb; 
 
-#ifdef DEBUG_IRQ 
-                       printk("skb_header %p has frame, x==%d\n", p, x); 
-#endif 
-
                        /* Try to save time by avoiding a copy on big frames */
 
                        if ((length > RX_COPYBREAK) 
@@ -1019,18 +1213,9 @@ static void mc32_rx_ring(struct device *dev)
                        {
                                skb=dev_alloc_skb(length+2);  
 
-                               if(skb==NULL) 
-                               { 
+                               if(skb==NULL) {
                                        lp->net_stats.rx_dropped++; 
-
-                                       p->length = 1532; 
-                                       p->status = 0;
-                                       p->control = 0;                 
-                                       
-                                       rx_ring_tail++;
-                                       rx_ring_tail&=(RX_RING_LEN-1); 
-
-                                       continue; /* better to use a goto? */ 
+                                       goto dropped; 
                                }
 
                                skb_reserve(skb,2);
@@ -1044,36 +1229,42 @@ static void mc32_rx_ring(struct device *dev)
                        lp->net_stats.rx_bytes+=skb->len; 
                        netif_rx(skb); 
                }
-               else    /* NOT COMPLETED_OK */
-               {
-                       /* There was some sort of reception error.     */
-                        /* This case should never occur unless         */
-                       /* the card is asked to upload damaged frames.  */
-  
-                       /* do nothing */ 
-               }
 
+       dropped:
                p->length = 1532; 
                p->status = 0;
-               p->control = 0;                 
-
-               rx_ring_tail++;
-               rx_ring_tail&=(RX_RING_LEN-1); 
+               
+               rx_ring_tail=next_rx(rx_ring_tail); 
        }
         while(x++<48);  
 
-       /* If there was actually a frame to be processed, */ 
-       /* place the EL bit at the descriptor prior to the one to be filled next */ 
+       /* If there was actually a frame to be processed, place the EOL bit */ 
+       /* at the descriptor prior to the one to be filled next */ 
 
-       if (rx_ring_tail != rx_old_tail) { 
-               lp->rx_ring[(rx_ring_tail-1)&(RX_RING_LEN-1)].p->control |=  CONTROL_EOL; 
-               lp->rx_ring[(rx_old_tail-1)&(RX_RING_LEN-1)].p->control  &= ~CONTROL_EOL; 
+       if (rx_ring_tail != rx_old_tail) 
+       { 
+               lp->rx_ring[prev_rx(rx_ring_tail)].p->control |=  CONTROL_EOL; 
+               lp->rx_ring[prev_rx(rx_old_tail)].p->control  &= ~CONTROL_EOL; 
 
                lp->rx_ring_tail=rx_ring_tail; 
        }
 }
 
 
+/**
+ *     mc32_tx_ring:
+ *     @dev: 3c527 that needs its transmit ring processing
+ *
+ *
+ *     This operates in a similar fashion to mc32_rx_ring. We iterate
+ *     over the transmit ring. For each descriptor which has been
+ *     processed by the card, we free its associated buffer and note
+ *     any errors. This continues until the transmit ring is emptied
+ *     or we reach a descriptor that hasn't yet been processed by the
+ *     card.
+ * 
+ */
+
 static void mc32_tx_ring(struct device *dev) {
 
   struct mc32_local *lp=(struct mc32_local *)dev->priv;
@@ -1085,7 +1276,7 @@ static void mc32_tx_ring(struct device *dev) {
   {   
          u16 t; 
 
-         t=(lp->tx_ring_tail+1)&(TX_RING_LEN-1); 
+         t=next_tx(lp->tx_ring_tail); 
          np=lp->tx_ring[t].p; 
 
          if(!(np->status & (1<<7))) { /* Not COMPLETED */ 
@@ -1097,9 +1288,20 @@ static void mc32_tx_ring(struct device *dev) {
          if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
          {
                  lp->net_stats.tx_errors++;   
-                 
-                  /* Error stats are stored on-card to be picked up by
-                    mc32_update_stats() - RP */
+
+                 switch(np->status&0x0F)
+                 {
+                 case 1:
+                         lp->net_stats.tx_aborted_errors++;break; /* Max collisions */ 
+                 case 2:
+                         lp->net_stats.tx_fifo_errors++;break;
+                 case 3:
+                         lp->net_stats.tx_carrier_errors++;break;
+                 case 4:
+                         lp->net_stats.tx_window_errors++;break;  /* CTS Lost */ 
+                 case 5:
+                         lp->net_stats.tx_aborted_errors++;break; /* Transmit timeout */ 
+                 }
          }
          
          
@@ -1115,12 +1317,32 @@ static void mc32_tx_ring(struct device *dev) {
 
          lp->tx_ring_tail=t; 
   }
+
 } 
 
-/*
- * The typical workload of the driver:
- *   Handle the network interface interrupts.
+
+/**
+ *     mc32_interrupt:
+ *     @irq: Interrupt number
+ *     @dev_id: 3c527 that requires servicing
+ *     @regs: Registers (unused)
+ *
+ *
+ *     An interrupt is raised whenever the 3c527 writes to the command
+ *     register. This register contains the message it wishes to send us
+ *     packed into a single byte field. We keep reading status entries
+ *     until we have processed all the control items, but simply count
+ *     transmit and receive reports. When all reports are in we empty the
+ *     transceiver rings as appropriate. This saves the overhead of
+ *     multiple command requests.
+ *
+ *     Because MCA is level-triggered, we shouldn't miss indications.
+ *     Therefore, we needn't ask the card to suspend interrupts within
+ *     this handler. The card receives an implicit acknowledgment of the
+ *     current interrupt when we read the command register.
+ *
  */
+
 static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
        struct device *dev = dev_id;
@@ -1128,12 +1350,12 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
        int ioaddr, status, boguscount = 0;
        int rx_event = 0;
        int tx_event = 0; 
-       int must_restart = 0;
        
        if (dev == NULL) {
                printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
                return;
        }
+
        dev->interrupt = 1;
  
        ioaddr = dev->base_addr;
@@ -1161,11 +1383,7 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                                break;
                        case 3: /* Halt */
                        case 4: /* Abort */
-                               lp->tx_halted=1;
-                               wake_up(&lp->event);
-                               break;
-                       case 5:
-                               lp->tx_halted=0;
+                               lp->xceiver_state |= TX_HALTED; 
                                wake_up(&lp->event);
                                break;
                        default:
@@ -1179,22 +1397,17 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                        case 2: /* RX */
                                rx_event=1; 
                                break;
-                       case 3:
-                       case 4:
-                               lp->rx_halted=1;
-                               wake_up(&lp->event);
-                               break;
-                       case 5:
-                               lp->rx_halted=0;
+                       case 3: /* Halt */
+                       case 4: /* Abort */
+                               lp->xceiver_state |= RX_HALTED;
                                wake_up(&lp->event);
                                break;
                        case 6:
                                /* Out of RX buffers stat */
-                               /* Must restart */
+                               /* Must restart rx */
                                lp->net_stats.rx_dropped++;
-                               must_restart = 1;       /* To restart */
-                               rx_event = 1; 
-
+                               mc32_rx_ring(dev); 
+                               mc32_start_transceiver(dev); 
                                break;
                        default:
                                printk("%s: strange rx ack %d\n", 
@@ -1203,60 +1416,48 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                status>>=3;
                if(status&1)
                {
-                       
+
                        /* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */
                        
-                       if(lp->exec_pending!=3) 
-                       {
+                       if(lp->exec_pending!=3) {
                                lp->exec_pending=2;
                                wake_up(&lp->event);
                        }
                        else 
-                       {
-                               lp->exec_pending=0;
-                               wake_up(&lp->event);
+                       {                               
+                               lp->exec_pending=0;
+
+                               /* A new multicast set may have been
+                                  blocked while the old one was
+                                  running. If so, do it now. */
+                                  
+                               if (lp->mc_reload_wait) 
+                                       mc32_reset_multicast_list(dev);
+                               else 
+                                       wake_up(&lp->event);                           
                        }
                }
                if(status&2)
                {
                        /*
-                        *      Update the stats as soon as
-                        *      we have it flagged and can 
-                        *      send an immediate reply (CRR set)
+                        *      We get interrupted once per
+                        *      counter that is about to overflow. 
                         */
-       
-                       if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)
-                       {
-                               mc32_update_stats(dev);
-                               outb(0, ioaddr+HOST_CMD);
-                       }
-                       
+
+                       mc32_update_stats(dev);                 
                }
        }
 
 
-       if(tx_event) { 
-               mc32_tx_ring(dev);
-       }
-
        /*
-        *      Process the receive ring and restart if the card 
-        *      stopped due to a shortage of free buffers.
+        *      Process the transmit and receive rings 
          */
+
+       if(tx_event) 
+               mc32_tx_ring(dev);
         
-       if(rx_event) {
+       if(rx_event) 
                mc32_rx_ring(dev);
-               if (must_restart) { 
-                       u16 rx_prev_tail=(lp->rx_ring_tail-1)&(RX_RING_LEN-1);
-
-                       /* Restart at the current rx_ring_tail */ 
-                       lp->rx_box->data[0]=lp->rx_ring[rx_prev_tail].p->next; 
-                       lp->rx_box->mbox=0; 
-
-                       while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); 
-                       outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); /* Re-enable receives */
-               }
-       }
 
        dev->interrupt = 0;     
 
@@ -1264,54 +1465,80 @@ static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 }
 
 
-/* The inverse routine to mc32_open(). */
+/**
+ *     mc32_close:
+ *     @dev: 3c527 card to shut down
+ *
+ *     The 3c527 is a bus mastering device. We must be careful how we
+ *     shut it down. It may also be running shared interrupt so we have
+ *     to be sure to silence it properly
+ *
+ *     We indicate that the card is closing to the rest of the
+ *     driver.  Otherwise, it is possible that the card may run out
+ *     of receive buffers and restart the transceiver while we're
+ *     trying to close it.
+ * 
+ *     We abort any receive and transmits going on and then wait until
+ *     any pending exec commands have completed in other code threads.
+ *     In theory we can't get here while that is true, in practice I am
+ *     paranoid
+ *
+ *     We turn off the interrupt enable for the board to be sure it can't
+ *     intefere with other devices.
+ */
 
 static int mc32_close(struct device *dev)
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
+
        int ioaddr = dev->base_addr;
        u8 regs;
        u16 one=1;
 
+       dev->tbusy = 1;
+       dev->start = 0;
+
+       lp->desired_state = HALTED;
+
        /*
         *      Send the indications on command (handy debug check)
         */
 
        mc32_command(dev, 4, &one, 2);
 
-       /* Abort RX and Abort TX */
-       
-       mc32_rx_abort(dev);     
-       mc32_tx_abort(dev);
+       /* Shut down the transceiver */
+
+       mc32_halt_transceiver(dev); 
        
        /* Catch any waiting commands */
        
        while(lp->exec_pending==1)
                sleep_on(&lp->event);
-               
+              
        /* Ok the card is now stopping */       
        
        regs=inb(ioaddr+HOST_CTRL);
        regs&=~HOST_CTRL_INTE;
        outb(regs, ioaddr+HOST_CTRL);
 
-       mc32_flush_rx_ring(lp);
-       mc32_flush_tx_ring(lp);
-       
-       dev->tbusy = 1;
-       dev->start = 0;
-
-       /* Update the statistics here. */
+       mc32_flush_rx_ring(dev);
+       mc32_flush_tx_ring(dev);
+               
+       mc32_update_stats(dev); 
 
        MOD_DEC_USE_COUNT;
 
        return 0;
-
 }
 
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
+
+/**
+ *     mc32_get_stats:
+ *     @dev: The 3c527 card to handle
+ *
+ *     We've collected all the stats we can in software already. Now
+ *     it's time to update those kept on-card and return the lot. 
+ * 
  */
 
 static struct net_device_stats *mc32_get_stats(struct device *dev)
@@ -1325,25 +1552,42 @@ static struct net_device_stats *mc32_get_stats(struct device *dev)
        return &lp->net_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.
+
+/**
+ *     do_mc32_set_multicast_list:
+ *     @dev: 3c527 device to load the list on
+ *     @retry: indicates this is not the first call. 
+ *
+ *
+ *     Actually set or clear the multicast filter for this adaptor. The
+ *     locking issues are handled by this routine. We have to track
+ *     state as it may take multiple calls to get the command sequence
+ *     completed. We just keep trying to schedule the loads until we
+ *     manage to process them all.
+ * 
+ *     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. 
+ *
+ *     See mc32_update_stats() regards setting the SAV BP bit. 
+ *
  */
+
 static void do_mc32_set_multicast_list(struct device *dev, int retry)
 {
        struct mc32_local *lp = (struct mc32_local *)dev->priv;
-       u16 filt;
+       u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ 
 
        if (dev->flags&IFF_PROMISC)
                /* Enable promiscuous mode */
-               filt = 1;
+               filt |= 1;
        else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)
        {
                dev->flags|=IFF_PROMISC;
-               filt = 1;
+               filt |= 1;
        }
        else if(dev->mc_count)
        {
@@ -1352,9 +1596,7 @@ static void do_mc32_set_multicast_list(struct device *dev, int retry)
                struct dev_mc_list *dmc=dev->mc_list;
                
                int i;
-               
-               filt = 0;
-               
+              
                if(retry==0)
                        lp->mc_list_valid = 0;
                if(!lp->mc_list_valid)
@@ -1377,21 +1619,41 @@ static void do_mc32_set_multicast_list(struct device *dev, int retry)
                        lp->mc_list_valid=1;
                }
        }
-       else 
-       {
-               filt = 0;
-       }
-       if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+       
+       if(mc32_command_nowait(dev, 0, &filt, 2)==-1) 
        {
                lp->mc_reload_wait = 1;
+       } 
+       else { 
+               lp->mc_reload_wait = 0;
        }
 }
 
+
+/**
+ *     mc32_set_multicast_list:
+ *     @dev: The 3c527 to use
+ *
+ *     Commence loading the multicast list. This is called when the kernel
+ *     changes the lists. It will override any pending list we are trying to
+ *     load.
+ */
+
 static void mc32_set_multicast_list(struct device *dev)
 {
        do_mc32_set_multicast_list(dev,0);
 }
 
+
+/**
+ *     mc32_reset_multicast_list:
+ *     @dev: The 3c527 to use
+ *
+ *     Attempt the next step in loading the multicast lists. If this attempt
+ *     fails to complete then it will be scheduled and this function called
+ *     again later from elsewhere.
+ */
+
 static void mc32_reset_multicast_list(struct device *dev)
 {
        do_mc32_set_multicast_list(dev,1);
@@ -1406,6 +1668,14 @@ static struct device this_device = {
        0, 0,  /* I/O address, IRQ */
        0, 0, 0, NULL, mc32_probe };
 
+/**
+ *     init_module:
+ *
+ *     Probe and locate a 3c527 card. This really should probe and locate
+ *     all the 3c527 cards in the machine not just one of them. Yes you can
+ *     insmod multiple modules for now but it's a hack.
+ */
+
 int init_module(void)
 {
        int result;
@@ -1416,6 +1686,17 @@ int init_module(void)
        return 0;
 }
 
+/**
+ *     cleanup_module:
+ *
+ *     Unloading time. We release the MCA bus resources and the interrupt
+ *     at which point everything is ready to unload. The card must be stopped
+ *     at this point or we would not have been called. When we unload we
+ *     leave the card stopped but not totally shut down. When the card is
+ *     initialized it must be rebooted or the rings reloaded before any
+ *     transmit operations are allowed to start scribbling into memory.
+ */
+
 void cleanup_module(void)
 {
        int slot;
@@ -1425,8 +1706,6 @@ void cleanup_module(void)
 
        /*
         * If we don't do this, we can't re-insmod it later.
-        * Release irq/dma here, when you have jumpered versions and
-        * allocate them in mc32_probe1().
         */
         
        if (this_device.priv)
@@ -1438,6 +1717,7 @@ void cleanup_module(void)
                kfree_s(this_device.priv, sizeof(struct mc32_local));
        }
        free_irq(this_device.irq, &this_device);
+       release_region(this_device.base_addr, MC32_IO_EXTENT);
 }
 
 #endif /* MODULE */
index e517345974acdc398d85ec3745594c2cdb07dcab..a696d0ef5c9a31335a6d9376edeb0a465326b0a9 100644 (file)
 
 #define HOST_RAMPAGE           8
 
+#define RX_HALTED (1<<0)
+#define TX_HALTED (1<<1)  
+#define HALTED (RX_HALTED | TX_HALTED)
+#define RUNNING 0
 
 struct mc32_mailbox
 {
@@ -53,7 +57,7 @@ struct mc32_stats
        u32     rx_toolong_errors   __attribute((packed));
        u32     rx_outofresource_errors  __attribute((packed)); 
 
-       u32     rx_discarded   __attribute((packed));  // via card pattern match filter
+       u32     rx_discarded   __attribute((packed));  /* via card pattern match filter */ 
 
        /* TX Errors */
        u32     tx_max_collisions __attribute((packed)); 
index 9198c667a9fd781840ccb306a54614c81d29633a..84687108bb5dfe808ef763adcc3480a41604e55f 100644 (file)
@@ -282,6 +282,11 @@ static void irtty_close(struct tty_struct *tty)
        tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
        tty->disc_data = 0;
        
+       /* We are not using any dongle anymore! */
+       if (self->dongle)
+               irda_device_dongle_cleanup(self->dongle);
+       self->dongle = NULL;
+
        /* Remove netdevice */
        if (self->netdev) {
                rtnl_lock();
@@ -291,11 +296,6 @@ static void irtty_close(struct tty_struct *tty)
                kfree(self->netdev);
        }
        
-       /* We are not using any dongle anymore! */
-       if (self->dongle)
-               irda_device_dongle_cleanup(self->dongle);
-       self->dongle = NULL;
-
        /* Remove speed changing task if any */
        if (self->task)
                irda_task_delete(self->task);
index d0ee3aab3626e57d94f7c6806d12fc9d2ba90c48..c6c75da19c90771a1d2ac8c17537fa3fcbfd601c 100644 (file)
        - Removed unused code
        - Made more functions static and __init
 
+       LK1.2.8 (Ion Badulescu)
+       - Quell bogus error messages, inform about the Tx threshold
+       - Removed #ifdef CONFIG_PCI, this driver is PCI only
+
 TODO:
        - implement tx_timeout() properly
        - support ethtool
@@ -71,7 +75,7 @@ static const char version2[] =
 " Updates and info at http://www.scyld.com/network/starfire.html\n";
 
 static const char version3[] =
-" (unofficial 2.2.x kernel port, version 1.2.7, February 26, 2001)\n";
+" (unofficial 2.2.x kernel port, version 1.2.8, March 7, 2001)\n";
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -420,7 +424,6 @@ pci_register_driver(struct pci_driver *drv)
 {
        struct pci_dev *dev;
        int count = 0, found, i;
-#ifdef CONFIG_PCI
        list_add_tail(&drv->node, &pci_drivers);
        for (dev = pci_devices; dev; dev = dev->next) {
                found = 0;
@@ -430,7 +433,6 @@ pci_register_driver(struct pci_driver *drv)
                if (!found)
                        count += pci_announce_device(drv, dev);
        }
-#endif
        return count;
 }
 
@@ -439,7 +441,6 @@ pci_unregister_driver(struct pci_driver *drv)
 {
        struct pci_dev *dev;
        int i, found;
-#ifdef CONFIG_PCI
        list_del(&drv->node);
        for (dev = pci_devices; dev; dev = dev->next) {
                found = 0;
@@ -454,7 +455,6 @@ pci_unregister_driver(struct pci_driver *drv)
                        drvmap[i].dev = NULL;
                }
        }
-#endif
 }
 
 static inline int pci_module_init(struct pci_driver *drv)
@@ -579,6 +579,7 @@ enum intr_status_bits {
        /* not quite bits */
        IntrRxDone=IntrRxQ2Done | IntrRxQ1Done,
        IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low,
+       IntrNormalMask=0xf0, IntrAbnormalMask=0x3f0e,
 };
 
 /* Bits in the RxFilterMode register. */
@@ -1557,9 +1558,12 @@ static void netdev_error(struct net_device *dev, int intr_status)
                get_stats(dev);
        }
        /* Came close to underrunning the Tx FIFO, increase threshold. */
-       if (intr_status & IntrTxDataLow)
+       if (intr_status & IntrTxDataLow) {
                writel(++np->tx_threshold, dev->base_addr + TxThreshold);
-       if ((intr_status & ~(IntrAbnormalSummary|IntrLinkChange|IntrStatsMax|IntrTxDataLow|1)) && debug)
+               printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n",
+                      np->tx_threshold * 16);
+       }
+       if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug)
                printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
                       dev->name, intr_status);
        /* Hmmmmm, it's not clear how to recover from DMA faults. */
index 63bf3e7d1a21daa8e64eb315df3156b1308a120f..777556537f7a154990052f4e8f33f149e18798f4 100644 (file)
@@ -6,7 +6,7 @@
                     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
 
-   Copyright (C) 1999-2000 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By:     Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000      Andre Hedrick <andre@suse.com>
                  systems.
    12/09/2000  - release previously allocated resources on failure at
                 tw_allocate_memory (acme)
+   1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when
+                 controller status is non-zero.
+                 Added handling of request_sense opcode.
+                 Fix possible null pointer dereference in
+                 tw_reset_device_extension()
+   1.02.00.004 - Add support for device id of 3ware 7000 series controllers.
+                 Make tw_setfeature() call with interrupts disabled.
+                 Register interrupt handler before enabling interrupts.
+                 Clear attention interrupt before draining aen queue. 
 */
 
 #include <linux/module.h>
@@ -119,7 +128,7 @@ struct proc_dir_entry tw_scsi_proc_entry = {
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.002";
+char *tw_driver_version="1.02.00.004";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -589,173 +598,178 @@ int tw_findcards(Scsi_Host_Template *tw_host)
        struct pci_dev *tw_pci_dev = pci_devices;
        u32 status_reg_value;
        unsigned char c = 1;
+       int i;
+       u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
        dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
-       while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) {
-               /* Prepare temporary device extension */
-               tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
-               if (tw_dev == NULL) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
-                       continue;
-               }
-               memset(tw_dev, 0, sizeof(TW_Device_Extension));
-
-               error = tw_initialize_device_extension(tw_dev);
-               if (error) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-
-               /* Calculate the cards register addresses */
-               tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
-               tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15);
-               tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4);
-               tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8);
-               tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC);
-               /* Save pci_dev struct to device extension */
-               tw_dev->tw_pci_dev = tw_pci_dev;
-
-               /* Poll status register for 60 secs for 'Controller Ready' flag */
-               if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-
-               /* Disable interrupts on the card */
-               tw_disable_interrupts(tw_dev);
-
-               while (tries < TW_MAX_RESET_TRIES) {
-                       /* Do soft reset */
-                       tw_soft_reset(tw_dev);
-
-                       error = tw_aen_drain_queue(tw_dev);
+       
+       for (i=0;i<TW_NUMDEVICES;i++) {
+               while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
+                       /* Prepare temporary device extension */
+                       tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
+                       if (tw_dev == NULL) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
+                               continue;
+                       }
+                       memset(tw_dev, 0, sizeof(TW_Device_Extension));
+                       
+                       error = tw_initialize_device_extension(tw_dev);
                        if (error) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
-                               tries++;
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
                                continue;
                        }
-
-                       /* Check for controller errors */
-                       if (tw_check_errors(tw_dev)) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
-                               tries++;
+                       
+                       /* Calculate the cards register addresses */
+                       tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
+                       tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15);
+                       tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4);
+                       tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8);
+                       tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC);
+                       /* Save pci_dev struct to device extension */
+                       tw_dev->tw_pci_dev = tw_pci_dev;
+                       
+                       /* Poll status register for 60 secs for 'Controller Ready' flag */
+                       if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
                                continue;
                        }
-
-                       /* Empty the response queue */
-                       error = tw_empty_response_que(tw_dev);
+                       
+                       /* Disable interrupts on the card */
+                       tw_disable_interrupts(tw_dev);
+                       
+                       while (tries < TW_MAX_RESET_TRIES) {
+                               /* Do soft reset */
+                               tw_soft_reset(tw_dev);
+                               
+                               error = tw_aen_drain_queue(tw_dev);
+                               if (error) {
+                                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
+                                       tries++;
+                                       continue;
+                               }
+                               
+                               /* Check for controller errors */
+                               if (tw_check_errors(tw_dev)) {
+                                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
+                                       tries++;
+                                       continue;
+                               }
+                               
+                               /* Empty the response queue */
+                               error = tw_empty_response_que(tw_dev);
+                               if (error) {
+                                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
+                                       tries++;
+                                       continue;
+                               }
+                               
+                               /* Now the controller is in a good state */
+                               break;
+                       }
+                       
+                       if (tries >= TW_MAX_RESET_TRIES) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
+                               continue;
+                       }
+                       
+                       /* Make sure that io region isn't already taken */
+                       if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
+                                      (tw_dev->tw_pci_dev->base_address[0]), 
+                                      (tw_dev->tw_pci_dev->base_address[0]) + 
+                                      TW_IO_ADDRESS_RANGE, numcards);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
+                               continue;
+                       }
+                       
+                       /* Reserve the io address space */
+                       request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
+                       error = tw_initialize_units(tw_dev);
                        if (error) {
-                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
-                               tries++;
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+                               release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
                                continue;
                        }
-
-                       /* Now the controller is in a good state */
-                       break;
-               }
-
-               if (tries >= TW_MAX_RESET_TRIES) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-
-               /* Make sure that io region isn't already taken */
-               if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
-                               (tw_dev->tw_pci_dev->base_address[0]), 
-                               (tw_dev->tw_pci_dev->base_address[0]) + 
-                               TW_IO_ADDRESS_RANGE, numcards);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-    
-               /* Reserve the io address space */
-               request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
-               error = tw_initialize_units(tw_dev);
-               if (error) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
-                       release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-
-               error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-               if (error) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
-                       release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-
-               /* Calculate max cmds per lun */
-               if (tw_dev->num_units > 0)
-                       tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
-
-               /* Register the card with the kernel SCSI layer */
-               host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-               
-               /* FIXME - check for NULL */
-
-               status_reg_value = inl(tw_dev->registers.status_reg_addr);
-
-               dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
+                       
+                       error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
+                       if (error) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
+                               release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
+                               continue;
+                       }
+                       
+                       /* Calculate max cmds per lun */
+                       if (tw_dev->num_units > 0)
+                               tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
+                       
+                       /* Register the card with the kernel SCSI layer */
+                       host = scsi_register(tw_host, sizeof(TW_Device_Extension));
+                       
+                       /* FIXME - check for NULL */
+                       
+                       status_reg_value = inl(tw_dev->registers.status_reg_addr);
+                       
+                       dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
                                (u32)(tw_pci_dev->base_address[0]), tw_pci_dev->irq, 
                                (status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, 
                                (status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24);
+                       
+                       if (host->hostdata) {
+                               tw_dev2 = (TW_Device_Extension *)host->hostdata;
+                               memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+                               tw_device_extension_list[tw_device_extension_count] = tw_dev2;
+                               numcards++;
+                               tw_device_extension_count = numcards;
+                               tw_dev2->host = host;
+                       } else { 
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
+                               scsi_unregister(host);
+                               release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
+                               continue;
+                       }
+                       
+                       /* Tell the firmware we support shutdown notification*/
+                       tw_setfeature(tw_dev2, 2, 1, &c);
+                       
+                       /* Now setup the interrupt handler */
+                       error = tw_setup_irq(tw_dev2);
+                       if (error) {
+                               printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
+                               scsi_unregister(host);
+                               release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+                               
+                               tw_free_device_extension(tw_dev);
+                               kfree(tw_dev);
+                               numcards--;
+                               continue;
+                       }
 
-               if (host->hostdata) {
-                       tw_dev2 = (TW_Device_Extension *)host->hostdata;
-                       memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
-                       tw_device_extension_list[tw_device_extension_count] = tw_dev2;
-                       numcards++;
-                       tw_device_extension_count = numcards;
-                       tw_dev2->host = host;
-               } else { 
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
-                       scsi_unregister(host);
-                       release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       continue;
-               }
-    
-               /* Re-enable interrupts on the card */
-               tw_enable_interrupts(tw_dev2);
-
-               /* Now setup the interrupt handler */
-               error = tw_setup_irq(tw_dev2);
-               if (error) {
-                       printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
-                       scsi_unregister(host);
-                       release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-
-                       tw_free_device_extension(tw_dev);
-                       kfree(tw_dev);
-                       numcards--;
-                       continue;
+                       /* Re-enable interrupts on the card */
+                       tw_enable_interrupts(tw_dev2);
+                       
+                       /* Free the temporary device extension */
+                       if (tw_dev)
+                               kfree(tw_dev);
                }
-
-               /* Free the temporary device extension */
-               if (tw_dev)
-                       kfree(tw_dev);
-               /* Tell the firmware we support shutdown notification*/
-               tw_setfeature(tw_dev2, 2, 1, &c);
        }
-
        if (numcards == 0) 
                printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n");
        else
-         register_reboot_notifier(&tw_notifier);
-
+               register_reboot_notifier(&tw_notifier);
+       
        return numcards;
 } /* End tw_findcards() */
 
@@ -1086,15 +1100,14 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                /* Handle attention interrupt */
                if (do_attention_interrupt) {
                        dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+                       dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
+                       tw_clear_attention_interrupt(tw_dev);
                        tw_state_request_start(tw_dev, &request_id);
                        error = tw_aen_read_queue(tw_dev, request_id);
                        if (error) {
                                printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n");
                                tw_dev->state[request_id] = TW_S_COMPLETED;
                                tw_state_request_finish(tw_dev, request_id);
-                       } else {
-                               dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
-                               tw_clear_attention_interrupt(tw_dev);
                        }
                }
 
@@ -1130,13 +1143,15 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                response_que.value = inl(response_que_addr);
                                request_id = response_que.u.response_id;
                                command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+                               error = 0;
                                if (command_packet->status != 0) {
-                                       printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+                                       printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
+                                       error = 1;
                                }
                                if (tw_dev->state[request_id] != TW_S_POSTED) {
                                        printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode);
+                                       error = 1;
                                }
-                               error = 0;
                                dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
                                /* Check for internal command */
                                if (tw_dev->srb[request_id] == 0) {
@@ -1180,8 +1195,8 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
                                        }
                                        if (error) {
                                                /* Tell scsi layer there was an error */
-                                               printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
-                                               tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+                                               dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
+                                               tw_dev->srb[request_id]->result = (DID_RESET << 16);
                                        } else {
                                                /* Tell scsi layer command was a success */
                                                tw_dev->srb[request_id]->result = (DID_OK << 16);
@@ -1463,8 +1478,10 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
                    (tw_dev->state[i] != TW_S_INITIAL) &&
                    (tw_dev->state[i] != TW_S_COMPLETED)) {
                        srb = tw_dev->srb[i];
-                       srb->result = (DID_RESET << 16);
-                       tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+                       if (srb != NULL) {
+                               srb->result = (DID_RESET << 16);
+                               tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+                       }
                }
        }
 
@@ -1809,6 +1826,10 @@ int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
                        error = tw_scsiop_read_capacity(tw_dev, request_id);
                        break;
+               case REQUEST_SENSE:
+                       dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
+                       error = tw_scsiop_request_sense(tw_dev, request_id);
+                       break;
                case TW_IOCTL:
                        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
                        error = tw_ioctl(tw_dev, request_id);
@@ -2165,6 +2186,23 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
        return 0;
 } /* End tw_scsiop_read_write() */
 
+/* This function will handle the request sense scsi command */
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+       dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+       
+       /* For now we just zero the sense buffer */
+       memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+       tw_dev->state[request_id] = TW_S_COMPLETED;
+       tw_state_request_finish(tw_dev, request_id);
+       
+       /* If we got a request_sense, we probably want a reset, return error */
+       tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+       tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+       return 0;
+} /* End tw_scsiop_request_sense() */
+
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
 {
index a48dc9ea8801f5214a0905a687fc6e8cc1c45720..2fc41906fdffc8d37c45cd17bb93045b649e25c2 100644 (file)
@@ -3,8 +3,9 @@
    
    Written By: Adam Radford <linux@3ware.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
+                    Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
-   Copyright (C) 1999, 2000 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By:     Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000      Andre Hedrick <andre@suse.com>
@@ -97,6 +98,8 @@
 #define TW_DEVICE_NAME                        "3ware Storage Controller"
 #define TW_VENDOR_ID (0x13C1)  /* 3ware */
 #define TW_DEVICE_ID (0x1000)  /* Storage Controller */
+#define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
+#define TW_NUMDEVICES 2
 
 /* Command packet opcodes */
 #define TW_OP_NOP            0x0
@@ -330,6 +333,7 @@ int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
index e841d4915f474b55013537a1de25c8ab83392ff1..25adc335b300292b0f913f7a62bda5a7d018319e 100644 (file)
@@ -1,11 +1,15 @@
 /*
- * bluetooth.c   Version 0.6
+ * bluetooth.c   Version 0.7
  *
  * Copyright (c) 2000 Greg Kroah-Hartman       <greg@kroah.com>
  * Copyright (c) 2000 Mark Douglas Corner      <mcorner@umich.edu>
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  *
+ * (11/29/2000) Version 0.7 gkh
+ *     Fixed problem with overrunning the tty flip buffer.
+ *     Removed unneeded NULL pointer initialization.
+ *
  * (10/05/2000) Version 0.6 gkh
  *     Fixed bug with urb->dev not being set properly, now that the usb
  *     core needs it.
@@ -73,9 +77,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -199,8 +203,7 @@ static struct tty_driver    bluetooth_tty_driver;
 static struct tty_struct *     bluetooth_tty[BLUETOOTH_TTY_MINORS];
 static struct termios *                bluetooth_termios[BLUETOOTH_TTY_MINORS];
 static struct termios *                bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
-static struct usb_bluetooth    *bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, };
-
+static struct usb_bluetooth    *bluetooth_table[BLUETOOTH_TTY_MINORS];
 
 
 static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
@@ -315,6 +318,11 @@ static int bluetooth_open (struct tty_struct *tty, struct file * filp)
        tty->driver_data = bluetooth;
        bluetooth->tty = tty;
 
+       /* force low_latency on so that our tty_push actually forces the data through, 
+        * otherwise it is scheduled, and with high data rates (like with OHCI) data
+        * can get lost. */
+       bluetooth->tty->low_latency = 1;
+       
        bluetooth->active = 1;
 
        /* Reset the packet position counters */
@@ -774,9 +782,14 @@ static void bluetooth_int_callback (struct urb *urb)
                return;
        }
 
-       if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){
-               for (i = 0; i < bluetooth->int_packet_pos; ++i)
+       if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) {
+               for (i = 0; i < bluetooth->int_packet_pos; ++i) {
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */
+                       if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(bluetooth->tty);
+                       }
                        tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+               }
                tty_flip_buffer_push(bluetooth->tty);
 
                bluetooth->int_packet_pos = 0;
@@ -888,8 +901,13 @@ static void bluetooth_read_bulk_callback (struct urb *urb)
        }
 
        if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
-               for (i = 0; i < bluetooth->bulk_packet_pos; ++i)
+               for (i = 0; i < bluetooth->bulk_packet_pos; ++i) {
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+                       if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(bluetooth->tty);
+                       }
                        tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+               }
                tty_flip_buffer_push(bluetooth->tty);
                bluetooth->bulk_packet_pos = 0;
        }       
index 0486d60ff20e8a60f43fd6902d82bcbd7dde9a29..b167699fd82c0d0709c953f02a6f524f778fc0ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2000 by David Brownell <david-b@pacbell.net>
+ * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/module.h>
-#undef DEBUG
+#ifdef CONFIG_USB_DEBUG
+       #define DEBUG
+#else
+       #undef DEBUG
+#endif
 #include <linux/usb.h>
 
 
 
 /* current USB framework handles max of 16 USB devices per driver */
-#define        MAX_CAMERAS             8
+#define        MAX_CAMERAS             16
 
 /* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
 #define        USB_CAMERA_MINOR_BASE   80
@@ -90,6 +94,8 @@ static const struct camera {
        /* These have the same application level protocol */  
     { 0x040a, 0x0120 },                // Kodak DC-240
     { 0x040a, 0x0130 },                // Kodak DC-280
+    { 0x040a, 0x0131 },                // Kodak DC-5000
+    { 0x040a, 0x0132 },                // Kodak DC-3400
 
        /* These have a different application level protocol which
         * is part of the Flashpoint "DigitaOS".  That supports some
@@ -435,7 +441,8 @@ static void * camera_probe(struct usb_device *dev, unsigned int ifnum)
                goto error;
        }
 
-       info ("USB Camera #%d connected", camera->subminor);
+       info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor,
+               USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor);
 
        camera->dev = dev;
        usb_inc_dev_use (dev);
@@ -475,12 +482,13 @@ static void camera_disconnect(struct usb_device *dev, void *ptr)
 }
 
 static /* const */ struct usb_driver camera_driver = {
-       "dc2xx",
-       camera_probe,
-       camera_disconnect,
-       { NULL, NULL },
-       &usb_camera_fops,
-       USB_CAMERA_MINOR_BASE
+       name:           "dc2xx",
+
+       probe:          camera_probe,
+       disconnect:     camera_disconnect,
+
+       fops:           &usb_camera_fops,
+       minor:          USB_CAMERA_MINOR_BASE
 };
 
 
@@ -497,7 +505,7 @@ void __exit usb_dc2xx_cleanup(void)
 }
 
 
-MODULE_AUTHOR("David Brownell, david-b@pacbell.net");
+MODULE_AUTHOR("David Brownell, dbrownell@users.sourceforge.net");
 MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");
 
 module_init (usb_dc2xx_init);
index cb5608b198da974d0cdafd887e742f9ea2d12e9c..1316c3b3c1631966b42064424635236ca764fa3e 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (01/22/2001) gb
+ *     Added write_room() and chars_in_buffer() support. 
+ * 
+ * (12/21/2000) gb
+ *     Moved termio stuff inside the port->active check.
+ *     Moved MOD_DEC_USE_COUNT to end of empeg_close().
+ * 
+ * (12/03/2000) gb
+ *     Added port->tty->ldisc.set_termios(port->tty, NULL) to empeg_open()
+ *     This notifies the tty driver that the termios have changed.
+ * 
  * (11/13/2000) gb
  *     Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
  *     (It only needs to be set once - Doh!)
@@ -39,9 +50,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #ifdef CONFIG_USB_SERIAL_DEBUG
 
 #include "usb-serial.h"
 
-#define EMPEG_VENDOR_ID                 0x084f
-#define EMPEG_PRODUCT_ID                0x0001
+#define EMPEG_VENDOR_ID                        0x084f
+#define EMPEG_PRODUCT_ID               0x0001
 
 #define MIN(a,b)               (((a)<(b))?(a):(b))
 
 /* function prototypes for an empeg-car player */
-static int  empeg_open         (struct usb_serial_port *port, struct file *filp);
-static void empeg_close                (struct usb_serial_port *port, struct file *filp);
-static int  empeg_write                (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static void empeg_throttle     (struct usb_serial_port *port);
-static void empeg_unthrottle   (struct usb_serial_port *port);
-static int  empeg_startup      (struct usb_serial *serial);
-static void empeg_shutdown     (struct usb_serial *serial);
-static int  empeg_ioctl                (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void empeg_set_termios  (struct usb_serial_port *port, struct termios *old_termios);
+static int  empeg_open                 (struct usb_serial_port *port, struct file *filp);
+static void empeg_close                        (struct usb_serial_port *port, struct file *filp);
+static int  empeg_write                        (struct usb_serial_port *port,
+                                       int from_user,
+                                       const unsigned char *buf,
+                                       int count);
+static int  empeg_write_room           (struct usb_serial_port *port);
+static int  empeg_chars_in_buffer      (struct usb_serial_port *port);
+static void empeg_throttle             (struct usb_serial_port *port);
+static void empeg_unthrottle           (struct usb_serial_port *port);
+static int  empeg_startup              (struct usb_serial *serial);
+static void empeg_shutdown             (struct usb_serial *serial);
+static int  empeg_ioctl                        (struct usb_serial_port *port,
+                                       struct file * file,
+                                       unsigned int cmd,
+                                       unsigned long arg);
+static void empeg_set_termios          (struct usb_serial_port *port, struct termios *old_termios);
 static void empeg_write_bulk_callback  (struct urb *urb);
 static void empeg_read_bulk_callback   (struct urb *urb);
 
@@ -93,6 +112,8 @@ struct usb_serial_device_type empeg_device = {
        ioctl:                  empeg_ioctl,
        set_termios:            empeg_set_termios,
        write:                  empeg_write,
+       write_room:             empeg_write_room,
+       chars_in_buffer:        empeg_chars_in_buffer,
        write_bulk_callback:    empeg_write_bulk_callback,
        read_bulk_callback:     empeg_read_bulk_callback,
 };
@@ -110,6 +131,7 @@ static int          bytes_out;
  ******************************************************************************/
 static int empeg_open (struct usb_serial_port *port, struct file *filp)
 {
+       struct usb_serial *serial = port->serial;
        unsigned long flags;
        int result;
 
@@ -123,60 +145,73 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
        ++port->open_count;
        MOD_INC_USE_COUNT;
 
-       /* gb - 2000/11/05
-        *
-        * personally, I think these termios should be set in
-        * empeg_startup(), but it appears doing so leads to one
-        * of those chicken/egg problems. :)
-        *
-        */
-       port->tty->termios->c_iflag
-               &= ~(IGNBRK
-               | BRKINT
-               | PARMRK
-               | ISTRIP
-               | INLCR
-               | IGNCR
-               | ICRNL
-               | IXON);
-
-       port->tty->termios->c_oflag
-               &= ~OPOST;
-
-       port->tty->termios->c_lflag
-               &= ~(ECHO
-               | ECHONL
-               | ICANON
-               | ISIG
-               | IEXTEN);
-
-       port->tty->termios->c_cflag
-               &= ~(CSIZE
-               | PARENB);
-
-       port->tty->termios->c_cflag
-               |= CS8;
-
-       /* gb - 2000/11/05
-        *
-        * force low_latency on
-        *
-        * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
-        * force the data through if low_latency is set.  Otherwise the pushes are
-        * scheduled; this is bad as it opens up the possibility of dropping bytes
-        * on the floor.  We are trying to sustain high data transfer rates; and
-        * don't want to drop bytes on the floor.
-        * Moral: use low_latency - drop no bytes - life is good. :)
-        *
-        */
-       port->tty->low_latency = 1;
-
        if (!port->active) {
+
+               /* gb - 2000/11/05
+                * personally, I think these termios should be set in
+                * empeg_startup(), but it appears doing so leads to one
+                * of those chicken/egg problems. :)
+                */
+               port->tty->termios->c_iflag
+                       &= ~(IGNBRK
+                       | BRKINT
+                       | PARMRK
+                       | ISTRIP
+                       | INLCR
+                       | IGNCR
+                       | ICRNL
+                       | IXON);
+
+               port->tty->termios->c_oflag
+                       &= ~OPOST;
+
+               port->tty->termios->c_lflag
+                       &= ~(ECHO
+                       | ECHONL
+                       | ICANON
+                       | ISIG
+                       | IEXTEN);
+
+               port->tty->termios->c_cflag
+                       &= ~(CSIZE
+                       | PARENB);
+
+               port->tty->termios->c_cflag
+                       |= CS8;
+
+               /* gb - 2000/12/03
+                * Contributed by Borislav Deianov
+                * Notify the tty driver that the termios have changed!!
+                */
+               port->tty->ldisc.set_termios(port->tty, NULL);
+
+               /* gb - 2000/11/05
+                * force low_latency on
+                *
+                * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
+                * force the data through if low_latency is set.  Otherwise the pushes are
+                * scheduled; this is bad as it opens up the possibility of dropping bytes
+                * on the floor.  We are trying to sustain high data transfer rates; and
+                * don't want to drop bytes on the floor.
+                * Moral: use low_latency - drop no bytes - life is good. :)
+                */
+               port->tty->low_latency = 1;
+
                port->active = 1;
                bytes_in = 0;
                bytes_out = 0;
 
                /* Start reading from the device */
+               FILL_BULK_URB(
+                       port->read_urb,
+                       serial->dev, 
+                       usb_rcvbulkpipe(serial->dev,
+                               port->bulk_in_endpointAddress),
+                       port->read_urb->transfer_buffer,
+                       port->read_urb->transfer_buffer_length,
+                       empeg_read_bulk_callback,
+                       port);
+
                port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
                result = usb_submit_urb(port->read_urb);
@@ -210,7 +245,6 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp)
        spin_lock_irqsave (&port->port_lock, flags);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
                transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
@@ -232,6 +266,8 @@ static void empeg_close (struct usb_serial_port *port, struct file * filp)
        /* Uncomment the following line if you want to see some statistics in your syslog */
        /* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 
+       MOD_DEC_USE_COUNT;
+
 }
 
 
@@ -287,8 +323,6 @@ static int empeg_write (struct usb_serial_port *port, int from_user, const unsig
                        memcpy (urb->transfer_buffer, current_position, transfer_size);
                }
 
-               count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
                /* build up our urb */
                FILL_BULK_URB (
                        urb,
@@ -320,6 +354,58 @@ exit:
 } 
 
 
+static int empeg_write_room (struct usb_serial_port *port)
+{
+       unsigned long flags;
+       int i;
+       int room = 0;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       spin_lock_irqsave (&port->port_lock, flags);
+
+       /* tally up the number of bytes available */
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (write_urb_pool[i]->status != -EINPROGRESS) {
+                       room += URB_TRANSFER_BUFFER_SIZE;
+               }
+       } 
+
+       spin_unlock_irqrestore (&port->port_lock, flags);
+
+       dbg(__FUNCTION__ " - returns %d", room);
+
+       return (room);
+
+}
+
+
+static int empeg_chars_in_buffer (struct usb_serial_port *port)
+{
+       unsigned long flags;
+       int i;
+       int chars = 0;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+
+       spin_lock_irqsave (&port->port_lock, flags);
+
+       /* tally up the number of bytes waiting */
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (write_urb_pool[i]->status == -EINPROGRESS) {
+                       chars += URB_TRANSFER_BUFFER_SIZE;
+               }
+       }
+
+       spin_unlock_irqrestore (&port->port_lock, flags);
+
+       dbg (__FUNCTION__ " - returns %d", chars);
+
+       return (chars);
+
+}
+
+
 static void empeg_write_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -379,9 +465,6 @@ static void empeg_read_bulk_callback (struct urb *urb)
                        if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
                                tty_flip_buffer_push(tty);
                                }
-                       /* gb - 2000/11/13
-                        * This doesn't push the data through unless tty->low_latency is set.
-                        */
                        tty_insert_flip_char(tty, data[i], 0);
                }
                /* gb - 2000/11/13
@@ -392,7 +475,18 @@ static void empeg_read_bulk_callback (struct urb *urb)
        }
 
        /* Continue trying to always read  */
+       FILL_BULK_URB(
+               port->read_urb,
+               serial->dev, 
+               usb_rcvbulkpipe(serial->dev,
+                       port->bulk_in_endpointAddress),
+               port->read_urb->transfer_buffer,
+               port->read_urb->transfer_buffer_length,
+               empeg_read_bulk_callback,
+               port);
+
        port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
        result = usb_submit_urb(port->read_urb);
 
        if (result)
index ace986765142dccb6951f1ad4960b9c0a6512660..ba9bd4d6662a7387ae5e144a727ecd079a1baa78 100644 (file)
@@ -54,9 +54,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
@@ -836,9 +836,6 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
        p_priv = (struct keyspan_port_private *)(port->private);
 
        /* Set some sane defaults */
-       p_priv->baud = 9600;
-       p_priv->cflag = CREAD | CLOCAL;
-       p_priv->flow_control = flow_none;
        p_priv->rts_state = 1;
        p_priv->dtr_state = 1;
 
@@ -851,16 +848,8 @@ static int keyspan_open (struct usb_serial_port *port, struct file *filp)
                        dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err);
                }
        }
-/*    Now done in startup routine
-       if (atomic_inc_return(&s_priv->active_count) == 1) {
-               s_priv->instat_urb->dev = serial->dev;
-               if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
-                       dbg(__FUNCTION__ " submit instat urb failed %d", err);
-               }
-       }
-*/
 
-       keyspan_send_setup(port);
+       keyspan_set_termios(port, NULL);
 
        return (0);
 }
index a596681d7732fe1e95b47f7b813d10c66b53f3d0..b6a57e1d6e912c6f46ff51beb42512176aa90271 100644 (file)
  * based on a driver by Brad Keryan)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
- * 
+ *
+ * 2001_02_05 gkh
+ *     Fixed buffer overflows bug with the generic serial driver.  Thanks to
+ *     Todd Squires <squirest@ct0.com> for fixing this.
+ *
+ * (12/12/2000) gkh
+ *     Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
+ *     moved them to the serial_open and serial_close functions.
+ *     Also fixed bug with there not being a MOD_DEC for the generic driver
+ *     (thanks to Gary Brubaker for finding this.)
+ *
  * (12/29/2000) gkh
  *     Small NULL pointer initialization cleanup which saves a bit of disk image
  *
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
@@ -456,6 +466,8 @@ static int serial_open (struct tty_struct *tty, struct file * filp)
                return -ENODEV;
        }
 
+       MOD_INC_USE_COUNT;
+       
        /* set up our port structure making the tty driver remember our port object, and us it */
        portNumber = MINOR(tty->device) - serial->minor;
        port = &serial->port[portNumber];
@@ -493,6 +505,8 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
        } else {
                generic_close(port, filp);
        }
+
+       MOD_DEC_USE_COUNT;
 }      
 
 
@@ -706,16 +720,22 @@ static int generic_open (struct usb_serial_port *port, struct file *filp)
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
 
+       MOD_INC_USE_COUNT;
+
        dbg(__FUNCTION__ " - port %d", port->number);
 
        spin_lock_irqsave (&port->port_lock, flags);
        
        ++port->open_count;
-       MOD_INC_USE_COUNT;
        
        if (!port->active) {
                port->active = 1;
 
+               /* force low_latency on so that our tty_push actually forces the data through, 
+                  otherwise it is scheduled, and with high data rates (like with OHCI) data
+                  can get lost. */
+               port->tty->low_latency = 1;
+               
                /* if we have a bulk interrupt, start reading from it */
                if (serial->num_bulk_in) {
                        /* Start reading from the device */
@@ -761,6 +781,7 @@ static void generic_close (struct usb_serial_port *port, struct file * filp)
        }
 
        spin_unlock_irqrestore (&port->port_lock, flags);
+       MOD_DEC_USE_COUNT;
 }
 
 
@@ -880,8 +901,13 @@ static void generic_read_bulk_callback (struct urb *urb)
        tty = port->tty;
        if (urb->actual_length) {
                for (i = 0; i < urb->actual_length ; ++i) {
-                        tty_insert_flip_char(tty, data[i], 0);
-               }
+                       /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+                       if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+                               tty_flip_buffer_push(tty);
+                       }
+                       /* this doesn't actually push the data through unless tty->low_latency is set */
+                       tty_insert_flip_char(tty, data[i], 0);
+               }
                tty_flip_buffer_push(tty);
        }
 
@@ -1056,7 +1082,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
        }
 
        /* found all that we need */
-       MOD_INC_USE_COUNT;
        info("%s converter detected", type->name);
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -1064,7 +1089,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
                num_ports = num_bulk_out;
                if (num_ports == 0) {
                        err("Generic device with no bulk out, not allowed.");
-                       MOD_DEC_USE_COUNT;
                        return NULL;
                }
        } else
@@ -1074,7 +1098,6 @@ static void * usb_serial_probe(struct usb_device *dev, unsigned int ifnum)
        serial = get_free_serial (num_ports, &minor);
        if (serial == NULL) {
                err("No more free serial devices");
-               MOD_DEC_USE_COUNT;
                return NULL;
        }
        
@@ -1220,7 +1243,6 @@ probe_error:
 
        /* free up any memory that we allocated */
        kfree (serial);
-       MOD_DEC_USE_COUNT;
        return NULL;
 }
 
@@ -1287,7 +1309,6 @@ static void usb_serial_disconnect(struct usb_device *dev, void *ptr)
                info("device disconnected");
        }
        
-       MOD_DEC_USE_COUNT;
 }
 
 
index 2193bab6996d8e8f44ecca1cfe5e521d6a370b00..6e8682d11afc64afb2a8f491feeaddf1fbd6e0cf 100644 (file)
  *     (at your option) any later version.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (01/21/2000) gkh
+ *     Added write_room and chars_in_buffer, as they were previously using the
+ *     generic driver versions which is all wrong now that we are using an urb
+ *     pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
+ *     Removed count assignment in the write function, which was not needed anymore
+ *     either.  Thanks to Al Borchers for pointing this out.
+ *
+ * (12/12/2000) gkh
+ *     Moved MOD_DEC to end of visor_close to be nicer, as the final write 
+ *     message can sleep.
  * 
  * (11/12/2000) gkh
  *     Fixed bug with data being dropped on the floor by forcing tty->low_latency
  *     to be on.  This fixes the OHCI issue!
  *
+ * (10/05/2000) gkh
+ *     Fixed bug with urb->dev not being set properly, now that the usb
+ *     core needs it.
+ * 
  * (09/11/2000) gkh
  *     Got rid of always calling kmalloc for every urb we wrote out to the
  *     device.
@@ -69,9 +84,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
 static int  visor_open         (struct usb_serial_port *port, struct file *filp);
 static void visor_close                (struct usb_serial_port *port, struct file *filp);
 static int  visor_write                (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  visor_write_room           (struct usb_serial_port *port);
+static int  visor_chars_in_buffer      (struct usb_serial_port *port);
 static void visor_throttle     (struct usb_serial_port *port);
 static void visor_unthrottle   (struct usb_serial_port *port);
 static int  visor_startup      (struct usb_serial *serial);
@@ -124,6 +141,8 @@ struct usb_serial_device_type handspring_device = {
        ioctl:                  visor_ioctl,
        set_termios:            visor_set_termios,
        write:                  visor_write,
+       write_room:             visor_write_room,
+       chars_in_buffer:        visor_chars_in_buffer,
        write_bulk_callback:    visor_write_bulk_callback,
        read_bulk_callback:     visor_read_bulk_callback,
 };
@@ -142,7 +161,9 @@ static int          bytes_out;
  ******************************************************************************/
 static int visor_open (struct usb_serial_port *port, struct file *filp)
 {
+       struct usb_serial *serial = port->serial;
        unsigned long flags;
+       int result;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return -ENODEV;
@@ -160,13 +181,18 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
                bytes_out = 0;
 
                /* force low_latency on so that our tty_push actually forces the data through, 
-                 otherwise it is scheduled, and with high data rates (like with OHCI) data
-                 can get lost. */
+                  otherwise it is scheduled, and with high data rates (like with OHCI) data
+                  can get lost. */
                port->tty->low_latency = 1;
-
-               /*Start reading from the device*/
-               if (usb_submit_urb(port->read_urb))
-                       dbg(__FUNCTION__  " - usb_submit_urb(read bulk) failed");
+               
+               /* Start reading from the device */
+               FILL_BULK_URB(port->read_urb, serial->dev, 
+                             usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+                             port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+                             visor_read_bulk_callback, port);
+               result = usb_submit_urb(port->read_urb);
+               if (result)
+                       err(__FUNCTION__ " - failed submitting read urb, error %d", result);
        }
        
        spin_unlock_irqrestore (&port->port_lock, flags);
@@ -193,7 +219,6 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
        spin_lock_irqsave (&port->port_lock, flags);
 
        --port->open_count;
-       MOD_DEC_USE_COUNT;
 
        if (port->open_count <= 0) {
                transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
@@ -216,6 +241,8 @@ static void visor_close (struct usb_serial_port *port, struct file * filp)
 
        /* Uncomment the following line if you want to see some statistics in your syslog */
        /* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+
+       MOD_DEC_USE_COUNT;
 }
 
 
@@ -263,8 +290,6 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig
                else
                        memcpy (urb->transfer_buffer, current_position, transfer_size);
                
-               count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
                /* build up our urb */
                FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), 
                                urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port);
@@ -286,6 +311,52 @@ exit:
 } 
 
 
+static int visor_write_room (struct usb_serial_port *port)
+{
+       unsigned long flags;
+       int i;
+       int room = 0;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       spin_lock_irqsave (&port->port_lock, flags);
+
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (write_urb_pool[i]->status != -EINPROGRESS) {
+                       room += URB_TRANSFER_BUFFER_SIZE;
+               }
+       }
+       
+       spin_unlock_irqrestore (&port->port_lock, flags);
+       
+       dbg(__FUNCTION__ " - returns %d", room);
+       return (room);
+}
+
+
+static int visor_chars_in_buffer (struct usb_serial_port *port)
+{
+       unsigned long flags;
+       int i;
+       int chars = 0;
+
+       dbg(__FUNCTION__ " - port %d", port->number);
+       
+       spin_lock_irqsave (&port->port_lock, flags);
+
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (write_urb_pool[i]->status == -EINPROGRESS) {
+                       chars += URB_TRANSFER_BUFFER_SIZE;
+               }
+       }
+       
+       spin_unlock_irqrestore (&port->port_lock, flags);
+
+       dbg (__FUNCTION__ " - returns %d", chars);
+       return (chars);
+}
+
+
 static void visor_write_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -310,15 +381,22 @@ static void visor_write_bulk_callback (struct urb *urb)
 static void visor_read_bulk_callback (struct urb *urb)
 {
        struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+       struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
        int i;
+       int result;
 
        if (port_paranoia_check (port, __FUNCTION__))
                return;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
+       if (!serial) {
+               dbg(__FUNCTION__ " - bad serial pointer, exiting");
+               return;
+       }
+
        if (urb->status) {
                dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
                return;
@@ -341,8 +419,13 @@ static void visor_read_bulk_callback (struct urb *urb)
        }
 
        /* Continue trying to always read  */
-       if (usb_submit_urb(urb))
-               dbg(__FUNCTION__ " - failed resubmitting read urb");
+       FILL_BULK_URB(port->read_urb, serial->dev, 
+                     usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+                     port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+                     visor_read_bulk_callback, port);
+       result = usb_submit_urb(port->read_urb);
+       if (result)
+               err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
        return;
 }
 
@@ -366,13 +449,16 @@ static void visor_throttle (struct usb_serial_port *port)
 static void visor_unthrottle (struct usb_serial_port *port)
 {
        unsigned long flags;
+       int result;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
        spin_lock_irqsave (&port->port_lock, flags);
 
-       if (usb_submit_urb (port->read_urb))
-               dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+       port->read_urb->dev = port->serial->dev;
+       result = usb_submit_urb(port->read_urb);
+       if (result)
+               err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
        spin_unlock_irqrestore (&port->port_lock, flags);
 
index 20429dc2136baa30c343b1853e501a2891ab3d28..498afbb2b69e7001bab12fe9f969d85951e8b14d 100644 (file)
 #error You really need /proc support for binfmt_misc. Please reconfigure!
 #endif
 
-#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
+enum {
+       VERBOSE_STATUS = 1 /* define as zero to save 400 bytes kernel memory */
+};
 
-struct binfmt_entry {
+typedef struct binfmt_entry {
        struct binfmt_entry *next;
        long id;
        int flags;                      /* type, status, etc. */
@@ -52,16 +54,15 @@ struct binfmt_entry {
        char *magic;                    /* magic or filename extension */
        char *mask;                     /* mask, NULL for exact match */
        char *interpreter;              /* filename of interpreter */
-       char *proc_name;
+       char *name;
        struct proc_dir_entry *proc_dir;
-};
+} Node;
 
-#define ENTRY_ENABLED 1                /* the old binfmt_entry.enabled */
-#define        ENTRY_MAGIC 8           /* not filename detection */
+enum { Enabled, Magic };
 
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
-static void entry_proc_cleanup(struct binfmt_entry *e);
-static int entry_proc_setup(struct binfmt_entry *e);
+static void entry_proc_cleanup(Node *e);
+static int entry_proc_setup(Node *e);
 
 static struct linux_binfmt misc_format = {
 #ifndef MODULE
@@ -73,7 +74,7 @@ static struct linux_binfmt misc_format = {
 
 static struct proc_dir_entry *bm_dir = NULL;
 
-static struct binfmt_entry *entries = NULL;
+static Node *entries = NULL;
 static int free_id = 1;
 static int enabled = 1;
 
@@ -85,7 +86,7 @@ static rwlock_t entries_lock __attribute__((unused)) = RW_LOCK_UNLOCKED;
  */
 static void clear_entry(int id)
 {
-       struct binfmt_entry **ep, *e;
+       Node **ep, *e;
 
        write_lock(&entries_lock);
        ep = &entries;
@@ -106,7 +107,7 @@ static void clear_entry(int id)
  */
 static void clear_entries(void)
 {
-       struct binfmt_entry *e, *n;
+       Node *e, *n;
 
        write_lock(&entries_lock);
        n = entries;
@@ -123,9 +124,9 @@ static void clear_entries(void)
 /*
  * Find entry through id and lock it
  */
-static struct binfmt_entry *get_entry(int id)
+static Node *get_entry(int id)
 {
-       struct binfmt_entry *e;
+       Node *e;
 
        read_lock(&entries_lock);
        e = entries;
@@ -139,7 +140,7 @@ static struct binfmt_entry *get_entry(int id)
 /*
  * unlock entry
  */
-static inline void put_entry(struct binfmt_entry *e)
+static inline void put_entry(Node *e)
 {
        if (e)
                read_unlock(&entries_lock);
@@ -148,19 +149,19 @@ static inline void put_entry(struct binfmt_entry *e)
 
 /* 
  * Check if we support the binfmt
- * if we do, return the binfmt_entry, else NULL
+ * if we do, return the node, else NULL
  * locking is done in load_misc_binary
  */
-static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+static Node *check_file(struct linux_binprm *bprm)
 {
-       struct binfmt_entry *e;
+       Node *e;
        char *p = strrchr(bprm->filename, '.');
        int j;
 
        e = entries;
        while (e) {
-               if (e->flags & ENTRY_ENABLED) {
-                       if (!(e->flags & ENTRY_MAGIC)) {
+               if (test_bit(Enabled, &e->flags)) {
+                       if (!test_bit(Magic, &e->flags)) {
                                if (p && !strcmp(e->magic, p + 1))
                                        return e;
                        } else {
@@ -183,7 +184,7 @@ static struct binfmt_entry *check_file(struct linux_binprm *bprm)
  */
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
-       struct binfmt_entry *fmt;
+       Node *fmt;
        struct dentry * dentry;
        char iname[128];
        char *iname_addr = iname;
@@ -233,46 +234,44 @@ _ret:
        return retval;
 }
 
-
-
-/*
- * /proc handling routines
- */
-
 /*
  * parses and copies one argument enclosed in del from *sp to *dp,
  * recognising the \x special.
  * returns pointer to the copied argument or NULL in case of an
  * error (and sets err) or null argument length.
  */
-static char *copyarg(char **dp, const char **sp, int *count,
-                    char del, int special, int *err)
+static char *scanarg(char *s, char del)
 {
-       char c = 0, *res = *dp;
-
-       while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
-               switch (c) {
-               case '\\':
-                       if (special && (**sp == 'x')) {
-                               if (!isxdigit(c = toupper(*(++*sp))))
-                                       *err = -EINVAL;
-                               **dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
-                               if (!isxdigit(c = toupper(*(++*sp))))
-                                       *err = -EINVAL;
-                               *((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
-                               ++*sp;
-                               *count -= 3;
-                               break;
-                       }
-               default:
-                       *((*dp)++) = c;
+       char c;
+
+       while ((c = *s++) != del) {
+               if (c == '\\' && *s == 'x') {
+                       s++;
+                       if (!isxdigit(*s++))
+                               return NULL;
+                       if (!isxdigit(*s++))
+                               return NULL;
                }
        }
-       if (*err || (c != del) || (res == *dp))
-               res = NULL;
-       else if (!special)
-               *((*dp)++) = '\0';
-       return res;
+       return s;
+}
+
+static int unquote(char *from)
+{
+       char c = 0, *s = from, *p = from;
+
+       while ((c = *s++) != '\0') {
+               if (c == '\\' && *s == 'x') {
+                       s++;
+                       c = toupper(*s++);
+                       *p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
+                       c = toupper(*s++);
+                       *p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
+                       continue;
+               }
+               *p++ = c;
+       }
+       return p - from;
 }
 
 /*
@@ -280,59 +279,197 @@ static char *copyarg(char **dp, const char **sp, int *count,
  * ':name:type:offset:magic:mask:interpreter:'
  * where the ':' is the IFS, that can be chosen with the first char
  */
-static int proc_write_register(struct file *file, const char *buffer,
-                              unsigned long count, void *data)
+static Node *create_entry(const char *buffer, size_t count)
 {
-       const char *sp;
-       char del, *dp;
-       struct binfmt_entry *e;
-       int memsize, cnt = count - 1, err;
+       Node *e;
+       int memsize, err;
+       char *buf, *p;
+       char del;
 
        /* some sanity checks */
        err = -EINVAL;
        if ((count < 11) || (count > 256))
-               goto _err;
+               goto out;
 
        err = -ENOMEM;
-       memsize = sizeof(struct binfmt_entry) + count;
-       if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
-               goto _err;
+       memsize = sizeof(Node) + count + 8;
+       e = (Node *) kmalloc(memsize, GFP_USER);
+       if (!e)
+               goto out;
+
+       p = buf = (char *)e + sizeof(Node);
+
+       memset(e, 0, sizeof(Node));
+       if (copy_from_user(buf, buffer, count))
+               goto Efault;
+
+       del = *p++;     /* delimeter */
+
+       memset(buf+count, del, 8);
+
+       e->name = p;
+       p = strchr(p, del);
+       if (!p)
+               goto Einval;
+       *p++ = '\0';
+       if (!e->name[0] ||
+           !strcmp(e->name, ".") ||
+           !strcmp(e->name, "..") ||
+           strchr(e->name, '/'))
+               goto Einval;
+       switch (*p++) {
+               case 'E': e->flags = 1<<Enabled; break;
+               case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
+               default: goto Einval;
+       }
+       if (*p++ != del)
+               goto Einval;
+       if (test_bit(Magic, &e->flags)) {
+               char *s = strchr(p, del);
+               if (!s)
+                       goto Einval;
+               *s++ = '\0';
+               e->offset = simple_strtoul(p, &p, 10);
+               if (*p++)
+                       goto Einval;
+               e->magic = p;
+               p = scanarg(p, del);
+               if (!p)
+                       goto Einval;
+               p[-1] = '\0';
+               if (!e->magic[0])
+                       goto Einval;
+               e->mask = p;
+               p = scanarg(p, del);
+               if (!p)
+                       goto Einval;
+               p[-1] = '\0';
+               if (!e->mask[0])
+                       e->mask = NULL;
+               e->size = unquote(e->magic);
+               if (e->mask && unquote(e->mask) != e->size)
+                       goto Einval;
+               if (e->size + e->offset > 128)
+                       goto Einval;
+       } else {
+               p = strchr(p, del);
+               if (!p)
+                       goto Einval;
+               *p++ = '\0';
+               e->magic = p;
+               p = strchr(p, del);
+               if (!p)
+                       goto Einval;
+               *p++ = '\0';
+               if (!e->magic[0] || strchr(e->magic, '/'))
+                       goto Einval;
+               p = strchr(p, del);
+               if (!p)
+                       goto Einval;
+               *p++ = '\0';
+       }
+       e->interpreter = p;
+       p = strchr(p, del);
+       if (!p)
+               goto Einval;
+       *p++ = '\0';
+       if (!e->interpreter[0])
+               goto Einval;
+
+       if (*p == '\n')
+               p++;
+       if (p != buf + count)
+               goto Einval;
+       return e;
 
-       err = 0;
-       sp = buffer + 1;
-       del = buffer[0];
-       dp = (char *)e + sizeof(struct binfmt_entry);
+out:
+       return ERR_PTR(err);
 
-       e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
+Efault:
+       kfree(e);
+       return ERR_PTR(-EFAULT);
+Einval:
+       kfree(e);
+       return ERR_PTR(-EINVAL);
+}
 
-       /* we can use bit 3 of type for ext/magic
-          flag due to the nice encoding of E and M */
-       if ((*sp & ~('E' | 'M')) || (sp[1] != del))
-               err = -EINVAL;
-       else
-               e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
-       cnt -= 2; sp++;
-
-       e->offset = 0;
-       while (cnt-- && isdigit(*sp))
-               e->offset = e->offset * 10 + *sp++ - '0';
-       if (*sp++ != del)
-               err = -EINVAL;
-
-       e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
-       e->size = dp - e->magic;
-       e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
-       if (e->mask && ((dp - e->mask) != e->size))
-               err = -EINVAL;
-       e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
-       e->id = free_id++;
+/*
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
+ */
+static int parse_command(const char *buffer, size_t count)
+{
+       char s[4];
+
+       if (!count)
+               return 0;
+       if (count > 3)
+               return -EINVAL;
+       if (copy_from_user(s, buffer, count))
+               return -EFAULT;
+       if (s[count-1] == '\n')
+               count--;
+       if (count == 1 && s[0] == '0')
+               return 1;
+       if (count == 1 && s[0] == '1')
+               return 2;
+       if (count == 2 && s[0] == '-' && s[1] == '1')
+               return 3;
+       return -EINVAL;
+}
+
+static void entry_status(Node *e, char *page)
+{
+       char *dp;
+       char *status = "disabled";
+
+       if (test_bit(Enabled, &e->flags))
+               status = "enabled";
+
+       if (!VERBOSE_STATUS) {
+               sprintf(page, "%s\n", status);
+               return;
+       }
 
-       /* more sanity checks */
-       if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
-           (e->size < 1) || ((e->size + e->offset) > 127) ||
-           !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
+       sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
+       dp = page + strlen(page);
+       if (!test_bit(Magic, &e->flags)) {
+               sprintf(dp, "extension .%s\n", e->magic);
+       } else {
+               int i;
+
+               sprintf(dp, "offset %i\nmagic ", e->offset);
+               dp = page + strlen(page);
+               for (i = 0; i < e->size; i++) {
+                       sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+                       dp += 2;
+               }
+               if (e->mask) {
+                       sprintf(dp, "\nmask ");
+                       dp += 6;
+                       for (i = 0; i < e->size; i++) {
+                               sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
+                               dp += 2;
+                       }
+               }
+               *dp++ = '\n';
+               *dp = '\0';
+       }
+}
+
+static int proc_write_register(struct file *file, const char *buffer,
+                              unsigned long count, void *data)
+{
+       Node *e = create_entry(buffer, count);
+       int err;
+
+       if (IS_ERR(e))
+               return PTR_ERR(e);
+       
+       if (entry_proc_setup(e))
                goto free_err;
 
+       e->id = free_id++;
        write_lock(&entries_lock);
        e->next = entries;
        entries = e;
@@ -355,68 +492,24 @@ free_err:
 static int proc_read_status(char *page, char **start, off_t off,
                            int count, int *eof, void *data)
 {
-       struct binfmt_entry *e;
-       char *dp;
-       int elen, i, err;
+       Node *e;
+       int elen;
 
-#ifndef VERBOSE_STATUS
-       if (data) {
-               if (!(e = get_entry((int) data))) {
-                       err = -ENOENT;
-                       goto _err;
-               }
-               i = e->flags & ENTRY_ENABLED;
-               put_entry(e);
-       } else {
-               i = enabled;
-       } 
-       sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
-#else
-       if (!data)
+       if (!data) {
                sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
-       else {
-               if (!(e = get_entry((long) data))) {
-                       err = -ENOENT;
-                       goto _err;
-               }
-               sprintf(page, "%s\ninterpreter %s\n",
-                       (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
-                       e->interpreter);
-               dp = page + strlen(page);
-               if (!(e->flags & ENTRY_MAGIC)) {
-                       sprintf(dp, "extension .%s\n", e->magic);
-                       dp = page + strlen(page);
-               } else {
-                       sprintf(dp, "offset %i\nmagic ", e->offset);
-                       dp = page + strlen(page);
-                       for (i = 0; i < e->size; i++) {
-                               sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
-                               dp += 2;
-                       }
-                       if (e->mask) {
-                               sprintf(dp, "\nmask ");
-                               dp += 6;
-                               for (i = 0; i < e->size; i++) {
-                                       sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
-                                       dp += 2;
-                               }
-                       }
-                       *dp++ = '\n';
-                       *dp = '\0';
-               }
+       } else {
+               if (!(e = get_entry((long) data)))
+                       return -ENOENT;
+               entry_status(e, page);
                put_entry(e);
        }
-#endif
 
        elen = strlen(page) - off;
        if (elen < 0)
                elen = 0;
        *eof = (elen <= count) ? 1 : 0;
        *start = page + off;
-       err = elen;
-
-_err:
-       return err;
+       return elen;
 }
 
 /*
@@ -426,45 +519,50 @@ _err:
 static int proc_write_status(struct file *file, const char *buffer,
                             unsigned long count, void *data)
 {
-       struct binfmt_entry *e;
-       int res = count;
-
-       if (buffer[count-1] == '\n')
-               count--;
-       if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
-               if (data) {
-                       if ((e = get_entry((long) data)))
-                               e->flags = (e->flags & ~ENTRY_ENABLED)
-                                           | (int)(buffer[0] - '0');
-                       put_entry(e);
-               } else {
-                       enabled = buffer[0] - '0';
-               }
-       } else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
-               if (data)
-                       clear_entry((long) data);
-               else
-                       clear_entries();
-       } else {
-               res = -EINVAL;
+       Node *e;
+       int res = parse_command(buffer, count);
+
+       switch(res) {
+               case 1: if (data) {
+                               if ((e = get_entry((long) data)))
+                                       clear_bit(Enabled, &e->flags);
+                               put_entry(e);
+                       } else {
+                               enabled = 0;
+                       }
+                       break;
+               case 2: if (data) {
+                               if ((e = get_entry((long) data)))
+                                       set_bit(Enabled, &e->flags);
+                               put_entry(e);
+                       } else {
+                               enabled = 1;
+                       }
+                       break;
+               case 3: if (data)
+                               clear_entry((long) data);
+                       else
+                               clear_entries();
+                       break;
+               default: return res;
        }
-       return res;
+       return count;
 }
 
 /*
  * Remove the /proc-dir entries of one binfmt
  */
-static void entry_proc_cleanup(struct binfmt_entry *e)
+static void entry_proc_cleanup(Node *e)
 {
-       remove_proc_entry(e->proc_name, bm_dir);
+       remove_proc_entry(e->name, bm_dir);
 }
 
 /*
  * Create the /proc-dir entry for binfmt
  */
-static int entry_proc_setup(struct binfmt_entry *e)
+static int entry_proc_setup(Node *e)
 {
-       if (!(e->proc_dir = create_proc_entry(e->proc_name,
+       if (!(e->proc_dir = create_proc_entry(e->name,
                                S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
        {
                printk(KERN_WARNING "Unable to create /proc entry.\n");
@@ -545,4 +643,3 @@ void cleanup_module(void)
        remove_proc_entry("sys/fs/binfmt_misc", NULL);
 }
 #endif
-#undef VERBOSE_STATUS
index 0a4c37c5e6a9c8be4150ae926c0985c73b819bd5..74a872db5a783555c748b25d46c5f0b75d1dc2a6 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -20,9 +20,6 @@
  * table to check for several different types  of binary formats.  We keep
  * trying until we recognize the file or we run out of supported binary
  * formats. 
- *
- * (current->executable doesn't exist anymore, procfs searches for the vma
- * that corresponds to the executable and uses its dentry.)
  */
 
 #include <linux/config.h>
@@ -520,7 +517,6 @@ int flush_old_exec(struct linux_binprm * bprm)
 
        current->sas_ss_sp = current->sas_ss_size = 0;
 
-       current->dumpable = 0;
        bprm->dumpable = 0;
        if (current->euid == current->uid && current->egid == current->gid)
                bprm->dumpable = !bprm->priv_change;
@@ -829,6 +825,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
 {
        struct linux_binprm bprm;
        struct dentry * dentry;
+       int was_dumpable;
        int retval;
        int i;
 
@@ -857,6 +854,9 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
                return bprm.envc;
        }
 
+       was_dumpable = current->dumpable;
+       current->dumpable = 0;
+
        retval = prepare_binprm(&bprm);
        
        if (retval >= 0) {
@@ -871,11 +871,11 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
        if (retval >= 0)
                retval = search_binary_handler(&bprm,regs);
 
-       current->dumpable = bprm.dumpable;
-
-       if (retval >= 0)
+       if (retval >= 0) {
                /* execve success */
+               current->dumpable = bprm.dumpable;
                return retval;
+       }
 
        /* Something went wrong, return the inode and free the argument pages*/
        if (bprm.dentry)
@@ -884,5 +884,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
        for (i=0 ; i<MAX_ARG_PAGES ; i++)
                free_page(bprm.page[i]);
 
+       current->dumpable = was_dumpable;
+
        return retval;
 }
index 286970f5a1232fef5dcd4965a9161e22c16b8768..771a1fa9c7768f91b56bd15adcb2983646dc0749 100644 (file)
@@ -528,10 +528,12 @@ struct dvd_layer {
        __u32 end_sector_l0;
 };
 
+#define DVD_LAYERS     4
+
 struct dvd_physical {
        __u8 type;
        __u8 layer_num;
-       struct dvd_layer layer[4];
+       struct dvd_layer layer[DVD_LAYERS];
 };
 
 struct dvd_copyright {
index 3e73b0a29b22a85199f372f2b9f0c42c76e3c9c6..6d5a62248d0937bf9a4ce8376c26f5590824d7be 100644 (file)
@@ -5,7 +5,7 @@
  *
  *             Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:    $Id: tcp_input.c,v 1.164.2.20 2001/02/23 20:20:22 davem Exp $
+ * Version:    $Id: tcp_input.c,v 1.164.2.21 2001/03/06 05:39:39 davem Exp $
  *
  * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2215,6 +2215,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                        tp->snd_wnd = htons(th->window);
                        tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
                        tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+                       tp->syn_seq = TCP_SKB_CB(skb)->seq;
                        tp->fin_seq = TCP_SKB_CB(skb)->seq;
 
                        tcp_set_state(sk, TCP_ESTABLISHED);