From d8401739030384cbb716aff800edfb984cabca43 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:23:30 -0500 Subject: [PATCH] Linux 2.2.19pre17 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) --- Documentation/Configure.help | 20 +- Documentation/isdn/README.eicon | 11 - MAINTAINERS | 7 + Makefile | 2 +- drivers/block/ide-pmac.c | 3 +- drivers/cdrom/cdrom.c | 49 +- drivers/char/Makefile | 8 +- drivers/char/cpia.c | 2 +- drivers/char/misc.c | 9 + drivers/char/sx.c | 16 +- drivers/net/3c527.c | 992 ++++++++++++++++++++------------ drivers/net/3c527.h | 6 +- drivers/net/irda/irtty.c | 10 +- drivers/net/starfire.c | 18 +- drivers/scsi/3w-xxxx.c | 356 +++++++----- drivers/scsi/3w-xxxx.h | 6 +- drivers/usb/bluetooth.c | 32 +- drivers/usb/dc2xx.c | 30 +- drivers/usb/serial/empeg.c | 226 +++++--- drivers/usb/serial/keyspan.c | 15 +- drivers/usb/serial/usbserial.c | 41 +- drivers/usb/serial/visor.c | 114 +++- fs/binfmt_misc.c | 437 ++++++++------ fs/exec.c | 16 +- include/linux/cdrom.h | 4 +- net/ipv4/tcp_input.c | 3 +- 26 files changed, 1564 insertions(+), 869 deletions(-) diff --git a/Documentation/Configure.help b/Documentation/Configure.help index ba218abac660..22c2d083c81d 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -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 diff --git a/Documentation/isdn/README.eicon b/Documentation/isdn/README.eicon index 16dd09eb9e1c..2e36d442b3d3 100644 --- a/Documentation/isdn/README.eicon +++ b/Documentation/isdn/README.eicon @@ -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 diff --git a/MAINTAINERS b/MAINTAINERS index 3d584b77623c..f7f992325e24 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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 diff --git a/Makefile b/Makefile index 43ada2a25469..d435daf20dd5 100644 --- 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/) diff --git a/drivers/block/ide-pmac.c b/drivers/block/ide-pmac.c index ac2230abe9f7..13a7c4684b09 100644 --- a/drivers/block/ide-pmac.c +++ b/drivers/block/ide-pmac.c @@ -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)); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 0ae2740ebb1c..f35564991037 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -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; } diff --git a/drivers/char/Makefile b/drivers/char/Makefile index acc8e533e7c6..12beadf6b13c 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -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 diff --git a/drivers/char/cpia.c b/drivers/char/cpia.c index f810498a9059..0a666fc460c8 100644 --- a/drivers/char/cpia.c +++ b/drivers/char/cpia.c @@ -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; } diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 05a8f3b5748f..d1f7a09c975b 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -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) diff --git a/drivers/char/sx.c b/drivers/char/sx.c index aef6223d0bfb..fc4ab9699a4a 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -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; diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index 5ff404b72b18..5a155d45b18b 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -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. @@ -10,33 +11,70 @@ * 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 @@ -61,8 +99,7 @@ static const char *version = #include #include #include - -#include +#include #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;itx_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;itx_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 */ diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h index e517345974ac..a696d0ef5c9a 100644 --- a/drivers/net/3c527.h +++ b/drivers/net/3c527.h @@ -27,6 +27,10 @@ #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)); diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c index 9198c667a9fd..84687108bb5d 100644 --- a/drivers/net/irda/irtty.c +++ b/drivers/net/irda/irtty.c @@ -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); diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index d0ee3aab3626..c6c75da19c90 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -59,6 +59,10 @@ - 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. */ diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 63bf3e7d1a21..777556537f7a 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -6,7 +6,7 @@ Arnaldo Carvalho de Melo - Copyright (C) 1999-2000 3ware Inc. + Copyright (C) 1999-2001 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -68,6 +68,15 @@ 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 @@ -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;iregisters.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) { diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index a48dc9ea8801..2fc41906fdff 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -3,8 +3,9 @@ Written By: Adam Radford Modifications By: Joel Jacobson + Arnaldo Carvalho de Melo - Copyright (C) 1999, 2000 3ware Inc. + Copyright (C) 1999-2001 3ware Inc. Kernel compatablity By: Andre Hedrick Non-Copyright (C) 2000 Andre Hedrick @@ -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); diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c index e841d4915f47..25adc335b300 100644 --- a/drivers/usb/bluetooth.c +++ b/drivers/usb/bluetooth.c @@ -1,11 +1,15 @@ /* - * bluetooth.c Version 0.6 + * bluetooth.c Version 0.7 * * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * * 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 #include #include +#include #include #include -#include #include #include @@ -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; } diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c index 0486d60ff20e..b167699fd82c 100644 --- a/drivers/usb/dc2xx.c +++ b/drivers/usb/dc2xx.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1999-2000 by David Brownell + * Copyright (C) 1999-2000 by David Brownell * * 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 @@ -59,13 +59,17 @@ #include #include #include -#undef DEBUG +#ifdef CONFIG_USB_DEBUG + #define DEBUG +#else + #undef DEBUG +#endif #include /* 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); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index cb5608b198da..1316c3b3c163 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -13,6 +13,17 @@ * * 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 #include #include +#include #include #include -#include #include #include #ifdef CONFIG_USB_SERIAL_DEBUG @@ -53,21 +64,29 @@ #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) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index ace986765142..ba9bd4d6662a 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -54,9 +54,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -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); } diff --git a/drivers/usb/serial/usbserial.c b/drivers/usb/serial/usbserial.c index a596681d7732..b6a57e1d6e91 100644 --- a/drivers/usb/serial/usbserial.c +++ b/drivers/usb/serial/usbserial.c @@ -14,7 +14,17 @@ * 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 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 * @@ -246,9 +256,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -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; } diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 2193bab6996d..6e8682d11afc 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -10,11 +10,26 @@ * (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 #include #include +#include #include #include -#include #include #include @@ -92,6 +107,8 @@ 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); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 20429dc2136b..498afbb2b69e 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -41,9 +41,11 @@ #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<flags = (1<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 diff --git a/fs/exec.c b/fs/exec.c index 0a4c37c5e6a9..74a872db5a78 100644 --- 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 @@ -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 ; idumpable = was_dumpable; + return retval; } diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h index 286970f5a123..771a1fa9c776 100644 --- a/include/linux/cdrom.h +++ b/include/linux/cdrom.h @@ -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 { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3e73b0a29b22..6d5a62248d09 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -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, * Fred N. van Kempen, @@ -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); -- 2.39.5