]> git.neil.brown.name Git - history.git/commitdiff
Import 1.1.32 1.1.32
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:34 +0000 (15:09 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:09:34 +0000 (15:09 -0500)
31 files changed:
Makefile
config.in
drivers/block/README.hd [new file with mode: 0644]
drivers/block/hd.c
drivers/char/console.c
drivers/char/keyboard.c
drivers/char/mem.c
drivers/char/tty_io.c
drivers/net/Space.c
drivers/net/ppp.c
drivers/sound/Makefile
drivers/sound/Readme
drivers/sound/ad1848.c
drivers/sound/configure.c
drivers/sound/dev_table.h
drivers/sound/dmabuf.c
drivers/sound/sb_dsp.c
drivers/sound/sb_mixer.c
drivers/sound/sb_mixer.h
drivers/sound/sound_calls.h
drivers/sound/sound_config.h
include/linux/hdreg.h
include/linux/mm.h
include/linux/wait.h
kernel/ptrace.c
kernel/sched.c
mm/memory.c
net/inet/af_inet.c
net/inet/arp.c
net/inet/dev.c
net/inet/tcp.c

index e5b07536ee4c5a7293d373acfdafaa9e01d17e77..59052c4805dcb815bff39763346fc1d05b307f4a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 1
-SUBLEVEL = 31
+SUBLEVEL = 32
 
 all:   Version zImage
 
index 34e1f620ee89a6f4636a61b0d545057a6a7861ba..4ad54aec91a80a6fe2d0448834401769292631da 100644 (file)
--- a/config.in
+++ b/config.in
@@ -81,7 +81,6 @@ if [ "$CONFIG_SLIP" = "y" ]; then
 fi
 bool 'PPP (point-to-point) support' CONFIG_PPP n
 bool 'PLIP (parallel port) support' CONFIG_PLIP n
-bool 'SK_G16 support' CONFIG_SK_G16 n
 bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n
 bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n
 bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n
@@ -110,6 +109,7 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then
        fi
        bool 'HP PCLAN support' CONFIG_HPLAN n
        bool 'NE2000/NE1000 support' CONFIG_NE2000 y
+       bool 'SK_G16 support' CONFIG_SK_G16 n
 fi
 bool 'EISA and on board controllers' CONFIG_NET_EISA n
        if [ "$CONFIG_NET_ALPHA" = "y" ]; then
diff --git a/drivers/block/README.hd b/drivers/block/README.hd
new file mode 100644 (file)
index 0000000..d6d35ab
--- /dev/null
@@ -0,0 +1,98 @@
+IDE Performance Enhancements   Version 2.0
+============================   ===========
+
+This version of hd.c includes support for two optional features:
+
+(1) The disk I/O routines can now run with interrupts unmasked
+       most of the time, making them much friendlier to high
+       speed serial ports and other system activity.
+
+(2) Support is included for IDE "Multiple Sector Mode", the use
+       of which can reduce disk I/O kernel overhead by 10-30%
+       on many systems, with a corresponding 10-20% increase in
+       data throughput.
+
+By default, both features are DISABLED, for compatibility with
+       systems on which they may cause troubles.
+
+The IRQ unmasking has been known to CORRUPT FILESYSTEMS in the
+past on systems with strange hard drives.  Backup before trying!
+
+It works on most systems, but use at your own risk!!
+
+Drives which support "Multiple Sector Mode" are identified by the
+kernel at boot time, and a message is displayed indicating the
+largest possible setting for "MaxMult".  I recommend using settings
+of 8, 16, or 32.  Many drives also support non-powers of two,
+but many other drives do not -- try strange values at your own risk!
+
+For more detailed boot-time information about your drive, change
+the definition of VERBOSE_DRIVE_INFO from 0 to 1 near the top
+of hd.c and rebuild/reinstall the kernel.
+
+Some drives (mostly older CONNER drives) do not implement multiple mode
+correctly, and data corruption may occur.. but if you wait long enough
+the error recovery logic *should* be able to recover eventually.
+
+To try this out more safely, mount the drive's partitions read-only
+before using hdparm (see below) for the first time.  If it doesn't
+work, email me (mlord@bnr.ca) with the drive name as displayed at
+boot time, so I can warn others and possibly add a hook to the code.
+
+To enable the features, a small program is included:  hdparm.c
+This one is *different* from previous versions -- be sure to recompile it!
+
+Compile this using   cc -O -o /usr/bin/hdparm hdparm.c
+and then use it to enable/disable the new features, as follows:
+
+To turn on 16-sector multiple mode, with interrupt unmasking:
+
+       hdparm /dev/hda 16 1
+
+To view the current settings:
+
+       hdparm /dev/hda
+
+If you have more than one drive, a separate command would need to              be issued for the second drive as well, using the same or different
+settings as desired:
+
+       hdparm /dev/hdb 16 1
+
+To turn off both features on the first drive, use:
+
+       hdparm /dev/hda 0 0
+
+To benchmark the performance difference, try:
+
+       hdparm /dev/hda 0 0
+       sync
+       time dd if=/dev/hda of=/dev/null bs=1024k count=30
+       time dd if=/dev/hda of=/dev/null bs=1024k count=30
+       time dd if=/dev/hda of=/dev/null bs=1024k count=30
+       hdparm /dev/hda 16 1
+       sync
+       time dd if=/dev/hda of=/dev/null bs=1024k count=30
+       time dd if=/dev/hda of=/dev/null bs=1024k count=30
+       time dd if=/dev/hda of=/dev/null bs=1024k count=30
+
+This gives before and after views.  Compare the total elapsed times,
+as well as the percent of CPU used in each case.  Run several trials
+to ensure/verify consistent results.  Some drives are actually *slower*
+with multiple mode enabled, but those are very rare indeed.  Most systems
+experience a 10-30% increase in throughput, with a corresponding 5-50%
+decrease in kernel/system CPU usage.
+
+If you are using linux kernel 1.1.4 or higher (with the "cluster" code),
+then you may not notice a big difference with the above tests.  However,
+I have noticed that the iozone benchmark program does seem to work fairly
+reliably under kernels with the "cluster" code, so you could try that
+instead (under older kernels, iozone seems to give wildly varying results
+from trial to trial, at least on my system).
+
+To have your favorite settings installed automatically at boot time,
+place the hdparm command(s) into the /etc/rc.d/rc.local file.
+Alternatively, one could modify the DEFAULTs near the top of hd.c
+and rebuild and install the new kernel.
+
+Enjoy,
+mlord@bnr.ca
index 3ef65d287869a96e20f5b63a407824aca84289a9..3e93f79e5bb23dde56736dfe54ccb90f31ff8eb7 100644 (file)
  *
  *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  *  in the early extended-partition checks and added DM partitions
+ *
+ *  IDE IRQ-unmask & drive-id & multiple-mode code added by Mark Lord.
  */
 
+#define DEFAULT_MULT_COUNT  0  /* set to 0 to disable multiple mode at boot */
+#define DEFAULT_UNMASK_INTR 0  /* set to 0 to *NOT* unmask irq's more often */
+#define VERBOSE_DRIVE_INFO  0  /* set to 1 for more drive info at boot time */
 
+#include <asm/irq.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -211,6 +217,128 @@ static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
        outb_p(cmd,++port);
 }
 
+static void hd_request (void);
+unsigned int identified  [MAX_HD] = {0,}; /* 1 = drive ID already displayed   */
+unsigned int unmask_intr [MAX_HD] = {0,}; /* 1 = unmask IRQs during I/O       */
+unsigned int max_mult    [MAX_HD] = {0,}; /* max sectors for MultMode         */
+unsigned int mult_req    [MAX_HD] = {0,}; /* requested MultMode count         */
+unsigned int mult_count  [MAX_HD] = {0,}; /* currently enabled MultMode count */
+struct request WCURRENT;
+
+static void rawstring (char *prefix, char *s, int n)
+{
+       if (prefix)
+               printk(prefix);
+       if (s && *s) {
+               int i;
+               for (i=0; i < n && s[i^1] == ' '; ++i); /* skip blanks */
+               for (; i < n && s[i^1]; ++i)            /* flip bytes */
+                       if (s[i^1] != ' ' || ((i+1) < n && s[(i+1)^1] != ' '))
+                               printk("%c",s[i^1]);
+       }
+}
+
+#if VERBOSE_DRIVE_INFO
+
+char *cfg_str[] =
+{      "", " HardSect", " SoftSect", " NotMFM", " HdSw>15uSec", " SpinMotCtl",
+       " Fixed", " Removeable", " DTR<=5Mbs", " DTR>5Mbs", " DTR>10Mbs",
+       " RotSpdTol>.5%", " dStbOff", " TrkOff", " FmtGapReq", "",
+};
+
+char *ioready[]                = {"no", "?", "yes", "on/off"};
+char *SlowMedFast[]    = {"slow", "medium", "fast"};
+char *BuffType[]       = {"?", "1Sect", "DualPort", "DualPortCache"};
+
+#define YN(b)  (((b)==0)?"no":"yes")
+
+static void dmpstr (char *prefix, unsigned int i, char *s[], unsigned int maxi)
+{
+       printk(prefix);
+       printk( (i > maxi) ? "?" : s[i] );
+}
+
+static void dump_identity (unsigned int dev, unsigned short ib[])
+{
+       int i;
+       char dashes[] = "\n+-------------------------------------------------------------------+\n";
+       printk (dashes);
+       printk ("hd%c:  Drive Identification Info:\n", dev+'a');
+       rawstring (" Model=",(char *)&ib[27],40);
+       rawstring (", FwRev=",(char *)&ib[23],8);
+       rawstring (", SerialNo=",(char *)&ib[10],20);
+       printk ("\n Config={");
+       for (i=0; i<=15; i++) if (ib[0] & (1<<i)) printk (cfg_str[i]);
+       printk (" }\n");
+       printk (" Default c/h/s=%d/%d/%d, TrkSize=%d, SectSize=%d, ECCbytes=%d\n",
+               ib[1],ib[3],ib[6],ib[4],ib[5], ib[22]);
+       dmpstr (" BuffType=",ib[20],BuffType,3);
+       ib[47] &= 0xFF;
+       printk (", BuffSize=%dKB, MaxMultSect=%d\n", ib[21]/2, ib[47]);
+       printk (" Features: DblWordIO=%s, IORDY=%s, LBA=%s, DMA=%s",
+               YN(ib[48]&1),ioready[(ib[49]&0xC00)>>10],YN(ib[49]&0x200),YN(ib[49]&0x100));
+       dmpstr (", tPIO=",ib[51]>>8,SlowMedFast,2);
+       if (ib[49]&0x100 && (ib[53]&1))
+               dmpstr (", tDMA=",ib[52]>>8,SlowMedFast,2);
+       printk ("\n (%s): Current c/h/s=%d/%d/%d, TotSect=%d",
+               (((ib[53]&1)==0)?"maybe":"valid"),
+               ib[54],ib[55],ib[56],*(int *)&ib[57]);
+       if (ib[49]&0x200)
+               printk (", MaxLBAsect=%d", *(int *)&ib[60]);
+       printk("\n CurMultSect=%d%s",ib[59]&0xFF,(ib[59]&0x100)?"":"?");
+       if (ib[49]&0x100)
+               printk (", DMA-1w=%04X, DMA-mw=%04X", ib[62], ib[63]);
+       printk ("%s\n",dashes);
+}
+#endif /* VERBOSE_DRIVE_INFO */
+
+static void identify_intr(void)
+{
+       unsigned int dev = DEVICE_NR(CURRENT->dev);
+       unsigned short ib[64], stat = inb_p(HD_STATUS);
+
+       if (unmask_intr[dev])
+               sti();
+       if (stat & (BUSY_STAT|ERR_STAT))
+               printk ("  hd%c: multiple mode not supported\n", dev+'a');
+       else {
+               insw(HD_DATA,(char *)ib,64); /* get first 128 ID bytes */
+#if VERBOSE_DRIVE_INFO
+               dump_identity(dev, ib);
+#endif
+               printk ("  hd%c: ", dev+'a');
+               rawstring(NULL, (char *)&ib[27], 40);
+               max_mult[dev] = ib[47] & 0xff;
+               printk (" (%dMB IDE w/%dKB Cache, MaxMult=%d)\n",
+                       ib[1]*ib[3]*ib[6] / 2048, ib[21]>>1, max_mult[dev]);
+               insw(HD_DATA,(char *)ib,64); /* flush remaining 384 ID bytes */
+               insw(HD_DATA,(char *)ib,64);
+               insw(HD_DATA,(char *)ib,64);
+       }
+       hd_request();
+       return;
+}
+
+static void set_multmode_intr(void)
+{
+       unsigned int dev = DEVICE_NR(CURRENT->dev), stat = inb_p(HD_STATUS);
+
+       if (unmask_intr[dev])
+               sti();
+       if (stat & (BUSY_STAT|ERR_STAT)) {
+               mult_req[dev] = mult_count[dev] = 0;
+               printk ("  hd%c: set multiple mode failed\n", dev+'a');
+       } else {
+               if ((mult_count[dev] = mult_req[dev]))
+                       printk ("  hd%c: enabled %d-sector multiple mode\n",
+                               dev+'a', mult_count[dev]);
+               else
+                       printk ("  hd%c: disabled multiple mode\n", dev+'a');
+       }
+       hd_request();
+       return;
+}
+
 static int drive_busy(void)
 {
        unsigned int i;
@@ -254,14 +382,21 @@ repeat:
                if (reset)
                        goto repeat;
        }
-       i++;
-       if (i < NR_HD) {
+       if (++i < NR_HD) {
+               if (unmask_intr[i]) {
+                       printk("hd%c: disabled irq-unmasking\n",i+'a');
+                       unmask_intr[i] = 0;
+               }
+               if (mult_req[i] || mult_count[i]) {
+                       printk("hd%c: disabled multiple mode\n",i+'a');
+                       mult_req[i] = mult_count[i] = 0;
+               }
                hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
                        hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
                if (reset)
                        goto repeat;
        } else
-               do_hd_request();
+               hd_request();
 }
 
 /*
@@ -313,9 +448,11 @@ static inline int wait_DRQ(void)
 
 static void read_intr(void)
 {
-       int i;
-       int retries = 100000;
+       unsigned int dev = DEVICE_NR(CURRENT->dev);
+       int i, retries = 100000, msect, nsect;
 
+       if (unmask_intr[dev])
+               sti();                  /* permit other IRQs during xfer */
        do {
                i = (unsigned) inb_p(HD_STATUS);
                if (i & BUSY_STAT)
@@ -326,42 +463,111 @@ static void read_intr(void)
                        goto ok_to_read;
        } while (--retries > 0);
        sti();
-       printk("HD: read_intr: status = 0x%02x\n",i);
+       printk("hd%c: read_intr: status = 0x%02x\n",dev+'a',i);
        if (i & ERR_STAT) {
                hd_error = (unsigned) inb(HD_ERROR);
-               printk("HD: read_intr: error = 0x%02x\n",hd_error);
+               printk("hd%c: read_intr: error = 0x%02x\n",dev+'a',hd_error);
        }
        bad_rw_intr();
        cli();
-       do_hd_request();
+       hd_request();
        return;
 ok_to_read:
-       insw(HD_DATA,CURRENT->buffer,256);
+       msect = mult_count[dev];
+read_next:
+       if (msect) {
+               if ((nsect = CURRENT->current_nr_sectors) > msect)
+                       nsect = msect;
+               msect -= nsect;
+       } else
+               nsect = 1;
+       insw(HD_DATA,CURRENT->buffer,nsect<<8);
+       CURRENT->sector += nsect;
+       CURRENT->buffer += nsect<<9;
        CURRENT->errors = 0;
-       CURRENT->buffer += 512;
-       CURRENT->sector++;
-       i = --CURRENT->nr_sectors;
-       --CURRENT->current_nr_sectors;
+       i = (CURRENT->nr_sectors -= nsect);
+
 #ifdef DEBUG
-       printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
-               MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT-> 
-               buffer);
+       printk("hd%c: read: sectors(%ld-%ld), remaining=%ld, buffer=%08lx\n",
+               dev+'a', CURRENT->sector, CURRENT->sector+nsect,
+               CURRENT->nr_sectors, (long) CURRENT->buffer+(nsect<<9));
 #endif
-       if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+       if ((CURRENT->current_nr_sectors -= nsect) <= 0)
                end_request(1);
        if (i > 0) {
+               if (msect)
+                       goto read_next;
                SET_INTR(&read_intr);
-               sti();
                return;
        }
        (void) inb_p(HD_STATUS);
 #if (HD_DELAY > 0)
        last_req = read_timer();
 #endif
-       do_hd_request();
+       if (CURRENT)
+               hd_request();
        return;
 }
 
+static inline void multwrite (unsigned int dev)
+{
+       unsigned int mcount = mult_count[dev];
+
+       while (mcount--) {
+               outsw(HD_DATA,WCURRENT.buffer,256);
+               if (!--WCURRENT.nr_sectors)
+                       return;
+               WCURRENT.buffer += 512;
+               if (!--WCURRENT.current_nr_sectors) {
+                       WCURRENT.bh = WCURRENT.bh->b_reqnext;
+                       if (WCURRENT.bh == NULL)
+                               panic("buffer list corrupted\n");
+                       WCURRENT.current_nr_sectors = WCURRENT.bh->b_size>>9;
+                       WCURRENT.buffer             = WCURRENT.bh->b_data;
+               }
+       }
+}
+
+static void multwrite_intr(void)
+{
+       int i;
+       unsigned int dev = DEVICE_NR(WCURRENT.dev);
+
+       if (unmask_intr[dev])
+               sti();
+       if (((i = inb_p(HD_STATUS)) & STAT_MASK) == STAT_OK) {
+               if (i & DRQ_STAT) {
+                       if (WCURRENT.nr_sectors) {
+                               multwrite(dev);
+                               SET_INTR(&multwrite_intr);
+                               return;
+                       }
+               } else {
+                       if (!WCURRENT.nr_sectors) {     /* all done? */
+                               for (i = CURRENT->nr_sectors; i > 0;){
+                                       i -= CURRENT->current_nr_sectors;
+                                       end_request(1);
+                               }
+#if (HD_DELAY > 0)
+                               last_req = read_timer();
+#endif
+                               if (CURRENT)
+                                       hd_request();
+                               return;
+                       }
+               }
+       }
+       sti();
+       printk("hd%c: multwrite_intr: status = 0x%02x\n",dev+'a',i);
+       if (i & ERR_STAT) {
+               hd_error = (unsigned) inb(HD_ERROR);
+               printk("hd:%c multwrite_intr: error = 0x%02x\n",dev+'a',hd_error);
+       }
+       bad_rw_intr();
+       cli();
+       hd_request();
+}
+
 static void write_intr(void)
 {
        int i;
@@ -384,7 +590,7 @@ static void write_intr(void)
        }
        bad_rw_intr();
        cli();
-       do_hd_request();
+       hd_request();
        return;
 ok_to_write:
        CURRENT->sector++;
@@ -401,7 +607,7 @@ ok_to_write:
 #if (HD_DELAY > 0)
                last_req = read_timer();
 #endif
-               do_hd_request();
+               hd_request();
        }
        return;
 }
@@ -410,7 +616,7 @@ static void recal_intr(void)
 {
        if (win_result())
                bad_rw_intr();
-       do_hd_request();
+       hd_request();
 }
 
 /*
@@ -433,7 +639,7 @@ static void hd_times_out(void)
                end_request(0);
        }
 
-       do_hd_request();
+       hd_request();
 }
 
 /*
@@ -443,7 +649,7 @@ static void hd_times_out(void)
  * worst that can happen is that an unexpected HD-interrupt comes in and
  * sets the "reset" variable and starts the timer)
  */
-static void do_hd_request(void)
+static void hd_request(void)
 {
        unsigned int block,dev;
        unsigned int sec,head,cyl,track;
@@ -462,7 +668,7 @@ repeat:
        nsect = CURRENT->nr_sectors;
        if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
 #ifdef DEBUG
-               printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
+               printk("hd : attempted read for sector %d past end of device at sector %d.\n",
                        block, hd[dev].nr_sects);
 #endif
                end_request(0);
@@ -475,17 +681,18 @@ repeat:
        head = track % hd_info[dev].head;
        cyl = track / hd_info[dev].head;
 #ifdef DEBUG
-       printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
-               dev, cyl, head, sec, CURRENT->buffer);
+       printk("hd%c : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
+               dev+'a', cyl, head, sec, CURRENT->buffer);
 #endif
-       cli();
+       if (!unmask_intr[dev])
+               cli();
        if (reset) {
                int i;
 
                for (i=0; i < NR_HD; i++)
                        recalibrate[i] = 1;
+               cli(); /* better play it safe, as resets are the last resort */
                reset_hd();
-               sti();
                return;
        }
        if (recalibrate[dev]) {
@@ -493,32 +700,70 @@ repeat:
                hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
                if (reset)
                        goto repeat;
-               sti();
                return;
        }       
-       if (CURRENT->cmd == WRITE) {
-               hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+       if (!identified[dev]) {
+               identified[dev]  = 1;
+               unmask_intr[dev] = DEFAULT_UNMASK_INTR;
+               mult_req[dev]    = DEFAULT_MULT_COUNT;
+               hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);
                if (reset)
                        goto repeat;
-               if (wait_DRQ()) {
-                       printk("HD: do_hd_request: no DRQ\n");
-                       bad_rw_intr();
+               return;
+       }
+       if (mult_req[dev] != mult_count[dev]) {
+               hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);
+               if (reset)
                        goto repeat;
-               }
-               outsw(HD_DATA,CURRENT->buffer,256);
-               sti();
                return;
        }
        if (CURRENT->cmd == READ) {
-               hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
+               unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;
+               hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);
                if (reset)
                        goto repeat;
-               sti();
+#ifdef DEBUG
+               printk("hd%c: reading %d sectors(%ld-%ld), buffer=%08lx\n",
+                       dev+'a', nsect, CURRENT->sector,
+                       CURRENT->sector+nsect-1, (long) CURRENT->buffer);
+#endif
+               return;
+       }
+       if (CURRENT->cmd == WRITE) {
+               if (mult_count[dev])
+                       hd_out(dev,nsect,sec,head,cyl,WIN_MULTWRITE,&multwrite_intr);
+               else
+                       hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
+               if (reset)
+                       goto repeat;
+#ifdef DEBUG
+               printk("hd%c: writing %d sectors(%ld-%ld), buffer=%08lx\n",
+                       dev+'a', nsect, CURRENT->sector,
+                       CURRENT->sector+nsect-1, (long) CURRENT->buffer);
+#endif
+               if (wait_DRQ()) {
+                       printk("hd%c: hd_request: no DRQ\n", dev+'a');
+                       bad_rw_intr();
+                       goto repeat;
+               }
+               if (mult_count[dev]) {
+                       WCURRENT = *CURRENT;
+                       multwrite(dev);
+               } else {
+                       outsw(HD_DATA,CURRENT->buffer,256);
+               }
                return;
        }
        panic("unknown hd-command");
 }
 
+static void do_hd_request (void)
+{
+       disable_irq(HD_IRQ);
+       hd_request();
+       enable_irq(HD_IRQ);
+}
+
 static int hd_ioctl(struct inode * inode, struct file * file,
        unsigned int cmd, unsigned long arg)
 {
@@ -568,6 +813,53 @@ static int hd_ioctl(struct inode * inode, struct file * file,
 
                case BLKRRPART: /* Re-read partition tables */
                        return revalidate_hddisk(inode->i_rdev, 1);
+
+               case HDIO_SETUNMASKINTR:
+                       if (!arg)  return -EINVAL;
+                       err = verify_area(VERIFY_READ, (long *) arg, sizeof(long));
+                       if (err)
+                               return err;
+                       unmask_intr[dev] = get_fs_long((long *) arg);
+                       return 0;
+
+                case HDIO_GETUNMASKINTR:
+                       if (!arg)  return -EINVAL;
+                       err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+                       if (err)
+                               return err;
+                       put_fs_long(unmask_intr[dev], (long *) arg);
+                       return 0;
+
+                case HDIO_GETMULTCOUNT:
+                       if (!arg)  return -EINVAL;
+                       err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+                       if (err)
+                               return err;
+                       put_fs_long(mult_count[dev], (long *) arg);
+                       return 0;
+
+               case HDIO_SETMULTCOUNT:
+               {
+                       unsigned long flags;
+                       if (!arg)  return -EINVAL;
+                       err = verify_area(VERIFY_READ, (long *) arg, sizeof(long));
+                       if (err)
+                               return err;
+                       arg = get_fs_long((long *) arg);
+                       save_flags(flags);
+                       cli();  /* a prior request might still be in progress */
+                       if (arg > max_mult[dev])
+                               err = -EINVAL;  /* out of range for device */
+                       else if (mult_req[dev] != mult_count[dev])
+                               err = -EBUSY;   /* busy, try again */
+                       else {
+                               mult_req[dev] = arg;
+                               err = 0;
+                       }
+                       restore_flags(flags);
+                       return err;
+               }
+
                RO_IOCTLS(inode->i_rdev,arg);
                default:
                        return -EINVAL;
index 4c43aee9943049a4f6a085953e5d88583ee25b4a..7ffafdc75d7ffc376e387c82c2502599e6d33aad 100644 (file)
@@ -83,6 +83,7 @@ static struct termios *console_termios_locked[NR_CONSOLES];
 int set_selection(const int arg);
 int paste_selection(struct tty_struct *tty);
 static void clear_selection(void);
+static void highlight_pointer(const int currcons, const int where);
 
 /* Variables for selection control. */
 #define SEL_BUFFER_SIZE 4096
@@ -1703,6 +1704,9 @@ void update_screen(int new_console)
                return;
        lock = 1;
        kbdsave(new_console);
+#ifdef CONFIG_SELECTION
+       highlight_pointer(fg_console,-1);
+#endif /* CONFIG_SELECTION */
        get_scrmem(fg_console); 
        fg_console = new_console;
        set_scrmem(fg_console); 
@@ -1778,8 +1782,49 @@ static void highlight(const int currcons, const int s, const int e)
                *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07);
 }
 
-/* is c in range [a-zA-Z0-9_]? */
-static inline int inword(const char c) { return (isalnum(c) || c == '_'); }
+/* use complementary color to show the pointer */
+static void highlight_pointer(const int currcons, const int where)
+{
+        unsigned char *p;
+       static char *prev=NULL;
+
+       if (where==-1) /* remove the pointer */
+       {
+                if (prev)
+               {
+                       *prev ^= 0x77;
+                       prev=NULL;
+               }
+        }
+       else
+       {
+               p = (unsigned char *)origin - hwscroll_offset + where + 1;
+               *p ^= 0x77;
+               if (prev) *prev ^= 0x77; /* remove the previous one */
+               prev=p;
+       }
+}
+
+
+/*
+ * This function uses a 128-bit look up table
+ */
+static unsigned long inwordLut[4]={
+  0x00000000, /* control chars     */
+  0x03FF0000, /* digits            */
+  0x87FFFFFE, /* uppercase and '_' */
+  0x07FFFFFE  /* lowercase         */
+};
+static inline int inword(const char c) {
+   return ( inwordLut[(c>>5)&3] >> (c&0x1F) ) & 1;
+}
+
+/* set inwordLut conntents. Invoked by ioctl(). */
+int sel_loadlut(const int arg)
+{
+    memcpy_fromfs(inwordLut,(unsigned long *)(arg+4),16);
+    return 0;
+}
 
 /* does screen address p correspond to character at LH/RH edge of screen? */
 static inline int atedge(const int p)
@@ -1828,7 +1873,6 @@ int set_selection(const int arg)
        switch (sel_mode)
        {
                case 0: /* character-by-character selection */
-               default:
                        new_sel_start = ps;
                        new_sel_end = pe;
                        break;
@@ -1859,6 +1903,17 @@ int set_selection(const int arg)
                        new_sel_end = pe + video_size_row
                                    - pe % video_size_row - 2;
                        break;
+                case 3: /* pointer highlight */
+                       if (sel_cons != currcons)
+                       {
+                               highlight_pointer(sel_cons,-1);
+                               clear_selection();
+                               sel_cons = currcons;
+                       }
+                       highlight_pointer(sel_cons,pe);
+                       return 0; /* nothing more */
+               default:
+                       return -EINVAL;
        }
        /* select to end of line if on trailing space */
        if (new_sel_end > new_sel_start &&
@@ -1962,6 +2017,7 @@ int paste_selection(struct tty_struct *tty)
    the selection. */
 static void clear_selection()
 {
+        highlight_pointer(sel_cons, -1); /* hide the pointer */
        if (sel_start != -1)
        {
                highlight(sel_cons, sel_start, sel_end);
index 9c8bd47a91c31cb7197d2fc0f1d70383bc8d828a..f021eef82543a0908a2bd7dedd9bc6ef938fbc4c 100644 (file)
@@ -86,7 +86,12 @@ static unsigned long key_down[8] = { 0, };
 static int want_console = -1;
 static int last_console = 0;           /* last used VC */
 static int dead_key_next = 0;
-static int shift_state = 0;
+/* 
+ * In order to retrieve the shift_state (for the mouse server), either
+ * the variable must be global, or a new procedure must be create to 
+ * return the value. I chose the former way.
+ */
+/*static*/ int shift_state = 0;
 static int npadch = -1;                        /* -1 or number assembled on pad */
 static unsigned char diacr = 0;
 static char rep = 0;                   /* flag telling character repeat */
index e279ea24ed558e262b3ebfaf431a0088f7f0c7ec..e859a9a0f55bae6af0858c98e9da51bb7b7701f2 100644 (file)
@@ -420,7 +420,7 @@ long chr_dev_init(long mem_start, long mem_end)
 #ifdef CONFIG_FTAPE
         /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */
         ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff);
-        printk( "ftape: allocated %d buffers alligned at: %p\n",
+        printk( "ftape: allocated %d buffers aligned at: %p\n",
                NR_FTAPE_BUFFERS, ftape_big_buffer);
         mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000;
 #endif 
index 1fad5d82fb48ac1eec3f9dff1f6937a405ad3252..29ba87cb49291926934d1eb511b8bebd04f90aca 100644 (file)
@@ -68,6 +68,8 @@
 #ifdef CONFIG_SELECTION
 extern int set_selection(const int arg);
 extern int paste_selection(struct tty_struct *tty);
+extern int sel_loadlut(const int arg);
+extern int shift_state;
 #endif /* CONFIG_SELECTION */
 extern int do_screendump(int arg);
 
@@ -1385,6 +1387,11 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                                case 4:
                                        unblank_screen();
                                        return 0;
+                               case 5:
+                                       return sel_loadlut(arg);
+                               case 6:
+                                       put_fs_byte(shift_state,arg);
+                                       return 0;
 #endif /* CONFIG_SELECTION */
                                default: 
                                        return -EINVAL;
index 0fb46432876b97fe8482dbce062be4c05183c255..dd38c70603bba3bbbab52a5c070934b9a4915911 100644 (file)
@@ -54,7 +54,9 @@ extern int el16_probe(struct device *);
 extern int elplus_probe(struct device *);
 extern int ac3200_probe(struct device *);
 extern int e2100_probe(struct device *);
-extern int SK_init(struct device *dev);
+extern int ni52_probe(struct device *);
+extern int ni65_probe(struct device *);
+extern int SK_init(struct device *);
 
 /* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */
 extern int atp_init(struct device *);
@@ -129,6 +131,12 @@ ethif_probe(struct device *dev)
 #endif
 #if defined(CONFIG_SK_G16)
        && SK_init(dev)
+#endif
+#ifdef CONFIG_NI52
+       && ni52_probe(dev)
+#endif
+#ifdef CONFIG_NI65
+       && ni65_probe(dev)
 #endif
        && 1 ) {
        return 1;       /* -ENODEV or -EAGAIN would be more accurate. */
index 4e7a5b5a2d072103d743c4aba12f655624441742..a73e192c744199dba9e80183a84d5c4d7db477ff 100644 (file)
@@ -267,7 +267,6 @@ ppp_init(struct device *dev)
   dev->mtu             = PPP_MTU;
   dev->hard_start_xmit = ppp_xmit;
   dev->open            = ppp_dev_open;
-  dev->do_ioctl        = ppp_dev_ioctl;
   dev->stop            = ppp_dev_close;
   dev->get_stats       = ppp_get_stats;
   dev->hard_header     = ppp_header;
@@ -280,6 +279,8 @@ ppp_init(struct device *dev)
 #ifdef NET02D
   dev->add_arp         = ppp_add_arp;
   dev->queue_xmit      = dev_queue_xmit;
+#else
+  dev->do_ioctl        = ppp_dev_ioctl;
 #endif
 
   for (i = 0; i < DEV_NUMBUFFS; i++)
@@ -605,6 +606,7 @@ ppp_dev_close(struct device *dev)
   return 0;
 }
 
+#ifndef NET02D
 static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr)
 {
   struct ppp *ppp = &ppp_ctrl[dev->base_addr];
@@ -630,6 +632,7 @@ static int ppp_dev_ioctl(struct device *dev, struct ifreq *ifr)
 
   return error;
 }
+#endif
 
 /*************************************************************
  * TTY OUTPUT
@@ -650,7 +653,11 @@ ppp_output_done (void *ppp)
   /* If the device is still up then enable the transmitter of the
      next frame. */
   if (((struct ppp *) ppp)->dev->flags & IFF_UP)
+#ifndef NET02D
+    mark_bh (NET_BH);
+#else
     dev_tint (((struct ppp *) ppp)->dev);
+#endif
 
   /* enable any blocked process pending transmission */
   wake_up_interruptible (&((struct ppp *) ppp)->write_wait);
@@ -1124,9 +1131,7 @@ ppp_do_ip (struct ppp *ppp, unsigned short proto, unsigned char *c,
   }
 
   /* receive the frame through the network software */
-  while ((dev_rint(c, count, 0, ppp->dev) & ~1) != 0)
-    ;
-
+  (void) dev_rint (c, count, 0, ppp->dev);
   return 1;
 }
 
index e6fc09ba2bb2e47bcdf69dbf1f1cbee90cb2db36..46925926d253725bcd62d312c5e215c4230da7d7 100644 (file)
@@ -5,7 +5,7 @@
 #
 #
 
-VERSION                = 2.90
+VERSION                = 2.90-2
 TARGET_OS      = linux
 
 .c.s:
index a7653246322edee9b6b3d48a78d2972cd8600b0d..a4a084706e5ba8482f92696e97277c9b390d34e7 100644 (file)
@@ -12,8 +12,8 @@ VoxWare v2.90 release notes
                there are some new features required by a popular 
                application. In addition there is also support
                for the GUS MAX and the 16 bit sampling option of GUS.
-               Also the Windows Sound System stuff is there but may not
-               work yet (may work with some WSS compatible cards).
+
+               The MSS/WSS support works now. At least with SG NX Pro 16.
 
 ********* IMPORTANT *****************************************
 Linux 1.0 or later is required to by this driver version.
@@ -65,6 +65,7 @@ contributors. (I could have forgotten some names.)
        Markus Aroharju and
        Risto Kankkunen         Major contributions to the mixer support
                                of GUS v3.7.
+       Hunyue Yau      Mixer support for SG NX Pro.
        Marc Hoffman    PSS support.
 
 Regards,
index c42e11c55fc7cb9bb41294d56e7dc81722ecd79d..b08f5f76cc68cca0cf6156f6fe29083aefd8493f 100644 (file)
@@ -903,16 +903,14 @@ ad1848_interrupt (int irq)
 int
 probe_ms_sound (struct address_info *hw_config)
 {
-  int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
-
   if ((INB (hw_config->io_base + 3) & 0x04) == 0)
     return 0;                  /* WSS ID test failed */
 
   if (hw_config->irq > 11)
-    return;
+    return 0;
 
-  if (hw_config->dma > 3 || hw_config->dma == 2)
-    return;
+  if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3)
+       return 0;
 
   return ad1848_detect (hw_config->io_base + 4);
 }
@@ -920,10 +918,12 @@ probe_ms_sound (struct address_info *hw_config)
 long
 attach_ms_sound (long mem_start, struct address_info *hw_config)
 {
-  static unsigned char interrupt_bits[11] =
+  static unsigned char interrupt_bits[12] =
   {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20};
   char            bits;
 
+  static unsigned char dma_bits[4] = {1, 2, 0, 3};
+
   int             config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
 
   if (!ad1848_detect (hw_config->io_base + 4))
@@ -941,7 +941,7 @@ attach_ms_sound (long mem_start, struct address_info *hw_config)
   if ((INB (version_port) & 0x40) == 0)
     printk ("[IRQ?]");
 
-  OUTB (bits | hw_config->dma, config_port);   /* Write IRQ+DMA setup */
+  OUTB (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */
 
   ad1848_init ("MS Sound System", hw_config->io_base + 4,
               hw_config->irq,
index e1cbc7b3021bcb64b778c2e65b86a675e7ccdaa8..5b7217bccb4668597a4e5493c5835039bcb41ba4 100644 (file)
@@ -322,6 +322,13 @@ main (int argc, char *argv[])
          }
     }
 
+  if (selected_options & B (OPT_SBPRO))
+    {
+      fprintf(stderr, "Do you want support for the mixer of SG NX Pro ? ");
+      if (think_positively (0))
+        printf("#define __SGNXPRO__\n");
+    }
+
   if (selected_options & B (OPT_SB16))
     selected_options |= B (OPT_SBPRO);
 
@@ -333,7 +340,7 @@ main (int argc, char *argv[])
        "if you wish to emulate the soundblaster and you have a DSPxxx.LD.\n"
         "then you must include the LD in the kernel.\n"
         "(do you wish to include a LD) ? ");
-      if (think_positively (1))
+      if (think_positively (0))
        {
          char            path[512];
 
index a2bf8e68931e4bf7cb6df4ad30987d7d2adefe51..12b20baf7d8289028453ccea50352bb47bced617 100644 (file)
@@ -278,6 +278,9 @@ struct sound_timer_operations {
 #endif
 #ifndef EXCLUDE_MSS
                {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA}, SND_DEFAULT_ENABLE},
+#      ifdef MSS2_BASE
+               {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA}, SND_DEFAULT_ENABLE},
+#      endif
 #endif
 
 #if !defined(EXCLUDE_UART6850) && !defined(EXCLUDE_MIDI)
index 0e275b6a3aea1cef99e1a04cf8043dae35ad87dc..be24074f1b31cbc824a180683c8f368fd0639561 100644 (file)
@@ -320,7 +320,7 @@ DMAbuf_getrdbuffer (int dev, char **buf, int *len)
       if (!(dmap->flags & DMA_ALLOC_DONE))
        reorganize_buffers (dev);
 
-      if (dmap->dma_mode)
+      if (!dmap->dma_mode)
        {
          int             err;
 
index 0e3936b1fb1be6a93171c744d169aa9c2f95f077..37be35c4cfca6a817d064dcc39011e18aa78ab28 100644 (file)
@@ -1,9 +1,9 @@
 /*
  * sound/sb_dsp.c
  *
- * The low level driver for the SoundBlaster DSP chip.
+ * The low level driver for the SoundBlaster DSP chip (SB1.0 to 2.1, SB Pro).
  *
- * Copyright by Hannu Savolainen 1993
+ * Copyright by Hannu Savolainen 1994
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * Modified:
+ *     Hunyue Yau      Jan 6 1994
+ *     Added code to support Sound Galaxy NX Pro
+ *
  */
 
 #include "sound_config.h"
@@ -756,6 +760,7 @@ long
 sb_dsp_init (long mem_start, struct address_info *hw_config)
 {
   int             i;
+  int             mixer_type = 0;
 
   sbc_major = sbc_minor = 0;
   sb_dsp_command (0xe1);       /*
@@ -786,7 +791,7 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
 
 #ifndef EXCLUDE_SBPRO
   if (sbc_major >= 3)
-    sb_mixer_init (sbc_major);
+    mixer_type = sb_mixer_init (sbc_major);
 #endif
 
 #ifndef EXCLUDE_YM8312
@@ -799,7 +804,16 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
   if (sbc_major >= 3)
     {
 #ifndef SCO
-      sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
+#  ifdef __SGNXPRO__
+      if (mixer_type == 2)
+       {
+         sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor);
+       }
+      else
+#  endif
+       {
+         sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor);
+       }
 #endif
     }
   else
index 92d3c64368a5bce10ea6e53a9a3eadc7af51c9dd..312a15c76fb97bb732f2be71777e3562090d4cae 100644 (file)
@@ -4,7 +4,7 @@
  *
  * The low level mixer driver for the SoundBlaster Pro and SB16 cards.
  *
- * Copyright by Hannu Savolainen 1993
+ * Copyright by Hannu Savolainen 1994
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
+ * Modified:
+ *     Hunyue Yau      Jan 6 1994
+ *     Added code to support the Sound Galaxy NX Pro mixer.
+ *
  */
 
 #include "sound_config.h"
@@ -91,9 +95,21 @@ sb_mixer_set_stereo (int mode)
                            | (mode ? STEREO_DAC : MONO_DAC)));
 }
 
+/*
+ * Returns:
+ *     0       No mixer detected.
+ *     1       Only a plain Sound Blaster Pro style mixer detected.
+ *     2       The Sound Galaxy NX Pro mixer detected.
+ */
 static int
 detect_mixer (void)
 {
+#ifdef __SGNXPRO__
+  int             oldbass, oldtreble;
+
+#endif
+  int             retcode = 1;
+
   /*
    * Detect the mixer by changing parameters of two volume channels. If the
    * values read back match with the values written, the mixer is there (is
@@ -109,7 +125,30 @@ detect_mixer (void)
   if (sb_getmixer (VOC_VOL) != 0x33)
     return 0;
 
-  return 1;
+#ifdef __SGNXPRO__
+  /* Attempt to detect the SG NX Pro by check for valid bass/treble
+ * registers.
+ */
+  oldbass = sb_getmixer (BASS_LVL);
+  oldtreble = sb_getmixer (TREBLE_LVL);
+
+  sb_setmixer (BASS_LVL, 0xaa);
+  sb_setmixer (TREBLE_LVL, 0x55);
+
+  if ((sb_getmixer (BASS_LVL) != 0xaa) ||
+      (sb_getmixer (TREBLE_LVL) != 0x55))
+    {
+      retcode = 1;             /* 1 == Only SB Pro detected */
+    }
+  else
+    retcode = 2;               /* 2 == SG NX Pro detected */
+  /* Restore register in either case since SG NX Pro has EEPROM with
+   * 'preferred' values stored.
+   */
+  sb_setmixer (BASS_LVL, oldbass);
+  sb_setmixer (TREBLE_LVL, oldtreble);
+#endif
+  return retcode;
 }
 
 static void
@@ -350,17 +389,23 @@ sb_mixer_reset (void)
   set_recmask (SOUND_MASK_MIC);
 }
 
-void
+/*
+ * Returns a code depending on whether a SG NX Pro was detected.
+ * 1 == Plain SB Pro
+ * 2 == SG NX Pro detected.
+ * 3 == SB16
+ *
+ * Used to update message.
+ */
+int
 sb_mixer_init (int major_model)
 {
-  sb_setmixer (0x00, 0);       /*
-                                * Reset mixer
-                                */
+  int             mixer_type = 0;
 
-  if (!detect_mixer ())
-    return;                    /*
-                                * No mixer. Why?
-                                */
+  sb_setmixer (0x00, 0);       /* Reset mixer */
+
+  if (!(mixer_type = detect_mixer ()))
+    return 0;                  /* No mixer. Why? */
 
   mixer_initialized = 1;
   mixer_model = major_model;
@@ -369,9 +414,21 @@ sb_mixer_init (int major_model)
     {
     case 3:
       mixer_caps = SOUND_CAP_EXCL_INPUT;
-      supported_devices = SBPRO_MIXER_DEVICES;
-      supported_rec_devices = SBPRO_RECORDING_DEVICES;
-      iomap = &sbpro_mix;
+#ifdef __SGNXPRO__
+      if (mixer_type == 2)     /* A SGNXPRO was detected */
+       {
+         supported_devices = SGNXPRO_MIXER_DEVICES;
+         supported_rec_devices = SGNXPRO_RECORDING_DEVICES;
+         iomap = &sgnxpro_mix;
+       }
+      else
+#endif
+       {
+         supported_devices = SBPRO_MIXER_DEVICES;
+         supported_rec_devices = SBPRO_RECORDING_DEVICES;
+         iomap = &sbpro_mix;
+         mixer_type = 1;
+       }
       break;
 
     case 4:
@@ -379,16 +436,18 @@ sb_mixer_init (int major_model)
       supported_devices = SB16_MIXER_DEVICES;
       supported_rec_devices = SB16_RECORDING_DEVICES;
       iomap = &sb16_mix;
+      mixer_type = 3;
       break;
 
     default:
       printk ("SB Warning: Unsupported mixer type\n");
-      return;
+      return 0;
     }
 
   if (num_mixers < MAX_MIXER_DEV)
     mixer_devs[num_mixers++] = &sb_mixer_operations;
   sb_mixer_reset ();
+  return mixer_type;
 }
 
 #endif
index b0b5f58a1f6ffb0957b56c45ba0d48587aa7d65f..1a5fc8adfd3628087e184cd1a793b3aed0ec3205 100644 (file)
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
+ *
+ * Modified:
+ *     Hunyue Yau      Jan 6 1994
+ *     Added defines for the Sound Galaxy NX Pro mixer.
  * 
  */
+
 #define SBPRO_RECORDING_DEVICES        (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
 
+/* Same as SB Pro, unless I find otherwise */
+#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
+
 #define SBPRO_MIXER_DEVICES            (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
                                         SOUND_MASK_CD | SOUND_MASK_VOLUME)
 
+/* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
+ * channel is the COVOX/DisneySoundSource emulation volume control
+ * on the mixer. It does NOT control speaker volume. Should have own
+ * mask eventually?
+ */
+#define SGNXPRO_MIXER_DEVICES  (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
+                                SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
+
 #define SB16_RECORDING_DEVICES         (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
                                         SOUND_MASK_CD)
 
 #define IRQ_STAT       0x82
 #define OPSW           0x3c
 
+/*
+ * Additional registers on the SG NX Pro 
+ */
+#define COVOX_VOL      0x42
+#define TREBLE_LVL     0x44
+#define BASS_LVL       0x46
+
 #define FREQ_HI         (1 << 3)/* Use High-frequency ANFI filters */
 #define FREQ_LOW        0      /* Use Low-frequency ANFI filters */
 #define FILT_ON         0      /* Yes, 0 to turn it on, 1 for off */
@@ -108,6 +131,23 @@ MIX_ENT(SOUND_MIXER_ALTPCM,        0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0)
 };
 
+#ifdef __SGNXPRO__
+mixer_tab sgnxpro_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,    0x22, 7, 4, 0x22, 3, 4),
+MIX_ENT(SOUND_MIXER_BASS,      0x46, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,    0x44, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,     0x26, 7, 4, 0x26, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,       0x04, 7, 4, 0x04, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,   0x42, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,      0x2e, 7, 4, 0x2e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,       0x0a, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_CD,                0x28, 7, 4, 0x28, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,    0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,    0x00, 0, 0, 0x00, 0, 0)
+};
+#endif
+
 mixer_tab sb16_mix = {
 MIX_ENT(SOUND_MIXER_VOLUME,    0x30, 7, 5, 0x31, 7, 5),
 MIX_ENT(SOUND_MIXER_BASS,      0x46, 7, 4, 0x47, 7, 4),
index cbef1a4baf95e57dc3f32e531aac8cbb0d13573f..eccd9b67336e8f21ee5aa862d0288626a53d7575 100644 (file)
@@ -140,7 +140,7 @@ void sb_midi_init(int model);
 void sb_setmixer (unsigned int port, unsigned int value);
 int sb_getmixer (unsigned int port);
 void sb_mixer_set_stereo(int mode);
-void sb_mixer_init(int major_model);
+int sb_mixer_init(int major_model);
 
 /*     From opl3.c     */
 int opl3_detect (int ioaddr);
index 68e61632b9163c2db904fcc69a68472aa3a1f142..6c53c8cdd0cdc993bd80fc57207f0fd7cc7f5632 100644 (file)
@@ -180,7 +180,7 @@ If your card has nonstandard I/O address or IRQ number, change defines
  * In v3.0 it's /dev/sndproc but this could be a temporary solution.
  */
 
-#define SND_NDEVS      64      /* Number of supported devices */
+#define SND_NDEVS      256     /* Number of supported devices */
 #define SND_DEV_CTL    0       /* Control port /dev/mixer */
 #define SND_DEV_SEQ    1       /* Sequencer output /dev/sequencer (FM
                                   synthesizer and MIDI output) */
@@ -199,7 +199,7 @@ If your card has nonstandard I/O address or IRQ number, change defines
 #define ON             1
 #define OFF            0
 
-#define MAX_AUDIO_DEV  4
+#define MAX_AUDIO_DEV  5
 #define MAX_MIXER_DEV  2
 #define MAX_SYNTH_DEV  3
 #define MAX_MIDI_DEV   6
index 0856ce2a8a07e960de20bd9dc623434e34c617ca..0b35fefd0fbb3cf4f5d4cb85790cf4245c424148 100644 (file)
 #define WIN_DIAGNOSE           0x90
 #define WIN_SPECIFY            0x91
 
+#define WIN_MULTREAD           0xC4    /* read multiple sectors        */
+#define WIN_MULTWRITE          0xC5    /* write multiple sectors       */
+#define WIN_SETMULT            0xC6    /* enable read multiple         */
+#define WIN_IDENTIFY           0xEC    /* ask drive to identify itself */
+#define WIN_SETFEATURES                0xEF    /* set special drive features   */
+
 /* Bits for HD_ERROR */
 #define MARK_ERR       0x01    /* Bad address mark */
 #define TRK0_ERR       0x02    /* couldn't find track 0 */
@@ -61,4 +67,9 @@ struct hd_geometry {
       unsigned short cylinders;
       unsigned long start;
 };
+#define HDIO_GETUNMASKINTR     0x302
+#define HDIO_SETUNMASKINTR     0x303
+#define HDIO_GETMULTCOUNT      0x304
+#define HDIO_SETMULTCOUNT      0x305
+#define HDIO_SETFEATURE        0x306
 #endif
index b249c4a37a2880a8a747e5ae773ef9eeeb6f8740..719481e72fc844389d02a85bf44c059e542ed33f 100644 (file)
@@ -145,10 +145,10 @@ extern int unmap_page_range(unsigned long from, unsigned long size);
 extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask);
 extern int zeromap_page_range(unsigned long from, unsigned long size, int mask);
 
-extern void do_wp_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk);
-extern void do_no_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk);
+extern void do_wp_page(struct vm_area_struct * vma, unsigned long address,
+       unsigned long error_code);
+extern void do_no_page(struct vm_area_struct * vma, unsigned long address,
+       unsigned long error_code);
 
 extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
 extern void mem_init(unsigned long low_start_mem,
index e03a88d933668893b2a9177f19ef911fb4195d10..90ffe7b3b71b51e7f6b137702cda8407af089c32 100644 (file)
@@ -6,6 +6,8 @@
 
 #define __WCLONE       0x80000000
 
+#ifdef __KERNEL__
+
 struct wait_queue {
        struct task_struct * task;
        struct wait_queue * next;
@@ -31,4 +33,6 @@ typedef struct select_table_struct {
 
 #define __MAX_SELECT_TABLE_ENTRIES (4096 / sizeof (struct select_table_entry))
 
+#endif /* __KERNEL__ */
+
 #endif
index c622764412b3f382b71a82ad21f012b1ff447779..7df8f1312ef5919acfc98b0cc83844f143b589fb 100644 (file)
@@ -81,24 +81,20 @@ static inline int put_stack_long(struct task_struct *task, int offset,
  * tables. NOTE! You should check that the long isn't on a page boundary,
  * and that it is in the task area before calling this: this routine does
  * no checking.
- *
- * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always
- * zero. This routine shouldn't have to change when we make a better mm.
  */
-static unsigned long get_long(struct task_struct * tsk,
-       unsigned long addr)
+static unsigned long get_long(struct vm_area_struct * vma, unsigned long addr)
 {
        unsigned long page;
 
 repeat:
-       page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr);
+       page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
        if (page & PAGE_PRESENT) {
                page &= PAGE_MASK;
                page += PAGE_PTR(addr);
                page = *((unsigned long *) page);
        }
        if (!(page & PAGE_PRESENT)) {
-               do_no_page(0,addr,tsk);
+               do_no_page(vma, addr, 0);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -118,14 +114,14 @@ repeat:
  * Now keeps R/W state of page so that a text page stays readonly
  * even if a debugger scribbles breakpoints into it.  -M.U-
  */
-static void put_long(struct task_struct * tsk, unsigned long addr,
+static void put_long(struct vm_area_struct * vma, unsigned long addr,
        unsigned long data)
 {
        unsigned long page, pte = 0;
        int readonly = 0;
 
 repeat:
-       page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr);
+       page = *PAGE_DIR_OFFSET(vma->vm_task->tss.cr3, addr);
        if (page & PAGE_PRESENT) {
                page &= PAGE_MASK;
                page += PAGE_PTR(addr);
@@ -133,13 +129,13 @@ repeat:
                page = *((unsigned long *) page);
        }
        if (!(page & PAGE_PRESENT)) {
-               do_no_page(0 /* PAGE_RW */ ,addr,tsk);
+               do_no_page(vma, addr, 0 /* PAGE_RW */);
                goto repeat;
        }
        if (!(page & PAGE_RW)) {
-               if(!(page & PAGE_COW))
+               if (!(page & PAGE_COW))
                        readonly = 1;
-               do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk);
+               do_wp_page(vma, addr, PAGE_RW | PAGE_PRESENT);
                goto repeat;
        }
 /* this is a hack for non-kernel-mapped video buffers and similar */
@@ -150,12 +146,34 @@ repeat:
        page &= PAGE_MASK;
        page += addr & ~PAGE_MASK;
        *(unsigned long *) page = data;
-       if(readonly) {
+       if (readonly) {
                *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW);
                invalidate();
        } 
 }
 
+static struct vm_area_struct * find_vma(struct task_struct * tsk, unsigned long addr)
+{
+       struct vm_area_struct * vma;
+
+       addr &= PAGE_MASK;
+       for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
+               if (!vma)
+                       return NULL;
+               if (vma->vm_end > addr)
+                       break;
+       }
+       if (vma->vm_start <= addr)
+               return vma;
+       if (!(vma->vm_flags & VM_GROWSDOWN))
+               return NULL;
+       if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur)
+               return NULL;
+       vma->vm_offset -= vma->vm_start - addr;
+       vma->vm_start = addr;
+       return vma;
+}
+
 /*
  * This routine checks the page boundaries, and that the offset is
  * within the task area. It then calls get_long() to read a long.
@@ -163,13 +181,21 @@ repeat:
 static int read_long(struct task_struct * tsk, unsigned long addr,
        unsigned long * result)
 {
-       unsigned long low,high;
+       struct vm_area_struct * vma = find_vma(tsk, addr);
 
-       if (addr > TASK_SIZE-sizeof(long))
+       if (!vma)
                return -EIO;
        if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-               low = get_long(tsk,addr & ~(sizeof(long)-1));
-               high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
+               unsigned long low,high;
+               struct vm_area_struct * vma_high = vma;
+
+               if (addr + sizeof(long) >= vma->vm_end) {
+                       vma_high = vma->vm_next;
+                       if (!vma_high || vma_high->vm_start != vma->vm_end)
+                               return -EIO;
+               }
+               low = get_long(vma, addr & ~(sizeof(long)-1));
+               high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
                switch (addr & (sizeof(long)-1)) {
                        case 1:
                                low >>= 8;
@@ -186,7 +212,7 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
                }
                *result = low;
        } else
-               *result = get_long(tsk,addr);
+               *result = get_long(vma, addr);
        return 0;
 }
 
@@ -197,13 +223,21 @@ static int read_long(struct task_struct * tsk, unsigned long addr,
 static int write_long(struct task_struct * tsk, unsigned long addr,
        unsigned long data)
 {
-       unsigned long low,high;
+       struct vm_area_struct * vma = find_vma(tsk, addr);
 
-       if (addr > TASK_SIZE-sizeof(long))
+       if (!vma)
                return -EIO;
        if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) {
-               low = get_long(tsk,addr & ~(sizeof(long)-1));
-               high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1));
+               unsigned long low,high;
+               struct vm_area_struct * vma_high = vma;
+
+               if (addr + sizeof(long) >= vma->vm_end) {
+                       vma_high = vma->vm_next;
+                       if (!vma_high || vma_high->vm_start != vma->vm_end)
+                               return -EIO;
+               }
+               low = get_long(vma, addr & ~(sizeof(long)-1));
+               high = get_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1));
                switch (addr & (sizeof(long)-1)) {
                        case 0: /* shouldn't happen, but safety first */
                                low = data;
@@ -227,10 +261,10 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
                                high |= data >> 8;
                                break;
                }
-               put_long(tsk,addr & ~(sizeof(long)-1),low);
-               put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high);
+               put_long(vma, addr & ~(sizeof(long)-1),low);
+               put_long(vma_high, (addr+sizeof(long)) & ~(sizeof(long)-1),high);
        } else
-               put_long(tsk,addr,data);
+               put_long(vma, addr, data);
        return 0;
 }
 
index 45f489cb029ef03ab52fe3b578d8dc711a96b49a..5e43d601d6769f30dbdc0f89d32ef7037133b9e7 100644 (file)
@@ -148,7 +148,6 @@ asmlinkage void math_emulate(long arg)
 
 unsigned long itimer_ticks = 0;
 unsigned long itimer_next = ~0;
-static unsigned long lost_ticks = 0;
 
 /*
  *  'schedule()' is the scheduler function. It's a very simple and nice
@@ -361,54 +360,76 @@ void sleep_on(struct wait_queue **p)
        __sleep_on(p,TASK_UNINTERRUPTIBLE);
 }
 
-static struct timer_list * next_timer = NULL;
+/*
+ * The head for the timer-list has a "expires" field of MAX_UINT,
+ * and the sorting routine counts on this..
+ */
+static struct timer_list timer_head = { &timer_head, &timer_head, ~0, 0, NULL };
+#define SLOW_BUT_DEBUGGING_TIMERS 1
 
 void add_timer(struct timer_list * timer)
 {
        unsigned long flags;
-       struct timer_list *p;
+       struct timer_list *p;
 
-       if (!timer)
+#if SLOW_BUT_DEBUGGING_TIMERS
+       if (timer->next || timer->prev) {
+               printk("add_timer() called with non-zero list from %08lx\n",
+                       ((unsigned long *) &timer)[-1]);
                return;
-       timer->next = NULL;
-       p = &next_timer;
+       }
+#endif
+       p = &timer_head;
+       timer->expires += jiffies;
        save_flags(flags);
        cli();
-       while (*p) {
-               if ((*p)->expires > timer->expires) {
-                       (*p)->expires -= timer->expires;
-                       timer->next = *p;
-                       break;
-               }
-               timer->expires -= (*p)->expires;
-               p = &(*p)->next;
-       }
-       *p = timer;
+       do {
+               p = p->next;
+       } while (timer->expires > p->expires);
+       timer->next = p;
+       timer->prev = p->prev;
+       p->prev = timer;
+       timer->prev->next = timer;
        restore_flags(flags);
 }
 
 int del_timer(struct timer_list * timer)
 {
        unsigned long flags;
-       unsigned long expires = 0;
-       struct timer_list **p;
+#if SLOW_BUT_DEBUGGING_TIMERS
+       struct timer_list * p;
 
-       p = &next_timer;
+       p = &timer_head;
        save_flags(flags);
        cli();
-       while (*p) {
-               if (*p == timer) {
-                       if ((*p = timer->next) != NULL)
-                               (*p)->expires += timer->expires;
-                       timer->expires += expires;
+       while ((p = p->next) != &timer_head) {
+               if (p == timer) {
+                       timer->next->prev = timer->prev;
+                       timer->prev->next = timer->next;
+                       timer->next = timer->prev = NULL;
                        restore_flags(flags);
+                       timer->expires -= jiffies;
                        return 1;
                }
-               expires += (*p)->expires;
-               p = &(*p)->next;
        }
+       if (p->next || p->prev)
+               printk("del_timer() called with timer not initialized\n");
        restore_flags(flags);
        return 0;
+#else  
+       save_flags(flags);
+       cli();
+       if (timer->next) {
+               timer->next->prev = timer->prev;
+               timer->prev->next = timer->next;
+               timer->next = timer->prev = NULL;
+               restore_flags(flags);
+               timer->expires -= jiffies;
+               return 1;
+       }
+       restore_flags(flags);
+       return 0;
+#endif
 }
 
 unsigned long timer_active = 0;
@@ -528,12 +549,15 @@ static void timer_bh(void * unused)
 {
        unsigned long mask;
        struct timer_struct *tp;
+       struct timer_list * timer;
 
        cli();
-       while (next_timer && next_timer->expires == 0) {
-               void (*fn)(unsigned long) = next_timer->function;
-               unsigned long data = next_timer->data;
-               next_timer = next_timer->next;
+       while ((timer = timer_head.next) != &timer_head && timer->expires < jiffies) {
+               void (*fn)(unsigned long) = timer->function;
+               unsigned long data = timer->data;
+               timer->next->prev = timer->prev;
+               timer->prev->next = timer->next;
+               timer->next = timer->prev = NULL;
                sti();
                fn(data);
                cli();
@@ -667,16 +691,8 @@ static void do_timer(struct pt_regs * regs)
        itimer_ticks++;
        if (itimer_ticks > itimer_next)
                need_resched = 1;
-       if (next_timer) {
-               if (next_timer->expires) {
-                       next_timer->expires--;
-                       if (!next_timer->expires)
-                               mark_bh(TIMER_BH);
-               } else {
-                       lost_ticks++;
-                       mark_bh(TIMER_BH);
-               }
-       }
+       if (timer_head.next->expires < jiffies)
+               mark_bh(TIMER_BH);
        if (tq_timer != &tq_last)
                mark_bh(TQUEUE_BH);
        sti();
index 4b423f28776a8edc8bbd421c533bb89046925c6d..bc3a2b4be3f1ad1f5488ac3d8193b2600aa47a5f 100644 (file)
@@ -554,20 +554,17 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
  * to a shared page. It is done by copying the page to a new address
  * and decrementing the shared-page counter for the old page.
  *
- * Note that we do many checks twice (look at do_wp_page()), as
- * we have to be careful about race-conditions.
- *
  * Goto-purists beware: the only reason for goto's here is that it results
  * in better assembly code.. The "default" path will see no jumps at all.
  */
-static void __do_wp_page(unsigned long error_code, unsigned long address,
-       struct task_struct * tsk)
+void do_wp_page(struct vm_area_struct * vma, unsigned long address,
+       unsigned long error_code)
 {
        unsigned long *pde, pte, old_page, prot;
        unsigned long new_page;
 
        new_page = __get_free_page(GFP_KERNEL);
-       pde = PAGE_DIR_OFFSET(tsk->tss.cr3,address);
+       pde = PAGE_DIR_OFFSET(vma->vm_task->tss.cr3,address);
        pte = *pde;
        if (!(pte & PAGE_PRESENT))
                goto end_wp_page;
@@ -582,13 +579,13 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
                goto bad_wp_page;
        if (old_page & PAGE_RW)
                goto end_wp_page;
-       tsk->mm->min_flt++;
+       vma->vm_task->mm->min_flt++;
        prot = (old_page & ~PAGE_MASK) | PAGE_RW;
        old_page &= PAGE_MASK;
        if (mem_map[MAP_NR(old_page)] != 1) {
                if (new_page) {
                        if (mem_map[MAP_NR(old_page)] & MAP_PAGE_RESERVED)
-                               ++tsk->mm->rss;
+                               ++vma->vm_task->mm->rss;
                        copy_page(old_page,new_page);
                        *(unsigned long *) pte = new_page | prot;
                        free_page(old_page);
@@ -596,7 +593,7 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
                        return;
                }
                free_page(old_page);
-               oom(tsk);
+               oom(vma->vm_task);
                *(unsigned long *) pte = BAD_PAGE | prot;
                invalidate();
                return;
@@ -609,12 +606,12 @@ static void __do_wp_page(unsigned long error_code, unsigned long address,
 bad_wp_page:
        printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page);
        *(unsigned long *) pte = BAD_PAGE | PAGE_SHARED;
-       send_sig(SIGKILL, tsk, 1);
+       send_sig(SIGKILL, vma->vm_task, 1);
        goto end_wp_page;
 bad_wp_pagetable:
        printk("do_wp_page: bogus page-table at address %08lx (%08lx)\n",address,pte);
        *pde = BAD_PAGETABLE | PAGE_TABLE;
-       send_sig(SIGKILL, tsk, 1);
+       send_sig(SIGKILL, vma->vm_task, 1);
 end_wp_page:
        if (new_page)
                free_page(new_page);
@@ -622,63 +619,12 @@ end_wp_page:
 }
 
 /*
- * check that a page table change is actually needed, and call
- * the low-level function only in that case..
+ * Ugly, ugly, but the goto's result in better assembly..
  */
-void do_wp_page(unsigned long error_code, unsigned long address,
-       struct task_struct * tsk)
-{
-       unsigned long page;
-       unsigned long * pg_table;
-
-       pg_table = PAGE_DIR_OFFSET(tsk->tss.cr3,address);
-       page = *pg_table;
-       if (!page)
-               return;
-       if ((page & PAGE_PRESENT) && page < high_memory) {
-               pg_table = (unsigned long *) ((page & PAGE_MASK) + PAGE_PTR(address));
-               page = *pg_table;
-               if (!(page & PAGE_PRESENT))
-                       return;
-               if (page & PAGE_RW)
-                       return;
-               if (!(page & PAGE_COW)) {
-                       if ((error_code & PAGE_USER) && tsk == current) {
-                               current->tss.cr2 = address;
-                               current->tss.error_code = error_code;
-                               current->tss.trap_no = 14;
-                               send_sig(SIGSEGV, tsk, 1);
-                               return;
-                       }
-               }
-               if (mem_map[MAP_NR(page)] == 1) {
-                       *pg_table |= PAGE_RW | PAGE_DIRTY;
-                       invalidate();
-                       return;
-               }
-               __do_wp_page(error_code, address, tsk);
-               return;
-       }
-       printk("bad page directory entry %08lx\n",page);
-       *pg_table = 0;
-}
-
-static int __verify_write(unsigned long start, unsigned long size)
-{
-       size--;
-       size += start & ~PAGE_MASK;
-       size >>= PAGE_SHIFT;
-       start &= PAGE_MASK;
-       do {
-               do_wp_page(1,start,current);
-               start += PAGE_SIZE;
-       } while (size--);
-       return 0;
-}
-
 int verify_area(int type, const void * addr, unsigned long size)
 {
        struct vm_area_struct * vma;
+       unsigned long start = (unsigned long) addr;
 
        /* If the current user space is mapped to kernel space (for the
         * case where we use a fake user buffer with get_fs/set_fs()) we
@@ -690,27 +636,52 @@ int verify_area(int type, const void * addr, unsigned long size)
        for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
                if (!vma)
                        goto bad_area;
-               if (vma->vm_end > (unsigned long) addr)
+               if (vma->vm_end > start)
                        break;
        }
-       if (vma->vm_start <= (unsigned long) addr)
+       if (vma->vm_start <= start)
                goto good_area;
        if (!(vma->vm_flags & VM_GROWSDOWN))
                goto bad_area;
-       if (vma->vm_end - (unsigned long) addr > current->rlim[RLIMIT_STACK].rlim_cur)
+       if (vma->vm_end - start > current->rlim[RLIMIT_STACK].rlim_cur)
                goto bad_area;
+
 good_area:
-       while (vma->vm_end - (unsigned long) addr < size) {
-               struct vm_area_struct * next = vma->vm_next;
-               if (!next)
+       if (!wp_works_ok && type == VERIFY_WRITE)
+               goto check_wp_fault_by_hand;
+       for (;;) {
+               struct vm_area_struct * next;
+               if (type != VERIFY_READ && !(vma->vm_page_prot & (PAGE_COW | PAGE_RW)))
                        goto bad_area;
-               if (vma->vm_end != next->vm_start)
+               if (vma->vm_end - start >= size)
+                       return 0;
+               next = vma->vm_next;
+               if (!next || vma->vm_end != next->vm_start)
                        goto bad_area;
                vma = next;
        }
-       if (wp_works_ok || type == VERIFY_READ || !size)
-               return 0;
-       return __verify_write((unsigned long) addr,size);
+
+check_wp_fault_by_hand:
+       size--;
+       size += start & ~PAGE_MASK;
+       size >>= PAGE_SHIFT;
+       start &= PAGE_MASK;
+
+       for (;;) {
+               if (!(vma->vm_page_prot & (PAGE_COW | PAGE_RW)))
+                       goto bad_area;
+               do_wp_page(vma, start, PAGE_PRESENT);
+               if (!size)
+                       return 0;
+               size--;
+               start += PAGE_SIZE;
+               if (start < vma->vm_end)
+                       continue;
+               vma = vma->vm_next;
+               if (!vma || vma->vm_start != start)
+                       break;
+       }
+
 bad_area:
        return -EFAULT;
 }
@@ -885,12 +856,33 @@ static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned
        return 0;
 }
 
-static void handle_no_page(struct vm_area_struct * vma,
-       unsigned long address, unsigned long error_code)
+void do_no_page(struct vm_area_struct * vma, unsigned long address,
+       unsigned long error_code)
 {
-       unsigned long page;
-       int prot;
+       unsigned long page, entry, prot;
+
+       page = get_empty_pgtable(vma->vm_task,address);
+       if (!page)
+               return;
+       page &= PAGE_MASK;
+       page += PAGE_PTR(address);
+       entry = *(unsigned long *) page;
+       if (entry & PAGE_PRESENT)
+               return;
+       if (entry) {
+               ++vma->vm_task->mm->rss;
+               ++vma->vm_task->mm->maj_flt;
+               swap_in((unsigned long *) page);
+               return;
+       }
+       address &= PAGE_MASK;
 
+       if (!vma->vm_ops || !vma->vm_ops->nopage) {
+               ++vma->vm_task->mm->rss;
+               ++vma->vm_task->mm->min_flt;
+               get_empty_page(vma->vm_task,address);
+               return;
+       }
        page = get_free_page(GFP_KERNEL);
        if (share_page(vma, address, error_code, page)) {
                ++vma->vm_task->mm->min_flt;
@@ -904,8 +896,10 @@ static void handle_no_page(struct vm_area_struct * vma,
        ++vma->vm_task->mm->maj_flt;
        ++vma->vm_task->mm->rss;
        page = vma->vm_ops->nopage(vma, address, page, error_code);
-       if (share_page(vma, address, error_code, 0))
+       if (share_page(vma, address, error_code, 0)) {
+               free_page(page);
                return;
+       }
        prot = vma->vm_page_prot;
        if ((prot & PAGE_COW) && mem_map[MAP_NR(page)] > 1)
                prot &= ~PAGE_RW;
@@ -915,28 +909,20 @@ static void handle_no_page(struct vm_area_struct * vma,
        oom(current);
 }
 
-void do_no_page(unsigned long error_code, unsigned long address,
-       struct task_struct *tsk)
+/*
+ * This routine handles page faults.  It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
-       unsigned long page, tmp;
        struct vm_area_struct * vma;
+       unsigned long address;
+       unsigned long page;
 
-       page = get_empty_pgtable(tsk,address);
-       if (!page)
-               return;
-       page &= PAGE_MASK;
-       page += PAGE_PTR(address);
-       tmp = *(unsigned long *) page;
-       if (tmp & PAGE_PRESENT)
-               return;
-       if (tmp) {
-               ++tsk->mm->rss;
-               ++tsk->mm->maj_flt;
-               swap_in((unsigned long *) page);
-               return;
-       }
-       address &= PAGE_MASK;
-       for (vma = tsk->mm->mmap ; ; vma = vma->vm_next) {
+       /* get the address */
+       __asm__("movl %%cr2,%0":"=r" (address));
+       for (vma = current->mm->mmap ; ; vma = vma->vm_next) {
                if (!vma)
                        goto bad_area;
                if (vma->vm_end > address)
@@ -946,81 +932,63 @@ void do_no_page(unsigned long error_code, unsigned long address,
                goto good_area;
        if (!(vma->vm_flags & VM_GROWSDOWN))
                goto bad_area;
-       if (vma->vm_end - address > tsk->rlim[RLIMIT_STACK].rlim_cur)
+       if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
                goto bad_area;
-       vma->vm_offset -= vma->vm_start - address;
-       vma->vm_start = address;
-
+       vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
+       vma->vm_start = (address & PAGE_MASK);
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
 good_area:
-       if (!vma->vm_ops || !vma->vm_ops->nopage) {
-               ++tsk->mm->rss;
-               ++tsk->mm->min_flt;
-               get_empty_page(tsk,address);
+       if (regs->eflags & VM_MASK) {
+               unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
+               if (bit < 32)
+                       current->screen_bitmap |= 1 << bit;
+       }
+       if (error_code & PAGE_PRESENT) {
+               if ((vma->vm_page_prot & (PAGE_RW | PAGE_COW | PAGE_PRESENT)) == PAGE_PRESENT)
+                       goto bad_area;
+#ifdef CONFIG_TEST_VERIFY_AREA
+               if (regs->cs == KERNEL_CS)
+                       printk("WP fault at %08x\n", regs->eip);
+#endif
+               do_wp_page(vma, address, error_code);
                return;
        }
-       handle_no_page(vma, address, error_code);
+       if (!(vma->vm_page_prot & PAGE_PRESENT))
+               goto bad_area;
+       do_no_page(vma, address, error_code);
        return;
 
-bad_area:
-       if (tsk != current)
-               goto kernel_needs_bad_page;
-       tsk->tss.cr2 = address;
-       tsk->tss.error_code = error_code;
-       tsk->tss.trap_no = 14;
-       send_sig(SIGSEGV,tsk,1);
-       if (error_code & 4)     /* user level access? */
-               return;
-
-kernel_needs_bad_page:
-       ++tsk->mm->rss;
-       ++tsk->mm->min_flt;
-       get_empty_page(tsk,address);
-}
-
 /*
- * This routine handles page faults.  It determines the address,
- * and the problem, and then passes it off to one of the appropriate
- * routines.
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
-{
-       unsigned long address;
-       unsigned long page;
-       unsigned int bit;
-
-       /* get the address */
-       __asm__("movl %%cr2,%0":"=r" (address));
-       if (address < TASK_SIZE) {
-               if (regs->eflags & VM_MASK) {
-                       bit = (address - 0xA0000) >> PAGE_SHIFT;
-                       if (bit < 32)
-                               current->screen_bitmap |= 1 << bit;
-               }
-               if (error_code & PAGE_PRESENT) {
-#ifdef CONFIG_TEST_VERIFY_AREA
-                       if (regs->cs == KERNEL_CS)
-                               printk("WP fault at %08x\n", regs->eip);
-#endif
-                       do_wp_page(error_code, address, current);
-               } else {
-                       do_no_page(error_code, address, current);
-               }
+bad_area:
+       if (error_code & PAGE_USER) {
+               current->tss.cr2 = address;
+               current->tss.error_code = error_code;
+               current->tss.trap_no = 14;
+               send_sig(SIGSEGV, current, 1);
                return;
        }
-       address -= TASK_SIZE;
-       if (wp_works_ok < 0 && address == 0 && (error_code & PAGE_PRESENT)) {
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+       if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & PAGE_PRESENT)) {
                wp_works_ok = 1;
                pg0[0] = PAGE_SHARED;
                printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
                return;
        }
-       if (address < PAGE_SIZE) {
+       if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
                printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
                pg0[0] = PAGE_SHARED;
        } else
                printk(KERN_ALERT "Unable to handle kernel paging request");
-       printk(" at kernel address %08lx\n",address);
-       address += TASK_SIZE;
+       printk(" at virtual address %08lx\n",address);
        __asm__("movl %%cr3,%0" : "=r" (page));
        printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
                current->tss.cr3, page);
index 1760fc15e36914890d62322e5a2b0692531c9182..6a4ba8ff09b43b2981ff9888f8e12524c09303b5 100644 (file)
@@ -615,6 +615,7 @@ static int inet_create(struct socket *sock, int protocol)
        sk->timeout = 0;
        sk->broadcast = 0;
        sk->localroute = 0;
+       sk->timer.next = sk->timer.prev = NULL;
        sk->timer.data = (unsigned long)sk;
        sk->timer.function = &net_timer;
        skb_queue_head_init(&sk->back_log);
index b82fc7008341d596b803808ed151bfc9ecf3cc03..5c61c5636b9e3c7b5f67b71fe43ac1e85fd61082 100644 (file)
@@ -752,7 +752,7 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                skb_queue_head_init(&entry->skb);
                entry->next = arp_tables[hash];
                arp_tables[hash] = entry;
-
+               entry->timer.next = entry->timer.prev = NULL;
                sti();
        }
 
@@ -841,6 +841,7 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
                entry->next = arp_tables[hash];
                entry->dev = dev;
                arp_tables[hash] = entry;
+               entry->timer.next = entry->timer.prev = NULL;
                entry->timer.function = arp_expire_request;
                entry->timer.data = (unsigned long)entry;
                entry->timer.expires = ARP_RES_TIME;
@@ -1048,6 +1049,7 @@ static int arp_req_set(struct arpreq *req)
                entry->hlen = hlen;
                entry->htype = htype;
                entry->next = arp_tables[hash];
+               entry->timer.next = entry->timer.prev = NULL;
                arp_tables[hash] = entry;
                skb_queue_head_init(&entry->skb);
        }
index 5227f132976cc91fd7ee020a38c7e9df2e94f7e1..bc11f64b2a3ae351ec786ff519e3e4f5f88d1697 100644 (file)
@@ -336,6 +336,8 @@ int dev_close(struct device *dev)
 void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
 {
        unsigned long flags;
+       int nitcount;
+       struct packet_type *ptype;
        int where = 0;          /* used to say if the packet should go  */
                                /* at the front or the back of the      */
                                /* queue - front is a retranmsit try    */
@@ -419,6 +421,17 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
        }
        restore_flags(flags);
 
+       /* copy outgoing packets to any sniffer packet handlers */
+       for (nitcount = dev_nit, ptype = ptype_base; nitcount > 0 && ptype != NULL; ptype = ptype->next) {
+               if (ptype->type == htons(ETH_P_ALL)) {
+                       struct sk_buff *skb2;
+                       if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
+                               break;
+                       ptype->func(skb2, skb->dev, ptype);
+                       nitcount--;
+               }
+       }
+
        if (dev->hard_start_xmit(skb, dev) == 0) {
                /*
                 *      Packet is now solely the responsibility of the driver
index 79b86894f5ce9cd9cf61d0a150dc1f2dfa122db5..d8742cf2eebb4bd0bb3365c4b44c7ad0a60da7cb 100644 (file)
@@ -681,8 +681,7 @@ struct sk_buff * tcp_dequeue_partial(struct sock * sk)
        save_flags(flags);
        cli();
        skb = sk->partial;
-       if (skb) 
-       {
+       if (skb) {
                sk->partial = NULL;
                del_timer(&sk->partial_timer);
        }
@@ -711,6 +710,7 @@ void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk)
        if (tmp)
                del_timer(&sk->partial_timer);
        sk->partial = skb;
+       sk->partial_timer.next = sk->partial_timer.prev = NULL;
        sk->partial_timer.expires = HZ;
        sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial;
        sk->partial_timer.data = (unsigned long) sk;
@@ -1987,6 +1987,7 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb,
        newsk->urg_data = 0;
        newsk->retransmits = 0;
        newsk->destroy = 0;
+       newsk->timer.next = newsk->timer.prev = NULL;
        newsk->timer.data = (unsigned long)newsk;
        newsk->timer.function = &net_timer;
        newsk->dummy_th.source = skb->h.th->dest;
@@ -2217,6 +2218,15 @@ static void tcp_close(struct sock *sk, int timeout)
                         * XXX if retransmit count reaches limit, is tcp_close()
                         * called with timeout == 1 ? if not, we need to fix that.
                         */
+                       if (!timeout) {
+                               int timer_active;
+
+                               timer_active = del_timer(&sk->timer);
+                               if (timer_active)
+                                       add_timer(&sk->timer);
+                               else
+                                       reset_timer(sk, TIME_CLOSE, 4 * sk->rto);
+                       }
 #ifdef NOTDEF
                        /* 
                         *      Start a timer.