diff options
author | Linus Torvalds <torvalds@cc.helsinki.fi> | 1994-02-02 06:45:07 +0000 |
---|---|---|
committer | Nicolas Pitre <nico@cam.org> | 2007-08-19 14:19:30 -0400 |
commit | 3cfe2636ea6f3283638c0e8c14f47d7d620f072d (patch) | |
tree | d087626ffe85d00b68fd8676fc66184829a80ce3 | |
parent | 0ef15e52af53204c01d894863c7bd1bf2ee86cd6 (diff) | |
download | archive-3cfe2636ea6f3283638c0e8c14f47d7d620f072d.tar.gz |
ALPHA-pl14y
37 files changed, 1051 insertions, 404 deletions
@@ -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; } @@ -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; @@ -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; } @@ -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]))) @@ -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(); @@ -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); |