aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cc.helsinki.fi>1994-02-02 06:45:07 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:30 -0400
commit3cfe2636ea6f3283638c0e8c14f47d7d620f072d (patch)
treed087626ffe85d00b68fd8676fc66184829a80ce3
parent0ef15e52af53204c01d894863c7bd1bf2ee86cd6 (diff)
downloadarchive-3cfe2636ea6f3283638c0e8c14f47d7d620f072d.tar.gz
ALPHA-pl14y
-rw-r--r--Makefile2
-rw-r--r--drivers/block/README.sbpcd214
-rw-r--r--drivers/block/ll_rw_blk.c5
-rw-r--r--drivers/block/sbpcd.c39
-rw-r--r--drivers/char/console.c187
-rw-r--r--drivers/char/defkeymap.c40
-rw-r--r--drivers/char/kbd_kern.h107
-rw-r--r--drivers/char/keyboard.c157
-rw-r--r--drivers/char/mem.c2
-rw-r--r--drivers/char/tty_io.c14
-rw-r--r--drivers/char/tty_ioctl.c42
-rw-r--r--drivers/char/vt.c109
-rw-r--r--fs/fifo.c16
-rw-r--r--fs/inode.c89
-rw-r--r--fs/pipe.c12
-rw-r--r--fs/proc/array.c31
-rw-r--r--fs/proc/root.c1
-rw-r--r--fs/super.c1
-rw-r--r--include/linux/kd.h12
-rw-r--r--include/linux/kernel_stat.h26
-rw-r--r--include/linux/keyboard.h75
-rw-r--r--include/linux/sys.h2
-rw-r--r--include/linux/timex.h2
-rw-r--r--include/linux/unistd.h1
-rw-r--r--kernel/irq.c3
-rw-r--r--kernel/sched.c50
-rw-r--r--kernel/time.c13
-rw-r--r--mm/swap.c5
-rw-r--r--net/inet/packet.c2
-rw-r--r--net/inet/skbuff.c10
-rw-r--r--net/inet/sock.c6
-rw-r--r--net/inet/sock.h8
-rw-r--r--net/inet/tcp.c142
-rw-r--r--net/inet/tcp.h2
-rw-r--r--net/inet/timer.c14
-rw-r--r--net/socket.c6
-rw-r--r--net/unix/sock.c8
37 files changed, 1051 insertions, 404 deletions
diff --git a/Makefile b/Makefile
index 85ac1c8..287c817 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 0.99
PATCHLEVEL = 14
-ALPHA = x
+ALPHA = y
all: Version zImage
diff --git a/drivers/block/README.sbpcd b/drivers/block/README.sbpcd
index e69de29..5b5dd1c 100644
--- a/drivers/block/README.sbpcd
+++ b/drivers/block/README.sbpcd
@@ -0,0 +1,214 @@
+This is release 1.2 of the SoundBlaster Pro (Matsushita, Kotobuki,
+Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux.
+
+The driver is able to drive the whole family of IDE-style
+Matsushita/Kotobuki/Panasonic drives (the "double speed" versions
+like CR-562 and CR-563, too), and it will work with the soundcard
+interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with
+the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...).
+The interface type has to get configured, because the behavior
+is different.
+
+The driver respects different drive firmware releases - my drive
+is a 2.11, but it should work with "old" drives <2.01 ... >3.00
+and with "new" drives (which count the releases around 0.75 or
+1.00).
+
+Up to 4 drives are supported. CR-52x and CR-56x drives can be mixed,
+but the CR-521 ones are hard-wired to drive ID 0. The drives have
+to use different drive IDs, but the same controller (it will be a
+little bit harder to support up to four interface cards - but I plan
+to do it the day somebody wishes to connect a fifth drive).
+Each drive has to get a unique minor number (0...3), corresponding
+to it's drive ID. The drive IDs may be selected freely from 0 to 3 -
+they must not be in consecutive order.
+
+If this driver doesn't work with your equipment, mail me a
+description, please.
+
+The driver supports reading of data from the CD and playing of
+audio tracks. The audio part should run with WorkMan, xcdplayer,
+with the "non-X11" products CDplayer and WorkBone - tell me if
+it is not compatible with other software.
+
+MultiSession is supported, "ManySession" (see below) alternatively.
+Photo CDs should work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm
+is a package to convert photo CD image files.
+
+I did not have a chance to play with XA or mixed mode CDs yet.
+Send one over, if you would like sbpcd to support that.
+
+The transfer rate will reach 150 kB/sec with standard drives and
+the full 300 kB/sec with double-speed drives.
+
+This release is part of the standard kernel and consists of
+- this README file
+- the driver file linux/drivers/block/sbpcd.c
+- the header file linux/include/linux/sbpcd.h.
+
+
+To install:
+-----------
+
+1. Setup your hardware parameters. Though the driver does "auto-probing"
+ now, this step is recommended for every-day use.
+ a. Go into /usr/src/linux/include/linux/sbpcd.h and configure
+ it for your hardware (near the beginning):
+ a1. Set it up for the appropriate type of interface board.
+ Most "compatible" sound boards (for example "Highscreen",
+ "SoundFX" and "Galaxy") need the "SBPRO 0" setup. The
+ "no-sound" board from OmniCd needs the "SBPRO 1" setup.
+ sbpcd.c holds some examples in it's auto-probe list.
+ a2. Tell the address of your CDROM_PORT.
+ b. Additionally for 2.a1 and 2.a2, the setup may be done during
+ boot time (via the "kernel command line" or "LILO option"):
+ sbpcd=0x230,SoundBlaster
+ or
+ sbpcd=0x320,LaserMate
+ (these strings are case sensitive!).
+
+2. Do a "make config" and select "yes" for Matsushita CD-ROM
+ support and for ISO9660 FileSystem support.
+ SCSI and/or SCSI CD-ROM support is not needed.
+
+3. Then do a "make dep", then make the kernel image ("make zlilo"
+ or else).
+
+4. Make the device file(s). The driver uses definitely and exclusive
+ the MAJOR 25, so do
+
+ mknod /dev/sbpcd b 25 0 (if you have only drive #0)
+and/or
+ mknod /dev/sbpcd0 b 25 0
+ mknod /dev/sbpcd1 b 25 1
+ mknod /dev/sbpcd2 b 25 2
+ mknod /dev/sbpcd3 b 25 3
+
+ to make the node(s).
+ Take care that you create a node with the same MINOR as your drive
+ id is. So, if the DOS driver tells you have drive id #3, you have to
+ mknod /dev/<any_name> b 25 3
+
+ If you further make a link like
+ ln -s sbpcd /dev/cdrom
+ you can use the name /dev/cdrom, too.
+
+5. Reboot with the new kernel.
+
+You should now be able to do "mount -t iso9660 /dev/sbpcd /mnt"
+and see the contents of your CD in the /mnt directory, and/or
+hear music with "workman -c /dev/sbpcd &".
+
+
+Things of interest:
+-------------------
+
+The driver is configured to try the SoundBlaster Pro type of
+interface at I/O port 0x0230 first. If this is not appropriate,
+sbpcd.h should get changed (you will find the right place -
+just at the beginning).
+
+No DMA and no IRQ is used, so the IRQ adjusting is not necessary,
+and the IRQ line stays free for the SB Pro sound drivers.
+
+To reduce or increase the amount of kernel messages, edit
+sbpcd.c and change the initialization of the variable
+"sbpcd_debug". This is the way to get rid of the initial
+warning message block, too.
+
+With "#define MANY_SESSION 1" (sbpcd.c), the driver can use
+"many-session" CDs. This will work only with "new" drives like
+CR-562 or CR-563. That is NOT multisession - it is a CD
+with multiple independent sessions, each containing block
+addresses as if it were the only session. With this feature
+enabled, the driver will read the LAST session. Without it,
+the FIRST session gets read.
+If you would like the support of reading "in-between" sessions,
+drop me a mail and some food for the soul. :-)
+Those "many-session" CDs can get made by CDROM writers like
+Philips CDD 521.
+With this feature enabled, it is impossible to read true
+multisession CDs.
+
+
+Auto-probing at boot time:
+--------------------------
+
+The driver does auto-probing at all well-known interface card
+addresses now. The idea to do that came from Adam J. Richter
+(YGGDRASIL).
+
+This auto-probing looks first at the configured address resp.
+the address submitted by the kernel command line. With this,
+it is possible to use this driver within installation boot
+floppies, and for any non-standard address, too.
+
+Auto-probing will make an assumption about the interface type
+("SBPRO" or not), based upon the address. That assumption may
+be wrong (initialization will be o.k., but you will get I/O
+errors during mount). In that case, use the "kernel command
+line" feature and specify address & type at boot time to find
+out the right setup.
+
+SBPCD's auto-probing happens before the initialization of the
+net drivers. That makes a hang possible if an ethernet card
+gets touched.
+
+For every-day use, address and type should get configured
+within sbpcd.h. That will stop the auto-probing due to success
+with the first try.
+
+
+Setting up address and interface type:
+--------------------------------------
+
+If your I/O port address is not 0x0230 or if you use a "no-sound"
+interface other than OmniCD, you have to look for the #defines
+near the beginning of sbpcd.h and configure them: set SBPRO to
+0 or 1, and change CDROM_PORT to the address of your CDROM I/O port.
+
+Most of the "SoundBlaster compatible" cards behave like the
+no-sound interfaces!
+
+With "original" SB Pro cards, an initial setting of CD_volume
+through the sound cards MIXER register gets done. That happens
+at the end of "sbpcd_init". If you are using a "compatible"
+sound card of type "LaserMate", you can change that code to get
+it done with your card, too...
+
+
+Using audio CDs:
+----------------
+
+Workman, WorkBone, xcdplayer and cdplayer should work good now,
+even with the double-speed drives.
+
+The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer
+wants "/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate
+links for using them without the need of supplying parameters.
+
+
+Known problems:
+---------------
+
+Currently, the detection of disk change or removal does not
+work as good as it should.
+
+Further, I do not know if this driver can live together with a
+SCSI CD-ROM driver and/or device, but I hope so.
+
+
+
+Bug reports, comments, wishes, donations (technical information
+is a donation, too :-) etc. to
+ emoenke@gwdg.de
+ or to eberhard_moenkeberg@rollo.central.de
+ or to my FIDO address: Eberhard Moenkeberg, 2:2437/210.27
+
+
+SnailMail address, preferable for CD editors if they want to submit
+a free "cooperation" copy:
+ Eberhard Moenkeberg
+ Reinholdstr. 14
+ D-37083 Goettingen
+ Germany
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 7ea4f88..5e42788 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -9,6 +9,7 @@
*/
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/config.h>
@@ -406,6 +407,10 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
if (bh[i]) {
bh[i]->b_req = 1;
make_request(major, rw, bh[i]);
+ if (rw == READ || rw == READA)
+ kstat.pgpgin++;
+ else
+ kstat.pgpgout++;
}
}
if (plugged) {
diff --git a/drivers/block/sbpcd.c b/drivers/block/sbpcd.c
index 43df7eb..3312e7f 100644
--- a/drivers/block/sbpcd.c
+++ b/drivers/block/sbpcd.c
@@ -5,7 +5,7 @@
* and for "no-sound" interfaces like Lasermate and the
* Panasonic CI-101P.
*
- * NOTE: This is release 1.0.
+ * NOTE: This is release 1.2.
* It works with my SbPro & drive CR-521 V2.11 from 2/92
* and with the new CR-562-B V0.75 on a "naked" Panasonic
* CI-101P interface. And vice versa.
@@ -57,6 +57,11 @@
* 1.1 Do SpinUp for new drives, too.
* Revised for clean compile under "old" kernels (pl9).
*
+ * 1.2 Found the "workman with double-speed drive" bug: use the driver's
+ * audio_state, not what the drive is reporting with ReadSubQ.
+ *
+ *
+ *
* special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine
* elaborated speed-up experiments (and the fabulous results!), for
* the "push" towards load-free wait loops, and for the extensive mail
@@ -68,17 +73,14 @@
*
* The FTP-home of this driver is
* ftp.gwdg.de:/pub/linux/cdrom/drivers/sbpcd/.
- * I will serve tsx-11.mit.edu, sunsite.unc.edu and
- * ftp.funet.fi, too.
- *
*
* If you change this software, you should mail a .diff
- * file with some description lines to emoenke.gwdg.de.
+ * file with some description lines to emoenke@gwdg.de.
* I want to know about it.
*
* If you are the editor of a Linux CD, you should
- * add sbpcd.c into your boot floppy kernel and send
- * me one of your CDs for free.
+ * enable sbpcd.c within your boot floppy kernel and
+ * send me one of your CDs for free.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -125,7 +127,7 @@
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
#include "blk.h"
-#define VERSION "1.1"
+#define VERSION "1.2"
#define SBPCD_DEBUG
@@ -143,7 +145,7 @@
#define MANY_SESSION 0
#define CDMKE
#undef FUTURE
-#define WORKMAN 1 /* some testing stuff to make it better */
+#define WORKMAN 0 /* some testing stuff to make it better */
/*==========================================================================*/
/*==========================================================================*/
@@ -2057,7 +2059,6 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
case CDROMPLAYMSF:
DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYMSF entered.\n"));
-#if WORKMAN
if (DS[d].audio_state==audio_playing)
{
i=xx_Pause_Resume(1);
@@ -2067,9 +2068,6 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
DS[d].pos_audio_start=DS[d].SubQ_run_tot;
i=xx_Seek(DS[d].pos_audio_start,1);
}
-#else
- if (DS[d].audio_state==audio_playing) return (-EINVAL);
-#endif
st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf));
if (st) return (st);
memcpy_fromfs(&msf, (void *) arg, sizeof(struct cdrom_msf));
@@ -2203,8 +2201,21 @@ static int sbpcd_ioctl(struct inode *inode,struct file *file,
st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
if (st) return (st);
memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl));
+#if 0
if (DS[d].SubQ_audio==0x80) DS[d].SubQ_audio=CDROM_AUDIO_NO_STATUS;
- SC.cdsc_audiostatus=DS[d].SubQ_audio;
+#endif
+ switch (DS[d].audio_state)
+ {
+ case audio_playing:
+ SC.cdsc_audiostatus=CDROM_AUDIO_PLAY;
+ break;
+ case audio_pausing:
+ SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED;
+ break;
+ default:
+ SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS;
+ break;
+ }
SC.cdsc_adr=DS[d].SubQ_ctl_adr;
SC.cdsc_ctrl=DS[d].SubQ_ctl_adr>>4;
SC.cdsc_trk=bcd2bin(DS[d].SubQ_trk);
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 2a72deb..efdeb13 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -14,6 +14,11 @@
* 'void update_screen(int new_console)'
* 'void blank_screen(void)'
* 'void unblank_screen(void)'
+ *
+ * 'int con_get_font(char *)'
+ * 'int con_set_font(char *)'
+ * 'int con_get_trans(char *)'
+ * 'int con_set_trans(char *)'
*
* Hopefully this will be a rather complete VT102 implementation.
*
@@ -23,8 +28,17 @@
* Chars, and VT100 enhancements by Peter MacDonald.
*
* Copy and paste function by Andrew Haylett.
+ *
+ * User definable mapping table and font loading by Eugene G. Crosser,
+ * <crosser@pccross.msk.su>
+ *
+ * Code to check for different video-cards mostly by Galen Hunt,
+ * <g-hunt@ee.utah.edu>
+ *
*/
+#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
+
/*
* NOTE!!! We sometimes disable and enable interrupts for a short while
* (to put a word in video IO), but this will work even for keyboard
@@ -32,11 +46,6 @@
* interrupt, as we use trap-gates. Hopefully all is well.
*/
-/*
- * Code to check for different video-cards mostly by Galen Hunt,
- * <g-hunt@ee.utah.edu>
- */
-
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/tty.h>
@@ -45,12 +54,12 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/kd.h>
-#include <linux/keyboard.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
+#include "kbd_kern.h"
#include "vt_kern.h"
#ifdef CONFIG_SELECTION
@@ -128,7 +137,6 @@ static struct {
unsigned long vc_ques : 1;
unsigned long vc_need_wrap : 1;
unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
- unsigned char vc_kbdmode;
unsigned char * vc_translate;
unsigned char * vc_G0_charset;
unsigned char * vc_G1_charset;
@@ -186,16 +194,15 @@ static int console_blanked = 0;
#define s_reverse (vc_cons[currcons].vc_s_reverse)
#define ulcolor (vc_cons[currcons].vc_ulcolor)
#define halfcolor (vc_cons[currcons].vc_halfcolor)
-#define kbdmode (vc_cons[currcons].vc_kbdmode)
#define tab_stop (vc_cons[currcons].vc_tab_stop)
#define vcmode (vt_cons[currcons].vc_mode)
#define vtmode (vt_cons[currcons].vt_mode)
#define vtpid (vt_cons[currcons].vt_pid)
#define vtnewvt (vt_cons[currcons].vt_newvt)
-#define set_kbd(x) set_vc_kbd_flag(kbd_table+currcons,x)
-#define clr_kbd(x) clr_vc_kbd_flag(kbd_table+currcons,x)
-#define is_kbd(x) vc_kbd_flag(kbd_table+currcons,x)
+#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
+#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
+#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
#define decarm VC_REPEAT
#define decckm VC_CKMODE
@@ -261,12 +268,31 @@ static unsigned char * translations[] = {
"\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
"\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
"\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
+ "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
+ /* USER: customizable mappings, initialized as the previous one (IBM) */
+(unsigned char *)
+ "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017"
+ "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037"
+ "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057"
+ "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077"
+ "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117"
+ "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137"
+ "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157"
+ "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177"
+ "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+ "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277"
+ "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317"
+ "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
+ "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357"
"\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"
};
#define NORM_TRANS (translations[0])
#define GRAF_TRANS (translations[1])
#define NULL_TRANS (translations[2])
+#define USER_TRANS (translations[3])
static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
8,12,10,14, 9,13,11,15 };
@@ -940,10 +966,8 @@ static void reset_terminal(int currcons, int do_clear)
clr_kbd(decckm);
clr_kbd(kbdapplic);
clr_kbd(lnm);
- kbd_table[currcons].flags =
- (kbd_table[currcons].flags & ~LED_MASK) |
- (kbd_table[currcons].default_flags & LED_MASK);
- kbdmode = 0;
+ kbd_table[currcons].lockstate = 0;
+ kbd_table[currcons].ledstate = kbd_table[currcons].default_ledstate;
set_leds();
default_attr(currcons);
@@ -1256,6 +1280,8 @@ void con_write(struct tty_struct * tty)
G0_charset = NORM_TRANS;
else if (c == 'U')
G0_charset = NULL_TRANS;
+ else if (c == 'K')
+ G0_charset = USER_TRANS;
if (charset == 0)
translate = G0_charset;
state = ESnormal;
@@ -1267,6 +1293,8 @@ void con_write(struct tty_struct * tty)
G1_charset = NORM_TRANS;
else if (c == 'U')
G1_charset = NULL_TRANS;
+ else if (c == 'K')
+ G1_charset = USER_TRANS;
if (charset == 1)
translate = G1_charset;
state = ESnormal;
@@ -1793,3 +1821,132 @@ static void clear_selection()
}
}
#endif /* CONFIG_SELECTION */
+
+/*
+ * PIO_FONT support.
+ */
+
+#define colourmap ((char *)0xa0000)
+#define blackwmap ((char *)0xb0000)
+#define cmapsz 8192
+#define seq_port_reg (0x3c4)
+#define seq_port_val (0x3c5)
+#define gr_port_reg (0x3ce)
+#define gr_port_val (0x3cf)
+
+static int set_get_font(char * arg, int set)
+{
+#ifdef CAN_LOAD_EGA_FONTS
+ int i;
+ char *charmap;
+
+ /* no use to "load" CGA... */
+
+ if (video_type == VIDEO_TYPE_EGAC)
+ charmap = colourmap;
+ else if (video_type == VIDEO_TYPE_EGAM)
+ charmap = blackwmap;
+ else
+ return -EINVAL;
+
+ i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz);
+ if (i)
+ return i;
+
+ cli();
+ outb_p( 0x00, seq_port_reg ); /* First, the sequencer */
+ outb_p( 0x01, seq_port_val ); /* Synchronous reset */
+ outb_p( 0x02, seq_port_reg );
+ outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */
+ outb_p( 0x04, seq_port_reg );
+ outb_p( 0x07, seq_port_val ); /* Sequential addressing */
+ outb_p( 0x00, seq_port_reg );
+ outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */
+
+ outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
+ outb_p( 0x02, gr_port_val ); /* select map 2 */
+ outb_p( 0x05, gr_port_reg );
+ outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */
+ outb_p( 0x06, gr_port_reg );
+ outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */
+ sti();
+
+ if (set)
+ for (i=0; i<cmapsz ; i++)
+ *(charmap+i) = get_fs_byte(arg+i);
+ else
+ for (i=0; i<cmapsz ; i++)
+ put_fs_byte(*(charmap+i), arg+i);
+
+ cli();
+ outb_p( 0x00, seq_port_reg ); /* Frist, the sequencer */
+ outb_p( 0x01, seq_port_val ); /* Synchronous reset */
+ outb_p( 0x02, seq_port_reg );
+ outb_p( 0x03, seq_port_val ); /* CPU writes to maps 0 and 1 */
+ outb_p( 0x04, seq_port_reg );
+ outb_p( 0x03, seq_port_val ); /* odd-even addressing */
+ outb_p( 0x00, seq_port_reg );
+ outb_p( 0x03, seq_port_val ); /* clear synchronous reset */
+
+ outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */
+ outb_p( 0x00, gr_port_val ); /* select map 0 for CPU */
+ outb_p( 0x05, gr_port_reg );
+ outb_p( 0x10, gr_port_val ); /* enable even-odd addressing */
+ outb_p( 0x06, gr_port_reg );
+ outb_p( 0x0e, gr_port_val ); /* map starts at b800:0000 */
+ sti();
+
+ return 0;
+#else
+ return -EINVAL;
+#endif
+}
+
+/*
+ * Load font into the EGA/VGA character generator. arg points to a 8192
+ * byte map, 32 bytes per character. Only first H of them are used for
+ * 8xH fonts (0 < H <= 32).
+ */
+
+int con_set_font (char *arg)
+{
+ return set_get_font (arg,1);
+}
+
+int con_get_font (char *arg)
+{
+ return set_get_font (arg,0);
+}
+
+/*
+ * Load customizable translation table (USER_TRANS[]). All checks are here,
+ * so we need only include 'return con_set_trans(arg)' in the ioctl handler
+ * arg points to a 256 byte translation table.
+ */
+int con_set_trans(char * arg)
+{
+ int i;
+
+ i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ);
+ if (i)
+ return i;
+
+ for (i=0; i<E_TABSZ ; i++) USER_TRANS[i] = get_fs_byte(arg+i);
+ USER_TRANS[012]=0;
+ USER_TRANS[014]=0;
+ USER_TRANS[015]=0;
+ USER_TRANS[033]=0;
+ return 0;
+}
+
+int con_get_trans(char * arg)
+{
+ int i;
+
+ i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ);
+ if (i)
+ return i;
+
+ for (i=0; i<E_TABSZ ; i++) put_fs_byte(USER_TRANS[i],arg+i);
+ return 0;
+}
diff --git a/drivers/char/defkeymap.c b/drivers/char/defkeymap.c
index 171931e..61100e7 100644
--- a/drivers/char/defkeymap.c
+++ b/drivers/char/defkeymap.c
@@ -9,11 +9,11 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
{
0x0200, 0x001b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036,
0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0x007f, 0x0009,
- 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069,
- 0x006f, 0x0070, 0x005b, 0x005d, 0x0201, 0x0702, 0x0061, 0x0073,
- 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x003b,
- 0x0027, 0x0060, 0x0700, 0x005c, 0x007a, 0x0078, 0x0063, 0x0076,
- 0x0062, 0x006e, 0x006d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c,
+ 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
+ 0x0b6f, 0x0b70, 0x005b, 0x005d, 0x0201, 0x0702, 0x0b61, 0x0b73,
+ 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x003b,
+ 0x0027, 0x0060, 0x0700, 0x005c, 0x0b7a, 0x0b78, 0x0b63, 0x0b76,
+ 0x0b62, 0x0b6e, 0x0b6d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c,
0x0703, 0x0020, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0209, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -26,11 +26,11 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
}, {
0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009,
- 0x0051, 0x0057, 0x0045, 0x0052, 0x0054, 0x0059, 0x0055, 0x0049,
- 0x004f, 0x0050, 0x007b, 0x007d, 0x0201, 0x0702, 0x0041, 0x0053,
- 0x0044, 0x0046, 0x0047, 0x0048, 0x004a, 0x004b, 0x004c, 0x003a,
- 0x0022, 0x007e, 0x0700, 0x007c, 0x005a, 0x0058, 0x0043, 0x0056,
- 0x0042, 0x004e, 0x004d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c,
+ 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49,
+ 0x0b4f, 0x0b50, 0x007b, 0x007d, 0x0201, 0x0702, 0x0b41, 0x0b53,
+ 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x003a,
+ 0x0022, 0x007e, 0x0700, 0x007c, 0x0b5a, 0x0b58, 0x0b43, 0x0b56,
+ 0x0b42, 0x0b4e, 0x0b4d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c,
0x0703, 0x0020, 0x0207, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0208, 0x0203, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -43,11 +43,11 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
}, {
0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200,
0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200,
- 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069,
- 0x006f, 0x0070, 0x0200, 0x007e, 0x0201, 0x0702, 0x0061, 0x0073,
- 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x007a, 0x0078, 0x0063, 0x0076,
- 0x0062, 0x006e, 0x006d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69,
+ 0x0b6f, 0x0b70, 0x0200, 0x007e, 0x0201, 0x0702, 0x0b61, 0x0b73,
+ 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x0b7a, 0x0b78, 0x0b63, 0x0b76,
+ 0x0b62, 0x0b6e, 0x0b6d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -60,11 +60,11 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0051, 0x0057, 0x0045, 0x0052, 0x0054, 0x0059, 0x0055, 0x0049,
- 0x004f, 0x0050, 0x0200, 0x0200, 0x0201, 0x0702, 0x0041, 0x0053,
- 0x0044, 0x0046, 0x0047, 0x0048, 0x004a, 0x004b, 0x004c, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x005a, 0x0058, 0x0043, 0x0056,
- 0x0042, 0x004e, 0x004d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49,
+ 0x0b4f, 0x0b50, 0x0200, 0x0200, 0x0201, 0x0702, 0x0b41, 0x0b53,
+ 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x0b5a, 0x0b58, 0x0b43, 0x0b56,
+ 0x0b42, 0x0b4e, 0x0b4d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
diff --git a/drivers/char/kbd_kern.h b/drivers/char/kbd_kern.h
index e69de29..4f85272 100644
--- a/drivers/char/kbd_kern.h
+++ b/drivers/char/kbd_kern.h
@@ -0,0 +1,107 @@
+#ifndef _KBD_KERN_H
+#define _KBD_KERN_H
+
+#include <linux/interrupt.h>
+#define set_leds() mark_bh(KEYBOARD_BH)
+
+#include <linux/keyboard.h>
+
+/*
+ * kbd->xxx contains the VC-local things (flag settings etc..)
+ *
+ * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
+ * The code in KDGETLED / KDSETLED depends on the internal and
+ * external order being the same.
+ *
+ * Note: lockstate is used as index in the array key_map.
+ */
+struct kbd_struct {
+ unsigned char ledstate; /* 3 bits */
+ unsigned char default_ledstate;
+#define VC_SCROLLOCK 0 /* scroll-lock mode */
+#define VC_NUMLOCK 1 /* numeric lock mode */
+#define VC_CAPSLOCK 2 /* capslock mode */
+
+ unsigned char lockstate; /* 4 bits - must be in 0..15 */
+#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */
+#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */
+#define VC_CTRLLOCK KG_CTRL /* control lock mode */
+#define VC_ALTLOCK KG_ALT /* alt lock mode */
+
+ unsigned char modeflags;
+#define VC_APPLIC 0 /* application key mode */
+#define VC_CKMODE 1 /* cursor key mode */
+#define VC_REPEAT 2 /* keyboard repeat */
+#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */
+#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */
+#define VC_PAUSE 5 /* pause key pressed - unused */
+#define VC_RAW 6 /* raw (scancode) mode */
+#define VC_MEDIUMRAW 7 /* medium raw (keycode) mode */
+};
+
+extern struct kbd_struct kbd_table[];
+
+
+extern unsigned long kbd_init(unsigned long);
+
+extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ return ((kbd->ledstate >> flag) & 1);
+}
+
+extern inline int vc_kbd_lock(struct kbd_struct * kbd, int flag)
+{
+ return ((kbd->lockstate >> flag) & 1);
+}
+
+extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ return ((kbd->modeflags >> flag) & 1);
+}
+
+extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ kbd->ledstate |= 1 << flag;
+}
+
+extern inline void set_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+{
+ kbd->lockstate |= 1 << flag;
+}
+
+extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ kbd->modeflags |= 1 << flag;
+}
+
+extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ kbd->ledstate &= ~(1 << flag);
+}
+
+extern inline void clr_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+{
+ kbd->lockstate &= ~(1 << flag);
+}
+
+extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ kbd->modeflags &= ~(1 << flag);
+}
+
+extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+ kbd->ledstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+{
+ kbd->lockstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+ kbd->modeflags ^= 1 << flag;
+}
+
+#endif
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index adec0e5..9bad94d 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1,7 +1,7 @@
/*
* linux/kernel/chr_drv/keyboard.c
*
- * Keyboard driver for Linux v0.96 using Latin-1.
+ * Keyboard driver for Linux v0.99 using Latin-1.
*
* Written for linux by Johan Myreen as a translation from
* the assembly version by Linus (with diacriticals added)
@@ -17,7 +17,6 @@
#include <linux/tty.h>
#include <linux/mm.h>
#include <linux/ptrace.h>
-#include <linux/keyboard.h>
#include <linux/interrupt.h>
#include <linux/config.h>
#include <linux/signal.h>
@@ -25,25 +24,21 @@
#include <asm/bitops.h>
+#include "kbd_kern.h"
#include "diacr.h"
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
-#ifndef KBD_DEFFLAGS
-
-#ifdef CONFIG_KBD_META
-#define KBD_META (1 << VC_META)
-#else
-#define KBD_META 0
+#ifndef KBD_DEFMODE
+#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META))
#endif
-#ifdef CONFIG_KBD_NUML
-#define KBD_NUML (1 << VC_NUMLOCK)
-#else
-#define KBD_NUML 0
+#ifndef KBD_DEFLEDS
+#define KBD_DEFLEDS (1 << VC_NUMLOCK)
#endif
-#define KBD_DEFFLAGS (KBD_NUML | (1 << VC_REPEAT) | KBD_META)
+#ifndef KBD_DEFLOCK
+#define KBD_DEFLOCK 0
#endif
/*
@@ -90,32 +85,26 @@ struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table;
static struct tty_struct * tty = NULL;
+/* used only by send_data - set by keyboard_interrupt */
static volatile unsigned char acknowledge = 0;
static volatile unsigned char resend = 0;
typedef void (*k_hand)(unsigned char value, char up_flag);
+typedef void (k_handfn)(unsigned char value, char up_flag);
-static void do_self(unsigned char value, char up_flag);
-static void do_fn(unsigned char value, char up_flag);
-static void do_spec(unsigned char value, char up_flag);
-static void do_pad(unsigned char value, char up_flag);
-static void do_dead(unsigned char value, char up_flag);
-static void do_cons(unsigned char value, char up_flag);
-static void do_cur(unsigned char value, char up_flag);
-static void do_shift(unsigned char value, char up_flag);
-static void do_meta(unsigned char value, char up_flag);
-static void do_ascii(unsigned char value, char up_flag);
-static void do_lock(unsigned char value, char up_flag);
+static k_handfn
+ do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
+ do_meta, do_ascii, do_lock, do_lowercase;
static k_hand key_handler[] = {
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii, do_lock
+ do_meta, do_ascii, do_lock, do_lowercase
};
/* maximum values each key_handler can handle */
const int max_vals[] = {
255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT,
- 255, 9, 3
+ 255, 9, 3, 255
};
const int NR_TYPES = SIZE(max_vals);
@@ -219,7 +208,7 @@ static void keyboard_interrupt(int int_pt_regs)
}
tty = TTY_TABLE(0);
kbd = kbd_table + fg_console;
- if ((raw_mode = vc_kbd_flag(kbd,VC_RAW))) {
+ if ((raw_mode = vc_kbd_mode(kbd,VC_RAW))) {
put_queue(scancode);
/* we do not return yet, because we want to maintain
the key_down array, so that we have the correct
@@ -301,7 +290,7 @@ static void keyboard_interrupt(int int_pt_regs)
if (raw_mode)
goto end_kbd_intr;
- if (vc_kbd_flag(kbd, VC_MEDIUMRAW)) {
+ if (vc_kbd_mode(kbd, VC_MEDIUMRAW)) {
put_queue(scancode + up_flag);
goto end_kbd_intr;
}
@@ -320,13 +309,24 @@ static void keyboard_interrupt(int int_pt_regs)
* with slow applications and under heavy loads.
*/
if (!rep ||
- (vc_kbd_flag(kbd,VC_REPEAT) && tty &&
+ (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
(L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q)))))
{
u_short key_code;
+ u_char type;
+
+ /* the XOR below used to be an OR */
+ int shift_final = shift_state ^ kbd->lockstate;
- key_code = key_map[shift_state][scancode];
- (*key_handler[key_code >> 8])(key_code & 0xff, up_flag);
+ key_code = key_map[shift_final][scancode];
+ type = KTYP(key_code);
+
+ if (type == KT_LETTER) {
+ type = KT_LATIN;
+ if (vc_kbd_led(kbd,VC_CAPSLOCK))
+ key_code = key_map[shift_final ^ (1<<KG_SHIFT)][scancode];
+ }
+ (*key_handler[type])(key_code & 0xff, up_flag);
}
end_kbd_intr:
@@ -379,7 +379,7 @@ static void applkey(int key, char mode)
static void enter(void)
{
put_queue(13);
- if (vc_kbd_flag(kbd,VC_CRLF))
+ if (vc_kbd_mode(kbd,VC_CRLF))
put_queue(10);
}
@@ -387,14 +387,14 @@ static void caps_toggle(void)
{
if (rep)
return;
- chg_vc_kbd_flag(kbd,VC_CAPSLOCK);
+ chg_vc_kbd_led(kbd,VC_CAPSLOCK);
}
static void caps_on(void)
{
if (rep)
return;
- set_vc_kbd_flag(kbd,VC_CAPSLOCK);
+ set_vc_kbd_led(kbd,VC_CAPSLOCK);
}
static void show_ptregs(void)
@@ -419,30 +419,34 @@ static void hold(void)
{
if (rep || !tty)
return;
- /* pressing scroll lock 1st time sends ^S, ChN */
- /* pressing scroll lock 2nd time sends ^Q, ChN */
- /* now done directly without regard to ISIG -- jlc */
- if (!vc_kbd_flag(kbd, VC_SCROLLOCK))
- stop_tty(tty);
- else
+
+ /*
+ * Note: SCROLLOCK wil be set (cleared) by stop_tty (start_tty);
+ * these routines are also activated by ^S/^Q.
+ * (And SCROLLOCK can also be set by the ioctl KDSETLED.)
+ */
+ if (tty->stopped)
start_tty(tty);
+ else
+ stop_tty(tty);
}
-static void num(void)
-{
#if 0
- if (k_down[KG_CTRL]) {
- /* pause key pressed, sends E1 1D 45, ChN */
- chg_vc_kbd_flag(kbd,VC_PAUSE);
- return;
- }
+/* unused at present - and the VC_PAUSE bit is not used anywhere either */
+static void pause(void)
+{
+ chg_vc_kbd_mode(kbd,VC_PAUSE);
+}
#endif
- if (vc_kbd_flag(kbd,VC_APPLIC)) {
+
+static void num(void)
+{
+ if (vc_kbd_mode(kbd,VC_APPLIC)) {
applkey('P', 1);
return;
}
if (!rep) /* no autorepeat for numlock, ChN */
- chg_vc_kbd_flag(kbd,VC_NUMLOCK);
+ chg_vc_kbd_led(kbd,VC_NUMLOCK);
}
static void lastcons(void)
@@ -494,6 +498,11 @@ static void do_spec(unsigned char value, char up_flag)
return;
fn_table[value]();
}
+
+static void do_lowercase(unsigned char value, char up_flag)
+{
+ printk("keyboard.c: do_lowercase was called - impossible\n");
+}
static void do_self(unsigned char value, char up_flag)
{
@@ -509,13 +518,6 @@ static void do_self(unsigned char value, char up_flag)
return;
}
- /* kludge... but works for ISO 8859-1 */
- if (vc_kbd_flag(kbd,VC_CAPSLOCK))
- if ((value >= 'a' && value <= 'z')
- || (value >= 224 && value <= 254)) {
- value -= 32;
- }
-
put_queue(value);
}
@@ -591,12 +593,12 @@ static void do_pad(unsigned char value, char up_flag)
return; /* no action, if this is a key release */
/* kludge... shift forces cursor/number keys */
- if (vc_kbd_flag(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
+ if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) {
applkey(app_map[value], 1);
return;
}
- if (!vc_kbd_flag(kbd,VC_NUMLOCK))
+ if (!vc_kbd_led(kbd,VC_NUMLOCK))
switch (value) {
case KVAL(K_PCOMMA):
case KVAL(K_PDOT):
@@ -630,12 +632,12 @@ static void do_pad(unsigned char value, char up_flag)
do_fn(KVAL(K_PGUP), 0);
return;
case KVAL(K_P5):
- applkey('G', vc_kbd_flag(kbd, VC_APPLIC));
+ applkey('G', vc_kbd_mode(kbd, VC_APPLIC));
return;
}
put_queue(pad_chars[value]);
- if (value == KVAL(K_PENTER) && vc_kbd_flag(kbd, VC_CRLF))
+ if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF))
put_queue(10);
}
@@ -645,7 +647,7 @@ static void do_cur(unsigned char value, char up_flag)
if (up_flag)
return;
- applkey(cur_chars[value], vc_kbd_flag(kbd,VC_CKMODE));
+ applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE));
}
static void do_shift(unsigned char value, char up_flag)
@@ -658,7 +660,7 @@ static void do_shift(unsigned char value, char up_flag)
/* kludge... */
if (value == KVAL(K_CAPSSHIFT)) {
value = KVAL(K_SHIFT);
- clr_vc_kbd_flag(kbd, VC_CAPSLOCK);
+ clr_vc_kbd_led(kbd, VC_CAPSLOCK);
}
if (up_flag) {
@@ -711,7 +713,7 @@ static void do_meta(unsigned char value, char up_flag)
if (up_flag)
return;
- if (vc_kbd_flag(kbd, VC_META)) {
+ if (vc_kbd_mode(kbd, VC_META)) {
put_queue('\033');
put_queue(value);
} else
@@ -729,30 +731,11 @@ static void do_ascii(unsigned char value, char up_flag)
npadch = (npadch * 10 + value) % 1000;
}
-/* done stupidly to avoid coding in any dependencies of
-lock values, shift values and kbd flags bit positions */
static void do_lock(unsigned char value, char up_flag)
{
if (up_flag || rep)
return;
- switch (value) {
- case KVAL(K_SHIFTLOCK):
- chg_vc_kbd_flag(kbd, VC_SHIFTLOCK);
- do_shift(KG_SHIFT, !vc_kbd_flag(kbd, VC_SHIFTLOCK));
- break;
- case KVAL(K_CTRLLOCK):
- chg_vc_kbd_flag(kbd, VC_CTRLLOCK);
- do_shift(KG_CTRL, !vc_kbd_flag(kbd, VC_CTRLLOCK));
- break;
- case KVAL(K_ALTLOCK):
- chg_vc_kbd_flag(kbd, VC_ALTLOCK);
- do_shift(KG_ALT, !vc_kbd_flag(kbd, VC_ALTLOCK));
- break;
- case KVAL(K_ALTGRLOCK):
- chg_vc_kbd_flag(kbd, VC_ALTGRLOCK);
- do_shift(KG_ALTGR, !vc_kbd_flag(kbd, VC_ALTGRLOCK));
- break;
- }
+ chg_vc_kbd_lock(kbd, value);
}
/*
@@ -799,7 +782,7 @@ static int send_data(unsigned char data)
static void kbd_bh(void * unused)
{
static unsigned char old_leds = 0xff;
- unsigned char leds = kbd_table[fg_console].flags & LED_MASK;
+ unsigned char leds = kbd_table[fg_console].ledstate;
if (leds != old_leds) {
old_leds = leds;
@@ -874,8 +857,10 @@ unsigned long kbd_init(unsigned long kmem_start)
kbd = kbd_table + 0;
for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) {
- kbd->flags = KBD_DEFFLAGS;
- kbd->default_flags = KBD_DEFFLAGS;
+ kbd->ledstate = KBD_DEFLEDS;
+ kbd->default_ledstate = KBD_DEFLEDS;
+ kbd->lockstate = KBD_DEFLOCK;
+ kbd->modeflags = KBD_DEFMODE;
}
bh_base[KEYBOARD_BH].routine = kbd_bh;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 7fa9dee..9d46136 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -90,6 +90,8 @@ static int mmap_mem(struct inode * inode, struct file * file,
if (off & 0xfff || off + len < off)
return -ENXIO;
+ if (x86 > 3 && off >= high_memory)
+ prot |= PAGE_PCD;
if (remap_page_range(addr, off, len, prot))
return -EAGAIN;
/* try to create a dummy vmm-structure so that the rest of the kernel knows we are here */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index c2da44d..2997601 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -49,13 +49,13 @@
#include <linux/kd.h>
#include <linux/mm.h>
#include <linux/string.h>
-#include <linux/keyboard.h>
#include <linux/malloc.h>
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/bitops.h>
+#include "kbd_kern.h"
#include "vt_kern.h"
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
@@ -390,7 +390,8 @@ void complete_change_console(unsigned int new_console)
* to account for and tracking tty count may be undesirable.
*/
vt_cons[new_console].vc_mode = KD_TEXT;
- clr_vc_kbd_flag(kbd_table + new_console, VC_RAW);
+ clr_vc_kbd_mode(kbd_table + new_console, VC_RAW);
+ clr_vc_kbd_mode(kbd_table + new_console, VC_MEDIUMRAW);
vt_cons[new_console].vt_mode.mode = VT_AUTO;
vt_cons[new_console].vt_mode.waitv = 0;
vt_cons[new_console].vt_mode.relsig = 0;
@@ -475,7 +476,8 @@ void change_console(unsigned int new_console)
* to account for and tracking tty count may be undesirable.
*/
vt_cons[fg_console].vc_mode = KD_TEXT;
- clr_vc_kbd_flag(kbd_table + fg_console, VC_RAW);
+ clr_vc_kbd_mode(kbd_table + fg_console, VC_RAW);
+ clr_vc_kbd_mode(kbd_table + fg_console, VC_MEDIUMRAW);
vt_cons[fg_console].vt_mode.mode = VT_AUTO;
vt_cons[fg_console].vt_mode.waitv = 0;
vt_cons[fg_console].vt_mode.relsig = 0;
@@ -515,7 +517,7 @@ void stop_tty(struct tty_struct *tty)
if (tty->stop)
(tty->stop)(tty);
if (IS_A_CONSOLE(tty->line)) {
- set_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
+ set_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
}
@@ -532,11 +534,11 @@ void start_tty(struct tty_struct *tty)
}
if (tty->start)
(tty->start)(tty);
+ TTY_WRITE_FLUSH(tty);
if (IS_A_CONSOLE(tty->line)) {
- clr_vc_kbd_flag(kbd_table + fg_console, VC_SCROLLOCK);
+ clr_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK);
set_leds();
}
- TTY_WRITE_FLUSH(tty);
}
/* Perform OPOST processing. Returns -1 when the write_q becomes full
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index c443c3a..1f4b50e 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -192,25 +192,27 @@ static int set_termios_2(struct tty_struct * tty, struct termios * termios)
tty->erasing = 0;
}
sti();
- if (canon_change && !(tty->termios->c_lflag & ICANON) &&
- !EMPTY(&tty->secondary))
+ if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary))
/* Get characters left over from canonical mode. */
wake_up_interruptible(&tty->secondary.proc_list);
/* see if packet mode change of state */
- /* The BSD man page pty.4 says that TIOCPKT_NOSTOP should be sent
- if the new state differs from ^S/^Q, but that's a bad way of
- detecting a new flow control scheme. Instead, a status byte
- is only sent if IXON has changed. */
- if (tty->link && tty->link->packet &&
- (old_termios.c_iflag ^ tty->termios->c_iflag) & IXON) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
- if (tty->termios->c_iflag & IXON)
- tty->ctrl_status |= TIOCPKT_DOSTOP;
- else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
- wake_up_interruptible(&tty->link->secondary.proc_list);
+ if (tty->link && tty->link->packet) {
+ int old_flow = ((old_termios.c_iflag & IXON) &&
+ (old_termios.c_cc[VSTOP] == '\023') &&
+ (old_termios.c_cc[VSTART] == '\021'));
+ int new_flow = (I_IXON(tty) &&
+ STOP_CHAR(tty) == '\023' &&
+ START_CHAR(tty) == '\021');
+ if (old_flow != new_flow) {
+ tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ if (new_flow)
+ tty->ctrl_status |= TIOCPKT_DOSTOP;
+ else
+ tty->ctrl_status |= TIOCPKT_NOSTOP;
+ wake_up_interruptible(&tty->link->secondary.proc_list);
+ }
}
unset_locked_termios(tty->termios, &old_termios,
@@ -376,8 +378,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
return retval;
if (cmd == TCSETSF || cmd == TCSETSW) {
if (cmd == TCSETSF)
- flush_input(tty);
- wait_until_sent(tty);
+ flush_input(termios_tty);
+ wait_until_sent(termios_tty);
}
return set_termios(termios_tty, (struct termios *) arg,
termios_dev);
@@ -391,8 +393,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
return retval;
if (cmd == TCSETAF || cmd == TCSETAW) {
if (cmd == TCSETAF)
- flush_input(tty);
- wait_until_sent(tty);
+ flush_input(termios_tty);
+ wait_until_sent(termios_tty);
}
return set_termio(termios_tty, (struct termio *) arg,
termios_dev);
@@ -484,7 +486,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
put_fs_long(termios_tty->pgrp, (pid_t *) arg);
return 0;
case TIOCSPGRP:
- retval = check_change(tty, dev);
+ retval = check_change(termios_tty, termios_dev);
if (retval)
return retval;
if ((current->tty < 0) ||
@@ -496,7 +498,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
return -EINVAL;
if (session_of_pgrp(pgrp) != current->session)
return -EPERM;
- termios_tty->pgrp = pgrp;
+ termios_tty->pgrp = pgrp;
return 0;
case TIOCOUTQ:
retval = verify_area(VERIFY_WRITE, (void *) arg,
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 28b5e40..2fb3731 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -11,7 +11,6 @@
#include <linux/tty.h>
#include <linux/timer.h>
#include <linux/kernel.h>
-#include <linux/keyboard.h>
#include <linux/kd.h>
#include <linux/vt.h>
#include <linux/string.h>
@@ -19,6 +18,7 @@
#include <asm/io.h>
#include <asm/segment.h>
+#include "kbd_kern.h"
#include "vt_kern.h"
#include "diacr.h"
@@ -45,6 +45,14 @@ extern void complete_change_console(unsigned int new_console);
extern int vt_waitactive(void);
/*
+ * routines to load custom translation table and EGA/VGA font from console.c
+ */
+extern int con_set_trans(char * table);
+extern int con_get_trans(char * table);
+extern int con_set_font(char * fontmap);
+extern int con_get_font(char * fontmap);
+
+/*
* these are the valid i/o ports we're allowed to change. they map all the
* video ports
*/
@@ -209,30 +217,57 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EINVAL;
case KDSKBMODE:
- if (arg == K_RAW) {
- set_vc_kbd_flag(kbd, VC_RAW);
- clr_vc_kbd_flag(kbd, VC_MEDIUMRAW);
- } else if (arg == K_XLATE) {
- clr_vc_kbd_flag(kbd, VC_RAW);
- clr_vc_kbd_flag(kbd, VC_MEDIUMRAW);
+ switch(arg) {
+ case K_RAW:
+ set_vc_kbd_mode(kbd, VC_RAW);
+ clr_vc_kbd_mode(kbd, VC_MEDIUMRAW);
+ break;
+ case K_MEDIUMRAW:
+ clr_vc_kbd_mode(kbd, VC_RAW);
+ set_vc_kbd_mode(kbd, VC_MEDIUMRAW);
+ break;
+ case K_XLATE:
+ clr_vc_kbd_mode(kbd, VC_RAW);
+ clr_vc_kbd_mode(kbd, VC_MEDIUMRAW);
compute_shiftstate();
- } else if (arg == K_MEDIUMRAW) {
- clr_vc_kbd_flag(kbd, VC_RAW);
- set_vc_kbd_flag(kbd, VC_MEDIUMRAW);
- } else
+ break;
+ default:
return -EINVAL;
+ }
flush_input(tty);
return 0;
case KDGKBMODE:
i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
if (!i) {
- ucval = vc_kbd_flag(kbd, VC_RAW);
- if (vc_kbd_flag(kbd, VC_MEDIUMRAW))
- put_fs_long(K_MEDIUMRAW, (unsigned long *) arg);
- else
- put_fs_long(ucval ? K_RAW : K_XLATE,
- (unsigned long *) arg);
+ ucval = (vc_kbd_mode(kbd, VC_RAW) ? K_RAW :
+ vc_kbd_mode(kbd, VC_MEDIUMRAW) ? K_MEDIUMRAW :
+ K_XLATE);
+ put_fs_long(ucval, (unsigned long *) arg);
+ }
+ return i;
+
+ /* this could be folded into KDSKBMODE, but for compatibility
+ reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */
+ case KDSKBMETA:
+ switch(arg) {
+ case K_METABIT:
+ clr_vc_kbd_mode(kbd, VC_META);
+ break;
+ case K_ESCPREFIX:
+ set_vc_kbd_mode(kbd, VC_META);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+
+ case KDGKBMETA:
+ i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
+ if (!i) {
+ ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX :
+ K_METABIT);
+ put_fs_long(ucval, (unsigned long *) arg);
}
return i;
@@ -258,7 +293,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
u_char s;
u_short v;
- i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
+ i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbentry));
if (i)
return i;
if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
@@ -377,31 +412,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char));
if (i)
return i;
- ucval = 0;
- if (vc_kbd_flag(kbd, VC_SCROLLOCK))
- ucval |= LED_SCR;
- if (vc_kbd_flag(kbd, VC_NUMLOCK))
- ucval |= LED_NUM;
- if (vc_kbd_flag(kbd, VC_CAPSLOCK))
- ucval |= LED_CAP;
- put_fs_byte(ucval, (char *) arg);
+ put_fs_byte(kbd->ledstate, (char *) arg);
return 0;
case KDSETLED:
if (arg & ~7)
return -EINVAL;
- if (arg & LED_SCR)
- set_vc_kbd_flag(kbd, VC_SCROLLOCK);
- else
- clr_vc_kbd_flag(kbd, VC_SCROLLOCK);
- if (arg & LED_NUM)
- set_vc_kbd_flag(kbd, VC_NUMLOCK);
- else
- clr_vc_kbd_flag(kbd, VC_NUMLOCK);
- if (arg & LED_CAP)
- set_vc_kbd_flag(kbd, VC_CAPSLOCK);
- else
- clr_vc_kbd_flag(kbd, VC_CAPSLOCK);
+ kbd->ledstate = arg;
set_leds();
return 0;
@@ -552,6 +569,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return 0;
+ case PIO_FONT:
+ return con_set_font((char *)arg);
+ /* con_set_font() defined in console.c */
+
+ case GIO_FONT:
+ return con_get_font((char *)arg);
+ /* con_get_font() defined in console.c */
+
+ case PIO_SCRNMAP:
+ return con_set_trans((char *)arg);
+ /* con_set_trans() defined in console.c */
+
+ case GIO_SCRNMAP:
+ return con_get_trans((char *)arg);
+ /* con_get_trans() defined in console.c */
+
default:
return -EINVAL;
}
diff --git a/fs/fifo.c b/fs/fifo.c
index 50e0b8c..ecd9bc2 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -24,7 +24,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
*/
filp->f_op = &connecting_fifo_fops;
if (!PIPE_READERS(*inode)++)
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
PIPE_RD_OPENERS(*inode)++;
while (!PIPE_WRITERS(*inode)) {
@@ -35,14 +35,14 @@ static int fifo_open(struct inode * inode,struct file * filp)
interruptible_sleep_on(&PIPE_WAIT(*inode));
}
if (!--PIPE_RD_OPENERS(*inode))
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
}
while (PIPE_WR_OPENERS(*inode))
interruptible_sleep_on(&PIPE_WAIT(*inode));
if (PIPE_WRITERS(*inode))
filp->f_op = &read_fifo_fops;
if (retval && !--PIPE_READERS(*inode))
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
break;
case 2:
@@ -57,7 +57,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
}
filp->f_op = &write_fifo_fops;
if (!PIPE_WRITERS(*inode)++)
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
if (!PIPE_READERS(*inode)) {
PIPE_WR_OPENERS(*inode)++;
while (!PIPE_READERS(*inode)) {
@@ -68,12 +68,12 @@ static int fifo_open(struct inode * inode,struct file * filp)
interruptible_sleep_on(&PIPE_WAIT(*inode));
}
if (!--PIPE_WR_OPENERS(*inode))
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
}
while (PIPE_RD_OPENERS(*inode))
interruptible_sleep_on(&PIPE_WAIT(*inode));
if (retval && !--PIPE_WRITERS(*inode))
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
break;
case 3:
@@ -85,11 +85,11 @@ static int fifo_open(struct inode * inode,struct file * filp)
*/
filp->f_op = &rdwr_fifo_fops;
if (!PIPE_READERS(*inode)++)
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
while (PIPE_WR_OPENERS(*inode))
interruptible_sleep_on(&PIPE_WAIT(*inode));
if (!PIPE_WRITERS(*inode)++)
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
while (PIPE_RD_OPENERS(*inode))
interruptible_sleep_on(&PIPE_WAIT(*inode));
break;
diff --git a/fs/inode.c b/fs/inode.c
index d8437b1..0db43c9 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -12,7 +12,11 @@
#include <asm/system.h>
-static struct inode * hash_table[NR_IHASH];
+static struct inode_hash_entry {
+ struct inode * inode;
+ int updating;
+} hash_table[NR_IHASH];
+
static struct inode * first_inode;
static struct wait_queue * inode_wait = NULL;
static int nr_inodes = 0, nr_free_inodes = 0;
@@ -22,7 +26,7 @@ static inline int const hashfn(dev_t dev, unsigned int i)
return (dev ^ i) % NR_IHASH;
}
-static inline struct inode ** const hash(dev_t dev, int i)
+static inline struct inode_hash_entry * const hash(dev_t dev, int i)
{
return hash_table + hashfn(dev, i);
}
@@ -49,23 +53,23 @@ static void remove_inode_free(struct inode *inode)
void insert_inode_hash(struct inode *inode)
{
- struct inode **h;
+ struct inode_hash_entry *h;
h = hash(inode->i_dev, inode->i_ino);
- inode->i_hash_next = *h;
+ inode->i_hash_next = h->inode;
inode->i_hash_prev = NULL;
if (inode->i_hash_next)
inode->i_hash_next->i_hash_prev = inode;
- *h = inode;
+ h->inode = inode;
}
static void remove_inode_hash(struct inode *inode)
{
- struct inode **h;
+ struct inode_hash_entry *h;
h = hash(inode->i_dev, inode->i_ino);
- if (*h == inode)
- *h = inode->i_hash_next;
+ if (h->inode == inode)
+ h->inode = inode->i_hash_next;
if (inode->i_hash_next)
inode->i_hash_next->i_hash_prev = inode->i_hash_prev;
if (inode->i_hash_prev)
@@ -309,7 +313,7 @@ void iput(struct inode * inode)
return;
}
if (inode->i_pipe)
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
repeat:
if (inode->i_count>1) {
inode->i_count--;
@@ -421,39 +425,27 @@ struct inode * iget(struct super_block * sb,int nr)
struct inode * __iget(struct super_block * sb, int nr, int crossmntp)
{
- struct inode * inode, * empty;
+ static struct wait_queue * update_wait = NULL;
+ struct inode_hash_entry * h;
+ struct inode * inode;
+ struct inode * empty = NULL;
if (!sb)
panic("VFS: iget with sb==NULL");
- empty = get_empty_inode();
+ h = hash(sb->s_dev, nr);
repeat:
- inode = *(hash(sb->s_dev,nr));
- while (inode) {
- if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
- inode = inode->i_hash_next;
- continue;
- }
- wait_on_inode(inode);
- if (inode->i_dev != sb->s_dev || inode->i_ino != nr)
- goto repeat;
- if (!inode->i_count)
- nr_free_inodes--;
- inode->i_count++;
- if (crossmntp && inode->i_mount) {
- struct inode * tmp = inode->i_mount;
- iput(inode);
- inode = tmp;
- if (!inode->i_count)
- nr_free_inodes--;
- inode->i_count++;
- wait_on_inode(inode);
- }
+ for (inode = h->inode; inode ; inode = inode->i_hash_next)
+ if (inode->i_dev == sb->s_dev && inode->i_ino == nr)
+ goto found_it;
+ if (!empty) {
+ h->updating++;
+ empty = get_empty_inode();
+ if (!--h->updating)
+ wake_up(&update_wait);
if (empty)
- iput(empty);
- return inode;
- }
- if (!empty)
+ goto repeat;
return (NULL);
+ }
inode = empty;
inode->i_sb = sb;
inode->i_dev = sb->s_dev;
@@ -462,6 +454,31 @@ repeat:
put_last_free(inode);
insert_inode_hash(inode);
read_inode(inode);
+ goto return_it;
+
+found_it:
+ if (!inode->i_count)
+ nr_free_inodes--;
+ inode->i_count++;
+ wait_on_inode(inode);
+ if (inode->i_dev != sb->s_dev || inode->i_ino != nr) {
+ printk("Whee.. inode changed from under us. Tell Linus\n");
+ iput(inode);
+ goto repeat;
+ }
+ if (crossmntp && inode->i_mount) {
+ struct inode * tmp = inode->i_mount;
+ tmp->i_count++;
+ iput(inode);
+ inode = tmp;
+ wait_on_inode(inode);
+ }
+ if (empty)
+ iput(empty);
+
+return_it:
+ while (h->updating)
+ sleep_on(&update_wait);
return inode;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 2e94ba1..64784cb 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -60,7 +60,7 @@ static int pipe_read(struct inode * inode, struct file * filp, char * buf, int c
buf += chars;
}
PIPE_LOCK(*inode)--;
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
if (read)
return read;
if (PIPE_WRITERS(*inode))
@@ -109,7 +109,7 @@ static int pipe_write(struct inode * inode, struct file * filp, char * buf, int
buf += chars;
}
PIPE_LOCK(*inode)--;
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
free = 1;
}
return written;
@@ -206,7 +206,7 @@ static int connect_read(struct inode * inode, struct file * filp, char * buf, in
break;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
- wake_up(& PIPE_WAIT(*inode));
+ wake_up_interruptible(& PIPE_WAIT(*inode));
if (current->signal & ~current->blocked)
return -ERESTARTSYS;
interruptible_sleep_on(& PIPE_WAIT(*inode));
@@ -246,20 +246,20 @@ static int connect_select(struct inode * inode, struct file * filp, int sel_type
static void pipe_read_release(struct inode * inode, struct file * filp)
{
PIPE_READERS(*inode)--;
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
}
static void pipe_write_release(struct inode * inode, struct file * filp)
{
PIPE_WRITERS(*inode)--;
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
}
static void pipe_rdwr_release(struct inode * inode, struct file * filp)
{
PIPE_READERS(*inode)--;
PIPE_WRITERS(*inode)--;
- wake_up(&PIPE_WAIT(*inode));
+ wake_up_interruptible(&PIPE_WAIT(*inode));
}
/*
diff --git a/fs/proc/array.c b/fs/proc/array.c
index f25bc56..fc9c06a 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
#include <linux/tty.h>
#include <linux/user.h>
#include <linux/a.out.h>
@@ -85,6 +86,33 @@ static int get_loadavg(char * buffer)
LOAD_INT(c), LOAD_FRAC(c));
}
+static int get_kstat(char * buffer)
+{
+ return sprintf(buffer, "cpu %u,%u,%u,%lu\n"
+ "disk %u,%u,%u,%u\n"
+ "page %u,%u\n"
+ "swap %u,%u\n"
+ "intr %u\n"
+ "ctxt %u\n"
+ "btime %lu\n",
+ kstat.cpu_user,
+ kstat.cpu_nice,
+ kstat.cpu_system,
+ jiffies - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system),
+ kstat.dk_drive[0],
+ kstat.dk_drive[1],
+ kstat.dk_drive[2],
+ kstat.dk_drive[3],
+ kstat.pgpgin,
+ kstat.pgpgout,
+ kstat.pswpin,
+ kstat.pswpout,
+ kstat.interrupts,
+ kstat.context_swtch,
+ xtime.tv_sec - jiffies / HZ);
+}
+
+
static int get_uptime(char * buffer)
{
unsigned long uptime;
@@ -468,6 +496,9 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
case 16:
length = get_module_list(page);
break;
+ case 17:
+ length = get_kstat(page);
+ break;
default:
free_page((unsigned long) page);
return -EBADF;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 9d9127d..1690b43 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -66,6 +66,7 @@ static struct proc_dir_entry root_dir[] = {
#endif
{14,5,"kcore" },
{16,7,"modules" },
+ {17,4,"stat" },
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
diff --git a/fs/super.c b/fs/super.c
index e0b23bc..5232057 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -210,6 +210,7 @@ static int do_umount(dev_t dev)
if (!(sb=get_super(dev)))
return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) {
+ fsync_dev(dev);
retval = do_remount_sb(sb, MS_RDONLY, 0);
if (retval)
return retval;
diff --git a/include/linux/kd.h b/include/linux/kd.h
index d751504..c67c539 100644
--- a/include/linux/kd.h
+++ b/include/linux/kd.h
@@ -90,6 +90,9 @@ struct port_io_arg {
#define GIO_FONT8x16 0x4B2C /* gets current 8x16 font used */
#define PIO_FONT8x16 0x4B2D /* use supplied 8x16 font */
+#define GIO_FONT 0x4B60 /* gets font in expanded form */
+#define PIO_FONT 0x4B61 /* use font in expanded form */
+
#define MKDIOADDR 32 /* io bitmap size from <linux/sched.h> */
struct kd_disparam {
long type; /* type of display */
@@ -164,6 +167,12 @@ typedef char scrnmap_t;
#define KDGKBMODE 0x4B44 /* gets current keyboard mode */
#define KDSKBMODE 0x4B45 /* sets current keyboard mode */
+/* merge with previous pair of ioctls? */
+#define K_METABIT 0x03
+#define K_ESCPREFIX 0x04
+#define KDGKBMETA 0x4B62 /* gets meta key handling mode */
+#define KDSKBMETA 0x4B63 /* sets meta key handling mode */
+
struct kbentry {
u_char kb_table;
u_char kb_index;
@@ -194,4 +203,7 @@ struct kbdiacrs {
#define KDGKBDIACR 0x4B4A /* read kernel accent table */
#define KDSKBDIACR 0x4B4B /* write kernel accent table */
+/* note: 0x4B60 and 0x4B61 used above for GIO_FONT and PIO_FONT
+ 0x4B62 and 0x4B63 used above for KDGKBMETA and KDSKBMETA */
+
#endif /* _LINUX_KD_H */
diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h
index e69de29..2f3e53b 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -0,0 +1,26 @@
+#ifndef _LINUX_KERNEL_STAT_H
+#define _LINUX_KERNEL_STAT_H
+
+/*
+ * 'kernel_stat.h' contains the definitions needed for doing
+ * some kernel statistics (cpu usage, context switches ...),
+ * used by rstatd/perfmeter
+ */
+
+#define DK_NDRIVE 4
+
+struct kernel_stat {
+ unsigned int cpu_user, cpu_nice, cpu_system;
+ unsigned int dk_drive[DK_NDRIVE];
+ unsigned int pgpgin, pgpgout;
+ unsigned int pswpin, pswpout;
+ unsigned int interrupts;
+ unsigned int ipackets, opackets;
+ unsigned int ierrors, oerrors;
+ unsigned int collisions;
+ unsigned int context_swtch;
+};
+
+extern struct kernel_stat kstat;
+
+#endif /* _LINUX_KERNEL_STAT_H */
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 9b34bcd..b956435 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -1,63 +1,10 @@
#ifndef __LINUX_KEYBOARD_H
#define __LINUX_KEYBOARD_H
-#include <linux/interrupt.h>
-#define set_leds() mark_bh(KEYBOARD_BH)
-
-/*
- * kbd->xxx contains the VC-local things (flag settings etc..)
- * The low 3 local flags are hardcoded to be the led setting..
- */
-struct kbd_struct {
- unsigned long flags;
- unsigned long default_flags;
-};
-
-extern struct kbd_struct kbd_table[];
-
-/*
- * These are the local "softflags", giving actual keyboard modes. The
- * three first flags are coded to the led settings.
- */
-#define VC_SCROLLOCK 0 /* scroll-lock mode */
-#define VC_NUMLOCK 1 /* numeric lock mode */
-#define VC_CAPSLOCK 2 /* capslock mode */
-#define VC_APPLIC 3 /* application key mode */
-#define VC_CKMODE 5 /* cursor key mode */
-#define VC_REPEAT 6 /* keyboard repeat */
-#define VC_RAW 7 /* raw (scancode) mode */
-#define VC_CRLF 8 /* 0 - enter sends CR, 1 - enter sends CRLF */
-#define VC_META 9 /* 0 - meta, 1 - meta=prefix with ESC */
-#define VC_PAUSE 10 /* pause key pressed */
-#define VC_MEDIUMRAW 11 /* medium raw (keycode) mode */
-#define VC_SHIFTLOCK 12 /* shift lock mode */
-#define VC_ALTGRLOCK 13 /* altgr lock mode */
-#define VC_CTRLLOCK 14 /* control lock mode */
-#define VC_ALTLOCK 15 /* alt lock mode */
-
-#define LED_MASK 7
-
-extern unsigned long kbd_init(unsigned long);
-
-extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag)
-{
- return ((kbd->flags >> flag) & 1);
-}
-
-extern inline void set_vc_kbd_flag(struct kbd_struct * kbd, int flag)
-{
- kbd->flags |= 1 << flag;
-}
-
-extern inline void clr_vc_kbd_flag(struct kbd_struct * kbd, int flag)
-{
- kbd->flags &= ~(1 << flag);
-}
-
-extern inline void chg_vc_kbd_flag(struct kbd_struct * kbd, int flag)
-{
- kbd->flags ^= 1 << flag;
-}
+#define KG_SHIFT 0
+#define KG_CTRL 2
+#define KG_ALT 3
+#define KG_ALTGR 1
#define NR_KEYS 128
#define NR_KEYMAPS 16
@@ -71,6 +18,7 @@ extern char func_buf[FUNC_BUFSIZE];
extern char *func_table[NR_FUNC];
#define KT_LATIN 0 /* we depend on this being zero */
+#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */
#define KT_FN 1
#define KT_SPEC 2
#define KT_PAD 3
@@ -163,11 +111,6 @@ extern char *func_table[NR_FUNC];
#define K_RIGHT K(KT_CUR,2)
#define K_UP K(KT_CUR,3)
-#define KG_SHIFT 0
-#define KG_CTRL 2
-#define KG_ALT 3
-#define KG_ALTGR 1
-
#define K_SHIFT K(KT_SHIFT,KG_SHIFT)
#define K_CTRL K(KT_SHIFT,KG_CTRL)
#define K_ALT K(KT_SHIFT,KG_ALT)
@@ -188,10 +131,10 @@ extern char *func_table[NR_FUNC];
#define K_ASC8 K(KT_ASCII,8)
#define K_ASC9 K(KT_ASCII,9)
-#define K_SHIFTLOCK K(KT_LOCK,0)
-#define K_CTRLLOCK K(KT_LOCK,2)
-#define K_ALTLOCK K(KT_LOCK,3)
-#define K_ALTGRLOCK K(KT_LOCK,1)
+#define K_SHIFTLOCK K(KT_LOCK,KG_SHIFT)
+#define K_CTRLLOCK K(KT_LOCK,KG_CTRL)
+#define K_ALTLOCK K(KT_LOCK,KG_ALT)
+#define K_ALTGRLOCK K(KT_LOCK,KG_ALTGR)
#define MAX_DIACR 256
#endif
diff --git a/include/linux/sys.h b/include/linux/sys.h
index cb51d7b..2f4b029 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -144,6 +144,7 @@ extern int sys_get_kernel_syms(); /* 130 */
extern int sys_quotactl();
extern int sys_getpgid();
extern int sys_fchdir();
+extern int sys_bdflush();
/*
* These are system calls that will be removed at some time
@@ -167,6 +168,7 @@ extern int sys_fchdir();
*/
#define sys_quotactl sys_ni_syscall
+#define sys_bdflush sys_ni_syscall
typedef int (*fn_ptr)();
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 1fcb100..bf4b390 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -89,6 +89,7 @@ struct timex {
* (read only)
*/
struct timeval time; /* (read only) */
+ long tick; /* (modified) usecs between clock ticks */
};
/*
@@ -100,6 +101,7 @@ struct timex {
#define ADJ_ESTERROR 0x0008 /* estimated time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
+#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
/*
diff --git a/include/linux/unistd.h b/include/linux/unistd.h
index 36f4882..c499a13 100644
--- a/include/linux/unistd.h
+++ b/include/linux/unistd.h
@@ -140,6 +140,7 @@
#define __NR_quotactl 131
#define __NR_getpgid 132
#define __NR_fchdir 133
+#define __NR_bdflush 134
extern int errno;
diff --git a/kernel/irq.c b/kernel/irq.c
index 0fc155e..e38d9e8 100644
--- a/kernel/irq.c
+++ b/kernel/irq.c
@@ -24,6 +24,7 @@
#include <linux/ptrace.h>
#include <linux/errno.h>
+#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -200,6 +201,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
struct sigaction * sa = irq + irq_sigaction;
+ kstat.interrupts++;
sa->sa_handler((int) regs);
}
@@ -212,6 +214,7 @@ asmlinkage void do_fast_IRQ(int irq)
{
struct sigaction * sa = irq + irq_sigaction;
+ kstat.interrupts++;
sa->sa_handler(irq);
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 5374207..6d94afd 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -16,6 +16,7 @@
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
#include <linux/sys.h>
#include <linux/fdreg.h>
#include <linux/errno.h>
@@ -56,6 +57,7 @@ long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
long time_reftime = 0; /* time at last adjustment (s) */
long time_adjust = 0;
+long time_adjust_step = 0;
int need_resched = 0;
@@ -100,6 +102,9 @@ struct {
short b;
} stack_start = { & user_stack [PAGE_SIZE>>2] , KERNEL_DS };
+struct kernel_stat kstat =
+ { 0, 0, 0, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
/*
* int 0x80 entry points.. Moved away from the header file, as
* iBCS2 may also want to use the '<linux/sys.h>' headers..
@@ -138,7 +143,7 @@ sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt,
sys_adjtimex, sys_mprotect, sys_sigprocmask, sys_create_module,
sys_init_module, sys_delete_module, sys_get_kernel_syms, sys_quotactl,
-sys_getpgid, sys_fchdir };
+sys_getpgid, sys_fchdir, sys_bdflush };
/* So we don't have to do any more manual updating.... */
int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
@@ -275,6 +280,8 @@ confuse_gcc2:
for_each_task(p)
p->counter = (p->counter >> 1) + p->priority;
}
+ if(current != next)
+ kstat.context_swtch++;
switch_to(next);
/* Now maybe reload the debug registers */
if(current->debugreg[7]){
@@ -592,41 +599,38 @@ static void do_timer(struct pt_regs * regs)
if (time_phase < -FINEUSEC) {
ltemp = -time_phase >> SHIFT_SCALE;
time_phase += ltemp << SHIFT_SCALE;
- xtime.tv_usec += tick - ltemp;
+ xtime.tv_usec += tick + time_adjust_step - ltemp;
}
else if (time_phase > FINEUSEC) {
ltemp = time_phase >> SHIFT_SCALE;
time_phase -= ltemp << SHIFT_SCALE;
- xtime.tv_usec += tick + ltemp;
+ xtime.tv_usec += tick + time_adjust_step + ltemp;
} else
- xtime.tv_usec += tick;
+ xtime.tv_usec += tick + time_adjust_step;
if (time_adjust)
{
/* We are doing an adjtime thing.
- */
-
- /* Limit the amount of the step for *next* tick to be
+ *
+ * Modify the value of the tick for next time.
+ * Note that a positive delta means we want the clock
+ * to run fast. This means that the tick should be bigger
+ *
+ * Limit the amount of the step for *next* tick to be
* in the range -tickadj .. +tickadj
*/
if (time_adjust > tickadj)
- ltemp = tickadj;
+ time_adjust_step = tickadj;
else if (time_adjust < -tickadj)
- ltemp = -tickadj;
+ time_adjust_step = -tickadj;
else
- ltemp = time_adjust;
+ time_adjust_step = time_adjust;
- /* Reduce the amount of time left by this step */
- time_adjust -= ltemp;
-
- /* Modify the value of the tick for next time.
- * Note that a positive delta means we want the clock
- * to run fast. This means that the tick should be bigger
- */
- tick = 1000000/HZ + ltemp;
+ /* Reduce by this step the amount of time left */
+ time_adjust -= time_adjust_step;
}
else
- tick = 1000000/HZ;
+ time_adjust_step = 0;
if (xtime.tv_usec >= 1000000) {
xtime.tv_usec -= 1000000;
@@ -638,6 +642,12 @@ static void do_timer(struct pt_regs * regs)
calc_load();
if ((VM_MASK & regs->eflags) || (3 & regs->cs)) {
current->utime++;
+ if(current != task[0]) {
+ if(current->priority != 15)
+ kstat.cpu_nice++;
+ else
+ kstat.cpu_user++;
+ }
/* Update ITIMER_VIRT for current task if not in a system call */
if (current->it_virt_value && !(--current->it_virt_value)) {
current->it_virt_value = current->it_virt_incr;
@@ -645,6 +655,8 @@ static void do_timer(struct pt_regs * regs)
}
} else {
current->stime++;
+ if(current != task[0])
+ kstat.cpu_system++;
#ifdef CONFIG_PROFILE
if (prof_buffer && current != task[0]) {
unsigned long eip = regs->eip;
diff --git a/kernel/time.c b/kernel/time.c
index 0542096..3161e8f 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -321,6 +321,11 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
if (txc.status < TIME_OK || txc.status > TIME_BAD)
return -EINVAL;
+ /* if the quartz is off by more than 10% something is VERY wrong ! */
+ if (txc.mode & ADJ_TICK)
+ if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
+ return -EINVAL;
+
cli();
/* Save for later - semantics of adjtime is to return old value */
@@ -336,7 +341,7 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
time_status = txc.status;
if (txc.mode & ADJ_FREQUENCY)
- time_freq = txc.frequency;
+ time_freq = txc.frequency << (SHIFT_KF - 16);
if (txc.mode & ADJ_MAXERROR)
time_maxerror = txc.maxerror;
@@ -374,9 +379,12 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
else if (time_freq < -ltemp)
time_freq = -ltemp;
}
+ if (txc.mode & ADJ_TICK)
+ tick = txc.tick;
+
}
txc.offset = save_adjust;
- txc.frequency = time_freq;
+ txc.frequency = ((time_freq+1) >> (SHIFT_KF - 16));
txc.maxerror = time_maxerror;
txc.esterror = time_esterror;
txc.status = time_status;
@@ -384,6 +392,7 @@ asmlinkage int sys_adjtimex(struct timex *txc_p)
txc.precision = time_precision;
txc.tolerance = time_tolerance;
txc.time = xtime;
+ txc.tick = tick;
sti();
diff --git a/mm/swap.c b/mm/swap.c
index 8adc9eb..885abf1 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/head.h>
#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
@@ -76,6 +77,10 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
}
while (set_bit(offset,p->swap_lockmap))
sleep_on(&lock_queue);
+ if (rw == READ)
+ kstat.pswpin++;
+ else
+ kstat.pswpout++;
if (p->swap_device) {
ll_rw_page(rw,p->swap_device,offset,buf);
} else if (p->swap_file) {
diff --git a/net/inet/packet.c b/net/inet/packet.c
index e85edec..c81209a 100644
--- a/net/inet/packet.c
+++ b/net/inet/packet.c
@@ -74,7 +74,7 @@ packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
}
sk->rmem_alloc += skb->mem_len;
skb_queue_tail(&sk->rqueue,skb);
- wake_up(sk->sleep);
+ wake_up_interruptible(sk->sleep);
release_sock(sk);
return(0);
}
diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c
index 506e95d..68f7f36 100644
--- a/net/inet/skbuff.c
+++ b/net/inet/skbuff.c
@@ -410,7 +410,7 @@ void kfree_skb(struct sk_buff *skb, int rw)
else
skb->sk->wmem_alloc-=skb->mem_len;
if(!skb->sk->dead)
- wake_up(skb->sk->sleep);
+ wake_up_interruptible(skb->sk->sleep);
kfree_skbmem(skb->mem_addr,skb->mem_len);
}
}
@@ -471,11 +471,11 @@ void skb_kept_by_device(struct sk_buff *skb)
void skb_device_release(struct sk_buff *skb, int mode)
{
unsigned long flags;
+
save_flags(flags);
- skb->lock--;
- if(skb->lock==0)
- {
- if(skb->free==1)
+ cli();
+ if (!--skb->lock) {
+ if (skb->free==1)
kfree_skb(skb,mode);
}
restore_flags(flags);
diff --git a/net/inet/sock.c b/net/inet/sock.c
index 37efd6f..643361d 100644
--- a/net/inet/sock.c
+++ b/net/inet/sock.c
@@ -741,13 +741,13 @@ inet_listen(struct socket *sock, int backlog)
static void def_callback1(struct sock *sk)
{
if(!sk->dead)
- wake_up(sk->sleep);
+ wake_up_interruptible(sk->sleep);
}
static void def_callback2(struct sock *sk,int len)
{
if(!sk->dead)
- wake_up(sk->sleep);
+ wake_up_interruptible(sk->sleep);
}
@@ -870,7 +870,7 @@ inet_create(struct socket *sock, int protocol)
sk->dead = 0;
sk->ack_timed = 0;
sk->send_tmp = NULL;
- sk->mss = 0; /* we will try not to send any packets smaller than this. */
+ sk->user_mss = 0;
sk->debug = 0;
/* this is how many unacked bytes we will accept for this socket. */
diff --git a/net/inet/sock.h b/net/inet/sock.h
index ee6fb0e..2133f4d 100644
--- a/net/inet/sock.h
+++ b/net/inet/sock.h
@@ -101,8 +101,11 @@ struct sock {
unsigned short max_unacked;
unsigned short window;
unsigned short bytes_rcv;
- unsigned short mtu;
- unsigned short max_window;
+/* mss is min(mtu, max_window) */
+ unsigned short mtu; /* mss negotiated in the syn's */
+ volatile unsigned short mss; /* current eff. mss - can change */
+ volatile unsigned short user_mss; /* mss requested by user in ioctl */
+ volatile unsigned short max_window;
unsigned short num;
volatile unsigned short cong_window;
volatile unsigned short cong_count;
@@ -110,7 +113,6 @@ struct sock {
volatile unsigned short packets_out;
volatile unsigned short urg;
volatile unsigned short shutdown;
- unsigned short mss;
volatile unsigned long rtt;
volatile unsigned long mdev;
volatile unsigned long rto;
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 9c1223b..b0d6074 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -103,7 +103,7 @@
#define SEQ_TICK 3
unsigned long seq_offset;
-#define LOCALNET_BIGPACKETS
+#define SUBNETSARELOCAL
static __inline__ int
min(unsigned int a, unsigned int b)
@@ -180,14 +180,14 @@ static int tcp_select_window(struct sock *sk)
/*
* two things are going on here. First, we don't ever offer a
- * window less than min(sk->mtu, MAX_WINDOW/2). This is the
+ * window less than min(sk->mss, MAX_WINDOW/2). This is the
* receiver side of SWS as specified in RFC1122.
* Second, we always give them at least the window they
* had before, in order to avoid retracting window. This
* is technically allowed, but RFC1122 advises against it and
* in practice it causes trouble.
*/
- if (new_window < min(sk->mtu, MAX_WINDOW/2) ||
+ if (new_window < min(sk->mss, MAX_WINDOW/2) ||
new_window < sk->window)
return(sk->window);
return(new_window);
@@ -420,7 +420,7 @@ tcp_select(struct sock *sk, int sel_type, select_table *wait)
* Hack so it will probably be able to write
* something if it says it's ok to write.
*/
- if (sk->prot->wspace(sk) >= sk->mtu) {
+ if (sk->prot->wspace(sk) >= sk->mss) {
release_sock(sk);
/* This should cause connect to work ok. */
if (sk->state == TCP_SYN_RECV ||
@@ -656,10 +656,7 @@ static struct sk_buff * dequeue_partial(struct sock * sk)
save_flags(flags);
cli();
skb = sk->send_tmp;
- if (skb) {
- sk->send_tmp = skb->next;
- skb->next = NULL;
- }
+ sk->send_tmp = NULL;
restore_flags(flags);
return skb;
}
@@ -669,7 +666,6 @@ static void enqueue_partial(struct sk_buff * skb, struct sock * sk)
struct sk_buff * tmp;
unsigned long flags;
- skb->next = NULL;
save_flags(flags);
cli();
tmp = sk->send_tmp;
@@ -888,6 +884,18 @@ tcp_write(struct sock *sk, unsigned char *from,
sti();
}
+/*
+ * The following code can result in copy <= if sk->mss is ever
+ * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window).
+ * sk->mtu is constant once SYN processing is finished. I.e. we
+ * had better not get here until we've seen his SYN and at least one
+ * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.)
+ * But ESTABLISHED should guarantee that. sk->max_window is by definition
+ * non-decreasing. Note that any ioctl to set user_mss must be done
+ * before the exchange of SYN's. If the initial ack from the other
+ * end has a window of 0, max_window and thus mss will both be 0.
+ */
+
/* Now we need to check if we have a half built packet. */
if ((skb = dequeue_partial(sk)) != NULL) {
int hdrlen;
@@ -896,11 +904,9 @@ tcp_write(struct sock *sk, unsigned char *from,
hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data)
+ sizeof(struct tcphdr);
- /* If sk->mtu has been changed this could cause problems. */
-
/* Add more stuff to the end of skb->len */
if (!(flags & MSG_OOB)) {
- copy = min(sk->mtu - (skb->len - hdrlen), len);
+ copy = min(sk->mss - (skb->len - hdrlen), len);
/* FIXME: this is really a bug. */
if (copy <= 0) {
printk("TCP: **bug**: \"copy\" <= 0!!\n");
@@ -915,7 +921,7 @@ tcp_write(struct sock *sk, unsigned char *from,
sk->send_seq += copy;
}
enqueue_partial(skb, sk);
- if ((skb->len - hdrlen) >= sk->mtu || (flags & MSG_OOB)) {
+ if ((skb->len - hdrlen) >= sk->mss || (flags & MSG_OOB)) {
tcp_send_partial(sk);
}
continue;
@@ -928,24 +934,26 @@ tcp_write(struct sock *sk, unsigned char *from,
* silly window prevention, as specified in RFC1122.
* (Note that this is diffferent than earlier versions of
* SWS prevention, e.g. RFC813.). What we actually do is
- * use the whole MTU. Since the results in the right
+ * use the whole MSS. Since the results in the right
* edge of the packet being outside the window, it will
* be queued for later rather than sent.
*/
copy = diff(sk->window_seq, sk->send_seq);
- if (sk->max_window > 1) {
- if (copy < (sk->max_window >> 1))
- copy = sk->mtu;
- } else /* no max_window yet, punt this test */
- copy = sk->mtu;
- copy = min(copy, sk->mtu);
+ /* what if max_window == 1? In that case max_window >> 1 is 0.
+ * however in that case copy == max_window, so it's OK to use
+ * the window */
+ if (copy < (sk->max_window >> 1))
+ copy = sk->mss;
+ copy = min(copy, sk->mss);
copy = min(copy, len);
/* We should really check the window here also. */
- if (sk->packets_out && copy < sk->mtu && !(flags & MSG_OOB)) {
+ if (sk->packets_out && copy < sk->mss && !(flags & MSG_OOB)) {
/* We will release the socket incase we sleep here. */
release_sock(sk);
+ /* NB: following must be mtu, because mss can be increased.
+ * mss is always <= mtu */
skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header + sizeof(*skb), 0, GFP_KERNEL);
sk->inuse = 1;
send_tmp = skb;
@@ -1204,6 +1212,14 @@ cleanup_rbuf(struct sock *sk)
* the user reads some more.
*/
sk->ack_backlog++;
+/*
+ * It's unclear whether to use sk->mtu or sk->mss here. They differ only
+ * if the other end is offering a window smaller than the agreed on MSS
+ * (called sk->mtu here). In theory there's no connection between send
+ * and receive, and so no reason to think that they're going to send
+ * small packets. For the moment I'm using the hack of reducing the mss
+ * only on the send side, so I'm putting mtu here.
+ */
if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) {
/* Send an ack right now. */
tcp_read_wakeup(sk);
@@ -1741,7 +1757,11 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
/*
- * Look for tcp options. Parses everything but only knows about MSS
+ * Look for tcp options. Parses everything but only knows about MSS.
+ * This routine is always called with the packet containing the SYN.
+ * However it may also be called with the ack to the SYN. So you
+ * can't assume this is always the SYN. It's always called after
+ * we have set up sk->mtu to our own MTU.
*/
static void
@@ -1749,6 +1769,7 @@ tcp_options(struct sock *sk, struct tcphdr *th)
{
unsigned char *ptr;
int length=(th->doff*4)-sizeof(struct tcphdr);
+ int mss_seen = 0;
ptr = (unsigned char *)(th + 1);
@@ -1770,9 +1791,10 @@ tcp_options(struct sock *sk, struct tcphdr *th)
switch(opcode)
{
case TCPOPT_MSS:
- if(opsize==4)
+ if(opsize==4 && th->syn)
{
sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
+ mss_seen = 1;
}
break;
/* Add other options here as people feel the urge to implement stuff like large windows */
@@ -1781,7 +1803,11 @@ tcp_options(struct sock *sk, struct tcphdr *th)
length-=opsize;
}
}
-
+ if (th->syn) {
+ if (! mss_seen)
+ sk->mtu=min(sk->mtu, 536); /* default MSS if none sent */
+ }
+ sk->mss = min(sk->max_window, sk->mtu);
}
static inline unsigned long default_mask(unsigned long dst)
@@ -1888,6 +1914,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->state = TCP_SYN_RECV;
newsk->timeout = 0;
newsk->send_seq = jiffies * SEQ_TICK - seq_offset;
+ newsk->window_seq = newsk->send_seq;
newsk->rcv_ack_seq = newsk->send_seq;
newsk->urg =0;
newsk->retransmits = 0;
@@ -1919,16 +1946,18 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
newsk->ip_tos=skb->ip_hdr->tos;
/* use 512 or whatever user asked for */
-/* note use of sk->mss, since user has no direct access to newsk */
- if (sk->mss)
- newsk->mtu = sk->mss;
+/* note use of sk->user_mss, since user has no direct access to newsk */
+ if (sk->user_mss)
+ newsk->mtu = sk->user_mss;
else {
-#ifdef LOCALNET_BIGPACKETS
- if ((saddr & default_mask(saddr)) == (daddr & default_mask(daddr)))
- newsk->mtu = MAX_WINDOW;
- else
+#ifdef SUBNETSARELOCAL
+ if ((saddr ^ daddr) & default_mask(saddr))
+#else
+ if ((saddr ^ daddr) & dev->pa_mask)
#endif
newsk->mtu = 576 - HEADER_SIZE;
+ else
+ newsk->mtu = MAX_WINDOW;
}
/* but not bigger than device MTU */
newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE);
@@ -2261,8 +2290,10 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
"sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq));
- if (ntohs(th->window) > sk->max_window)
+ if (ntohs(th->window) > sk->max_window) {
sk->max_window = ntohs(th->window);
+ sk->mss = min(sk->max_window, sk->mtu);
+ }
if (sk->retransmits && sk->timeout == TIME_KEEPOPEN)
sk->retransmits = 0;
@@ -2804,7 +2835,8 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
/*
* This is important. If we don't have much room left,
* we need to throw out a few packets so we have a good
- * window.
+ * window. Note that mtu is used, not mss, because mss is really
+ * for the send side. He could be sending us stuff as large as mtu.
*/
while (sk->prot->rspace(sk) < sk->mtu) {
skb1 = skb_peek(&sk->rqueue);
@@ -3026,6 +3058,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
sk->inuse = 1;
sk->daddr = sin.sin_addr.s_addr;
sk->send_seq = jiffies * SEQ_TICK - seq_offset;
+ sk->window_seq = sk->send_seq;
sk->rcv_ack_seq = sk->send_seq -1;
sk->err = 0;
sk->dummy_th.dest = sin.sin_port;
@@ -3070,16 +3103,17 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
t1->doff = 6;
/* use 512 or whatever user asked for */
- if (sk->mss)
- sk->mtu = sk->mss;
+ if (sk->user_mss)
+ sk->mtu = sk->user_mss;
else {
-#ifdef LOCALNET_BIGPACKETS
- if ((sk->saddr & default_mask(sk->saddr)) ==
- (sk->daddr & default_mask(sk->daddr)))
- sk->mtu = MAX_WINDOW;
- else
+#ifdef SUBNETSARELOCAL
+ if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr))
+#else
+ if ((sk->saddr ^ sk->daddr) & dev->pa_mask)
#endif
sk->mtu = 576 - HEADER_SIZE;
+ else
+ sk->mtu = MAX_WINDOW;
}
/* but not bigger than device MTU */
sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE);
@@ -3487,7 +3521,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
sk->shutdown = SHUTDOWN_MASK;
tcp_reset(daddr, saddr, th, sk->prot, opt, dev);
if (!sk->dead) {
- wake_up(sk->sleep);
+ wake_up_interruptible(sk->sleep);
}
kfree_skb(skb, FREE_READ);
release_sock(sk);
@@ -3553,6 +3587,20 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
}
/*
+ * We've already processed his first
+ * ack. In just about all cases that
+ * will have set max_window. This is
+ * to protect us against the possibility
+ * that the initial window he sent was 0.
+ * This must occur after tcp_options, which
+ * sets sk->mtu.
+ */
+ if (sk->max_window == 0) {
+ sk->max_window = 32;
+ sk->mss = min(sk->max_window, sk->mtu);
+ }
+
+ /*
* Now process the rest like we were
* already in the established state.
*/
@@ -3775,9 +3823,15 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int op
switch(optname)
{
case TCP_MAXSEG:
- if(val<200||val>2048 || val>sk->mtu)
+/* if(val<200||val>2048 || val>sk->mtu) */
+/*
+ * values greater than interface MTU won't take effect. however at
+ * the point when this call is done we typically don't yet know
+ * which interface is going to be used
+ */
+ if(val<1||val>MAX_WINDOW)
return -EINVAL;
- sk->mss=val;
+ sk->user_mss=val;
return 0;
case TCP_NODELAY:
sk->nonagle=(val==0)?0:1;
@@ -3797,7 +3851,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *o
switch(optname)
{
case TCP_MAXSEG:
- val=sk->mss;
+ val=sk->user_mss;
break;
case TCP_NODELAY:
val=sk->nonagle; /* Until Johannes stuff is in */
diff --git a/net/inet/tcp.h b/net/inet/tcp.h
index 7c83fbd..bc95256 100644
--- a/net/inet/tcp.h
+++ b/net/inet/tcp.h
@@ -41,7 +41,7 @@
* 90 minutes to time out.
*/
-#define TCP_TIMEOUT_LEN (5*60*HZ)/* should be about 5 mins */
+#define TCP_TIMEOUT_LEN (15*60*HZ) /* should be about 15 mins */
#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to sucessfully
* close the socket, about 60 seconds */
#define TCP_ACK_TIME 3000 /* time to delay before sending an ACK */
diff --git a/net/inet/timer.c b/net/inet/timer.c
index 73d4b24..4cd4515 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -101,14 +101,20 @@ net_timer (unsigned long data)
sk->inuse = 1;
DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why));
- if (sk->keepopen)
+ if (sk->wfront &&
+ before(sk->window_seq, sk->wfront->h.seq) &&
+ sk->send_head == NULL &&
+ sk->ack_backlog == 0 &&
+ sk->state != TCP_TIME_WAIT)
+ reset_timer(sk, TIME_PROBE0, sk->rto);
+ else if (sk->keepopen)
reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN);
/* Always see if we need to send an ack. */
if (sk->ack_backlog) {
sk->prot->read_wakeup (sk);
if (! sk->dead)
- wake_up (sk->sleep);
+ wake_up_interruptible (sk->sleep);
}
/* Now we need to figure out why the socket was on the timer. */
@@ -143,7 +149,7 @@ net_timer (unsigned long data)
/* Kill the ARP entry in case the hardware has changed. */
arp_destroy_maybe (sk->daddr);
if (!sk->dead)
- wake_up (sk->sleep);
+ wake_up_interruptible (sk->sleep);
sk->shutdown = SHUTDOWN_MASK;
reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME);
release_sock (sk);
@@ -213,7 +219,7 @@ net_timer (unsigned long data)
if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) {
sk->state = TCP_TIME_WAIT;
if (!sk->dead)
- wake_up (sk->sleep);
+ wake_up_interruptible (sk->sleep);
release_sock (sk);
} else {
sk->prot->close (sk, 1);
diff --git a/net/socket.c b/net/socket.c
index 6caa65b..805e7c6 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -222,7 +222,7 @@ static inline void
sock_release_peer(struct socket *peer)
{
peer->state = SS_DISCONNECTING;
- wake_up(peer->wait);
+ wake_up_interruptible(peer->wait);
}
@@ -253,7 +253,7 @@ sock_release(struct socket *sock)
if (peersock) sock_release_peer(peersock);
inode = SOCK_INODE(sock);
sock->state = SS_FREE; /* this really releases us */
- wake_up(&socket_wait_free);
+ wake_up_interruptible(&socket_wait_free);
/* We need to do this. If sock alloc was called we already have an inode. */
iput(inode);
@@ -391,7 +391,7 @@ sock_awaitconn(struct socket *mysock, struct socket *servsock)
* Wake up server, then await connection. server will set state to
* SS_CONNECTED if we're connected.
*/
- wake_up(servsock->wait);
+ wake_up_interruptible(servsock->wait);
if (mysock->state != SS_CONNECTED) {
interruptible_sleep_on(mysock->wait);
if (mysock->state != SS_CONNECTED &&
diff --git a/net/unix/sock.c b/net/unix/sock.c
index dff2bbe..6ab4e83 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -554,7 +554,7 @@ unix_proto_accept(struct socket *sock, struct socket *newsock, int flags)
UN_DATA(newsock)->peerupd = UN_DATA(clientsock);
UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un;
UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len;
- wake_up(clientsock->wait);
+ wake_up_interruptible(clientsock->wait);
return(0);
}
@@ -646,7 +646,8 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1);
ubuf += cando;
todo -= cando;
- if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
+ if (sock->state == SS_CONNECTED)
+ wake_up_interruptible(sock->conn->wait);
avail = UN_BUF_AVAIL(upd);
} while(todo && avail);
unix_unlock(upd);
@@ -731,7 +732,8 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1);
ubuf += cando;
todo -= cando;
- if (sock->state == SS_CONNECTED) wake_up(sock->conn->wait);
+ if (sock->state == SS_CONNECTED)
+ wake_up_interruptible(sock->conn->wait);
space = UN_BUF_SPACE(pupd);
} while(todo && space);
unix_unlock(pupd);