diff -u --recursive --new-file v1.1.31/linux/Makefile linux/Makefile --- v1.1.31/linux/Makefile Tue Jul 19 10:18:53 1994 +++ linux/Makefile Tue Jul 19 09:28:54 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 31 +SUBLEVEL = 32 all: Version zImage diff -u --recursive --new-file v1.1.31/linux/config.in linux/config.in --- v1.1.31/linux/config.in Sat Jul 9 16:30:45 1994 +++ linux/config.in Wed Jul 20 21:48:46 1994 @@ -81,7 +81,6 @@ 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 @@ 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 -u --recursive --new-file v1.1.31/linux/drivers/block/README.hd linux/drivers/block/README.hd --- v1.1.31/linux/drivers/block/README.hd Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.hd Wed Jul 20 16:09:20 1994 @@ -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 diff -u --recursive --new-file v1.1.31/linux/drivers/block/hd.c linux/drivers/block/hd.c --- v1.1.31/linux/drivers/block/hd.c Sat Jul 16 19:51:20 1994 +++ linux/drivers/block/hd.c Wed Jul 20 16:09:20 1994 @@ -14,9 +14,15 @@ * * 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 #include #include #include @@ -211,6 +217,128 @@ 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<>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 @@ 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 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 @@ 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 @@ } bad_rw_intr(); cli(); - do_hd_request(); + hd_request(); return; ok_to_write: CURRENT->sector++; @@ -401,7 +607,7 @@ #if (HD_DELAY > 0) last_req = read_timer(); #endif - do_hd_request(); + hd_request(); } return; } @@ -410,7 +616,7 @@ { if (win_result()) bad_rw_intr(); - do_hd_request(); + hd_request(); } /* @@ -433,7 +639,7 @@ end_request(0); } - do_hd_request(); + hd_request(); } /* @@ -443,7 +649,7 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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; diff -u --recursive --new-file v1.1.31/linux/drivers/char/console.c linux/drivers/char/console.c --- v1.1.31/linux/drivers/char/console.c Mon Jun 27 16:46:58 1994 +++ linux/drivers/char/console.c Wed Jul 20 15:54:08 1994 @@ -83,6 +83,7 @@ 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 @@ 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 @@ *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 @@ switch (sel_mode) { case 0: /* character-by-character selection */ - default: new_sel_start = ps; new_sel_end = pe; break; @@ -1859,6 +1903,17 @@ 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 @@ 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); diff -u --recursive --new-file v1.1.31/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c --- v1.1.31/linux/drivers/char/keyboard.c Fri Jun 17 15:20:04 1994 +++ linux/drivers/char/keyboard.c Wed Jul 20 15:54:08 1994 @@ -86,7 +86,12 @@ 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 */ diff -u --recursive --new-file v1.1.31/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v1.1.31/linux/drivers/char/mem.c Tue Jun 21 14:16:20 1994 +++ linux/drivers/char/mem.c Wed Jul 20 22:11:10 1994 @@ -420,7 +420,7 @@ #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 diff -u --recursive --new-file v1.1.31/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v1.1.31/linux/drivers/char/tty_io.c Thu Jul 14 00:48:21 1994 +++ linux/drivers/char/tty_io.c Wed Jul 20 15:54:08 1994 @@ -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); @@ -1384,6 +1386,11 @@ return paste_selection(tty); 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: diff -u --recursive --new-file v1.1.31/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.1.31/linux/drivers/net/Space.c Fri Jul 8 13:26:34 1994 +++ linux/drivers/net/Space.c Wed Jul 20 17:09:03 1994 @@ -54,7 +54,9 @@ 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 @@ #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. */ diff -u --recursive --new-file v1.1.31/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.1.31/linux/drivers/net/ppp.c Wed Jun 22 14:57:09 1994 +++ linux/drivers/net/ppp.c Wed Jul 20 15:26:04 1994 @@ -267,7 +267,6 @@ 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 @@ #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 @@ 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 @@ return error; } +#endif /************************************************************* * TTY OUTPUT @@ -650,7 +653,11 @@ /* 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 @@ } /* 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; } Only in v1.1.31/linux/drivers/sound: .blurb.orig diff -u --recursive --new-file v1.1.31/linux/drivers/sound/Makefile linux/drivers/sound/Makefile --- v1.1.31/linux/drivers/sound/Makefile Tue Jul 19 10:18:55 1994 +++ linux/drivers/sound/Makefile Wed Jul 20 15:00:35 1994 @@ -5,7 +5,7 @@ # # -VERSION = 2.90 +VERSION = 2.90-2 TARGET_OS = linux .c.s: diff -u --recursive --new-file v1.1.31/linux/drivers/sound/Readme linux/drivers/sound/Readme --- v1.1.31/linux/drivers/sound/Readme Tue Jul 19 10:18:55 1994 +++ linux/drivers/sound/Readme Wed Jul 20 15:00:28 1994 @@ -12,9 +12,9 @@ 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 @@ 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, diff -u --recursive --new-file v1.1.31/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v1.1.31/linux/drivers/sound/ad1848.c Tue Jul 19 10:18:56 1994 +++ linux/drivers/sound/ad1848.c Wed Jul 20 15:00:28 1994 @@ -903,16 +903,14 @@ 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 @@ 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 @@ 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, diff -u --recursive --new-file v1.1.31/linux/drivers/sound/configure.c linux/drivers/sound/configure.c --- v1.1.31/linux/drivers/sound/configure.c Tue Jul 19 10:18:56 1994 +++ linux/drivers/sound/configure.c Wed Jul 20 15:00:29 1994 @@ -322,6 +322,13 @@ } } + 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 @@ "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]; diff -u --recursive --new-file v1.1.31/linux/drivers/sound/dev_table.h linux/drivers/sound/dev_table.h --- v1.1.31/linux/drivers/sound/dev_table.h Tue Jul 19 10:18:57 1994 +++ linux/drivers/sound/dev_table.h Wed Jul 20 15:00:29 1994 @@ -278,6 +278,9 @@ #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) diff -u --recursive --new-file v1.1.31/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c --- v1.1.31/linux/drivers/sound/dmabuf.c Tue Jul 19 10:18:58 1994 +++ linux/drivers/sound/dmabuf.c Wed Jul 20 14:58:28 1994 @@ -320,7 +320,7 @@ if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev); - if (dmap->dma_mode) + if (!dmap->dma_mode) { int err; diff -u --recursive --new-file v1.1.31/linux/drivers/sound/sb_dsp.c linux/drivers/sound/sb_dsp.c --- v1.1.31/linux/drivers/sound/sb_dsp.c Tue Jul 19 10:19:08 1994 +++ linux/drivers/sound/sb_dsp.c Wed Jul 20 15:00:55 1994 @@ -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 @@ -25,6 +25,10 @@ * 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 @@ 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 @@ #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 @@ 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 diff -u --recursive --new-file v1.1.31/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c --- v1.1.31/linux/drivers/sound/sb_mixer.c Tue Jul 19 10:19:09 1994 +++ linux/drivers/sound/sb_mixer.c Wed Jul 20 15:00:55 1994 @@ -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 @@ -26,6 +26,10 @@ * 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 @@ | (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 @@ 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 @@ 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 @@ { 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 @@ 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 diff -u --recursive --new-file v1.1.31/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h --- v1.1.31/linux/drivers/sound/sb_mixer.h Tue Jul 19 10:19:09 1994 +++ linux/drivers/sound/sb_mixer.h Wed Jul 20 15:00:55 1994 @@ -24,13 +24,29 @@ * 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) @@ -62,6 +78,13 @@ #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 */ @@ -107,6 +130,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), diff -u --recursive --new-file v1.1.31/linux/drivers/sound/sound_calls.h linux/drivers/sound/sound_calls.h --- v1.1.31/linux/drivers/sound/sound_calls.h Tue Jul 19 10:19:10 1994 +++ linux/drivers/sound/sound_calls.h Wed Jul 20 15:00:55 1994 @@ -140,7 +140,7 @@ 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); diff -u --recursive --new-file v1.1.31/linux/drivers/sound/sound_config.h linux/drivers/sound/sound_config.h --- v1.1.31/linux/drivers/sound/sound_config.h Tue Jul 19 10:19:11 1994 +++ linux/drivers/sound/sound_config.h Wed Jul 20 15:00:55 1994 @@ -180,7 +180,7 @@ * 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 @@ #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 diff -u --recursive --new-file v1.1.31/linux/include/linux/hdreg.h linux/include/linux/hdreg.h --- v1.1.31/linux/include/linux/hdreg.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/hdreg.h Wed Jul 20 16:09:21 1994 @@ -42,6 +42,12 @@ #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 @@ 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 diff -u --recursive --new-file v1.1.31/linux/include/linux/mm.h linux/include/linux/mm.h --- v1.1.31/linux/include/linux/mm.h Tue Jul 19 10:19:14 1994 +++ linux/include/linux/mm.h Tue Jul 19 20:08:58 1994 @@ -145,10 +145,10 @@ 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, diff -u --recursive --new-file v1.1.31/linux/include/linux/wait.h linux/include/linux/wait.h --- v1.1.31/linux/include/linux/wait.h Mon Jul 18 14:48:31 1994 +++ linux/include/linux/wait.h Tue Jul 19 13:10:15 1994 @@ -6,6 +6,8 @@ #define __WCLONE 0x80000000 +#ifdef __KERNEL__ + struct wait_queue { struct task_struct * task; struct wait_queue * next; @@ -30,5 +32,7 @@ } select_table; #define __MAX_SELECT_TABLE_ENTRIES (4096 / sizeof (struct select_table_entry)) + +#endif /* __KERNEL__ */ #endif diff -u --recursive --new-file v1.1.31/linux/kernel/ptrace.c linux/kernel/ptrace.c --- v1.1.31/linux/kernel/ptrace.c Tue Jul 19 10:19:15 1994 +++ linux/kernel/ptrace.c Tue Jul 19 09:28:35 1994 @@ -81,24 +81,20 @@ * 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ } *result = low; } else - *result = get_long(tsk,addr); + *result = get_long(vma, addr); return 0; } @@ -197,13 +223,21 @@ 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 @@ 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; } diff -u --recursive --new-file v1.1.31/linux/kernel/sched.c linux/kernel/sched.c --- v1.1.31/linux/kernel/sched.c Thu Jun 9 18:56:13 1994 +++ linux/kernel/sched.c Wed Jul 20 21:12:31 1994 @@ -148,7 +148,6 @@ 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 @@ __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 @@ { 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 @@ 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(); diff -u --recursive --new-file v1.1.31/linux/mm/memory.c linux/mm/memory.c --- v1.1.31/linux/mm/memory.c Tue Jul 19 10:19:15 1994 +++ linux/mm/memory.c Tue Jul 19 20:10:12 1994 @@ -554,20 +554,17 @@ * 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 @@ 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 @@ return; } free_page(old_page); - oom(tsk); + oom(vma->vm_task); *(unsigned long *) pte = BAD_PAGE | prot; invalidate(); return; @@ -609,12 +606,12 @@ 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 @@ } /* - * 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 @@ 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 @@ 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 @@ ++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 @@ 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 @@ 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); diff -u --recursive --new-file v1.1.31/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.31/linux/net/inet/af_inet.c Fri Jul 8 13:26:42 1994 +++ linux/net/inet/af_inet.c Wed Jul 20 18:01:59 1994 @@ -615,6 +615,7 @@ 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); diff -u --recursive --new-file v1.1.31/linux/net/inet/arp.c linux/net/inet/arp.c --- v1.1.31/linux/net/inet/arp.c Tue Jun 21 14:16:27 1994 +++ linux/net/inet/arp.c Wed Jul 20 17:56:56 1994 @@ -752,7 +752,7 @@ 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 @@ 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 @@ 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); } diff -u --recursive --new-file v1.1.31/linux/net/inet/dev.c linux/net/inet/dev.c --- v1.1.31/linux/net/inet/dev.c Tue Jun 21 14:16:28 1994 +++ linux/net/inet/dev.c Wed Jul 20 15:26:05 1994 @@ -336,6 +336,8 @@ 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 */ @@ -418,6 +420,17 @@ #endif } 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) { /* diff -u --recursive --new-file v1.1.31/linux/net/inet/tcp.c linux/net/inet/tcp.c --- v1.1.31/linux/net/inet/tcp.c Mon Jul 18 14:48:32 1994 +++ linux/net/inet/tcp.c Wed Jul 20 18:05:15 1994 @@ -681,8 +681,7 @@ save_flags(flags); cli(); skb = sk->partial; - if (skb) - { + if (skb) { sk->partial = NULL; del_timer(&sk->partial_timer); } @@ -711,6 +710,7 @@ 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 @@ 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 @@ * 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.