Commit 24a1c2a7 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.92

parent 55415e93
VERSION = 1 VERSION = 1
PATCHLEVEL = 1 PATCHLEVEL = 1
SUBLEVEL = 91 SUBLEVEL = 92
ARCH = i386 ARCH = i386
...@@ -198,7 +198,7 @@ ifdef CONFIG_MODVERSIONS ...@@ -198,7 +198,7 @@ ifdef CONFIG_MODVERSIONS
MODV = -DCONFIG_MODVERSIONS MODV = -DCONFIG_MODVERSIONS
endif endif
modules: dummy modules: include/linux/version.h
@set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE $(MODV)" modules; done @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i CFLAGS="$(CFLAGS) -DMODULE $(MODV)" modules; done
modules_install: modules_install:
......
...@@ -199,11 +199,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y ...@@ -199,11 +199,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
fi fi
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
bool 'VESA Power Saving Protocol Support' CONFIG_VESA_PSPM n
if [ "$CONFIG_VESA_PSPM" = "y" ]; then
bool 'VESA PSPM Force Off' CONFIG_PSPM_FORCE_OFF n
fi
bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
......
...@@ -10,7 +10,7 @@ bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y ...@@ -10,7 +10,7 @@ bool 'Normal floppy disk support' CONFIG_BLK_DEV_FD y
bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 y bool 'Normal (MFM/RLL) disk and IDE disk/cdrom support' CONFIG_ST506 y
if [ "$CONFIG_ST506" = "y" ]; then if [ "$CONFIG_ST506" = "y" ]; then
comment 'Please see drivers/block/README.ide for help/info on IDE drives' comment 'Please see drivers/block/README.ide for help/info on IDE drives'
bool ' Use old (reliable) disk-only driver for primary i/f' CONFIG_BLK_DEV_HD y bool ' Use old disk-only driver for primary i/f' CONFIG_BLK_DEV_HD n
if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then if [ "$CONFIG_BLK_DEV_HD" = "y" ]; then
bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n bool ' Include new IDE driver for secondary i/f support' CONFIG_BLK_DEV_IDE n
else else
...@@ -229,7 +229,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y ...@@ -229,7 +229,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
fi fi
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
......
...@@ -219,7 +219,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE n ...@@ -219,7 +219,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE n
fi fi
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
if [ "$CONFIG_QIC02_TAPE" = "y" ]; then if [ "$CONFIG_QIC02_TAPE" = "y" ]; then
......
...@@ -206,11 +206,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y ...@@ -206,11 +206,6 @@ bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y
fi fi
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
bool 'VESA Power Saving Protocol Support' CONFIG_VESA_PSPM n
if [ "$CONFIG_VESA_PSPM" = "y" ]; then
bool 'VESA PSPM Force Off' CONFIG_PSPM_FORCE_OFF n
fi
bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n bool 'QIC-02 tape support' CONFIG_QIC02_TAPE n
......
...@@ -45,7 +45,7 @@ NOTES: ...@@ -45,7 +45,7 @@ NOTES:
====== ======
1) The drive MUST be turned on when booting or it will not be recognized! 1) The drive MUST be turned on when booting or it will not be recognized!
(but see comments on modulized version below) (but see comments on modularized version below)
2) when the cdrom device is opened the eject button is disabled to keep the 2) when the cdrom device is opened the eject button is disabled to keep the
user from ejecting a mounted disk and replacing it with another. user from ejecting a mounted disk and replacing it with another.
...@@ -60,8 +60,13 @@ THANKS ...@@ -60,8 +60,13 @@ THANKS
Many thanks to Ron Jeppesen (ronj.an@site007.saic.com) for getting Many thanks to Ron Jeppesen (ronj.an@site007.saic.com) for getting
this project off the ground. He wrote the initial release and this project off the ground. He wrote the initial release and
the first two patches to this driver (0.1, 0.2, and 0.3). the first two patches to this driver (0.1, 0.2, and 0.3).
Thanks also to Eberhard Moenkeberg (emoenke@gwdg.de) for prodding
me to place this code into the mainstream Linux source tree (as
of Linux version 1.1.91), as well as some patches to make it a
better device citizen. Further thanks to "S. Joel Katz"
<stimpson@panix.com> for his MODULE patches (see details below).
(aknowlegements from Ron Jeppesen in the 0.3 release:) (Acknowledgments from Ron Jeppesen in the 0.3 release:)
Thanks to Corey Minyard who wrote the original CDU-31A driver on which Thanks to Corey Minyard who wrote the original CDU-31A driver on which
this driver is based. Thanks to Ken Pizzini and Bob Blair who provided this driver is based. Thanks to Ken Pizzini and Bob Blair who provided
patches and feedback on the first release of this driver. patches and feedback on the first release of this driver.
...@@ -89,7 +94,7 @@ rmmod sony535 ...@@ -89,7 +94,7 @@ rmmod sony535
to if MODULE is not defined. That means your patched file should behave to if MODULE is not defined. That means your patched file should behave
exactly as it used to if compiled into the kernel. exactly as it used to if compiled into the kernel.
I have an externel drive, and I usually leave it powered off. I used I have an external drive, and I usually leave it powered off. I used
to have to reboot if I needed to use the CDROM drive. Now I don't. to have to reboot if I needed to use the CDROM drive. Now I don't.
Even if you have an internal drive, why waste the 268K of memory Even if you have an internal drive, why waste the 268K of memory
......
...@@ -399,9 +399,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) ...@@ -399,9 +399,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
int correct_size; int correct_size;
struct blk_dev_struct * dev; struct blk_dev_struct * dev;
int i; int i;
#if defined(CONFIG_CDU535) && defined(CONFIG_CDU31A)
int sonycd_save_mem_start;
#endif
/* Make sure that the first block contains something reasonable */ /* Make sure that the first block contains something reasonable */
while (!*bh) { while (!*bh) {
...@@ -545,24 +542,12 @@ long blk_dev_init(long mem_start, long mem_end) ...@@ -545,24 +542,12 @@ long blk_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_BLK_DEV_XD #ifdef CONFIG_BLK_DEV_XD
mem_start = xd_init(mem_start,mem_end); mem_start = xd_init(mem_start,mem_end);
#endif #endif
#if defined(CONFIG_CDU535) && defined(CONFIG_CDU31A)
{ /* since controllers for 535 and 31A can be at same location
* we have to be careful.
*/
sonycd_save_mem_start = mem_start;
mem_start = cdu31a_init(mem_start,mem_end);
if ( mem_start == sonycd_save_mem_start ) { /* CDU31A not found */
mem_start = sony535_init(mem_start,mem_end);
}
}
#else
#ifdef CONFIG_CDU31A #ifdef CONFIG_CDU31A
mem_start = cdu31a_init(mem_start,mem_end); mem_start = cdu31a_init(mem_start,mem_end);
#endif #endif
#ifdef CONFIG_CDU535 #ifdef CONFIG_CDU535
mem_start = sony535_init(mem_start,mem_end); mem_start = sony535_init(mem_start,mem_end);
#endif #endif
#endif /* CONFIG_CDU31A && CONFIG_CDU535 */
#ifdef CONFIG_MCD #ifdef CONFIG_MCD
mem_start = mcd_init(mem_start,mem_end); mem_start = mcd_init(mem_start,mem_end);
#endif #endif
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
* include/linux/cdrom.h). With this interface, CDROMs can be * include/linux/cdrom.h). With this interface, CDROMs can be
* accessed and standard audio CDs can be played back normally. * accessed and standard audio CDs can be played back normally.
* *
* This interface is (unfortunatly) a polled interface. This is * This interface is (unfortunately) a polled interface. This is
* because most Sony interfaces are set up with DMA and interrupts * because most Sony interfaces are set up with DMA and interrupts
* disables. Some (like mine) do not even have the capability to * disables. Some (like mine) do not even have the capability to
* handle interrupts or DMA. For this reason you will see a lot of * handle interrupts or DMA. For this reason you will see a lot of
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
* *
* This ugly hack waits for something to happen, sleeping a little * This ugly hack waits for something to happen, sleeping a little
* between every try. it also handles attentions, which are * between every try. it also handles attentions, which are
* asyncronous events from the drive informing the driver that a disk * asynchronous events from the drive informing the driver that a disk
* has been inserted, removed, etc. * has been inserted, removed, etc.
* *
* One thing about these drives: They talk in MSF (Minute Second Frame) format. * One thing about these drives: They talk in MSF (Minute Second Frame) format.
...@@ -93,10 +93,11 @@ ...@@ -93,10 +93,11 @@
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_CDU535 #if defined(CONFIG_CDU535) || defined(MODULE)
#ifdef MODULE #ifdef MODULE
# include <linux/module.h> # include <linux/module.h>
# include <linux/malloc.h>
# include <linux/version.h> # include <linux/version.h>
#endif #endif
...@@ -130,16 +131,25 @@ ...@@ -130,16 +131,25 @@
#endif #endif
/* /*
* this is the base address of the interface card for the Sony CDU535 * this is the base address of the interface card for the Sony CDU-535
* CDROM drive. If your jumpers are set for an address other than * CDROM drive. If your jumpers are set for an address other than
* this one (the default), change the following line to the * this one (the default), change the following line to the
* proper address. * proper address.
*/ */
#ifndef CDU535_ADDRESS #ifndef CDU535_ADDRESS
#define CDU535_ADDRESS (0x340) # define CDU535_ADDRESS (0x340)
#endif #endif
#define DEBUG 1 #ifndef CDU535_HANDLE
# define CDU535_HANDLE "cdu535"
#endif
#ifndef CDU535_MESSAGE_NAME
# define CDU535_MESSAGE_NAME "Sony CDU-535"
#endif
#ifndef DEBUG
# define DEBUG 1
#endif
/* /*
* SONY535_BUFFER_SIZE determines the size of internal buffer used * SONY535_BUFFER_SIZE determines the size of internal buffer used
...@@ -440,10 +450,10 @@ check_drive_status(void) ...@@ -440,10 +450,10 @@ check_drive_status(void)
* should be placed in the cmd[] array, number of bytes in the command is * should be placed in the cmd[] array, number of bytes in the command is
* stored in nCmd. The response from the command will be stored in the * stored in nCmd. The response from the command will be stored in the
* response array. The number of bytes you expect back (excluding status) * response array. The number of bytes you expect back (excluding status)
* should be passed in nReponse. Finally, some * should be passed in nResponse. Finally, some
* commands set bit 7 of the return status even when there is no second * commands set bit 7 of the return status even when there is no second
* status byte, on these commands set ignoreStatusBit7 TRUE. * status byte, on these commands set ignoreStatusBit7 TRUE.
* If the command was sent and data recieved back, then we return 0, * If the command was sent and data received back, then we return 0,
* else we return TIME_OUT. You still have to check the status yourself. * else we return TIME_OUT. You still have to check the status yourself.
* You should call check_drive_status() before calling this routine * You should call check_drive_status() before calling this routine
* so that you do not lose notifications of disk changes, etc. * so that you do not lose notifications of disk changes, etc.
...@@ -843,7 +853,7 @@ do_cdu535_request(void) ...@@ -843,7 +853,7 @@ do_cdu535_request(void)
break; break;
default: default:
panic("Unkown SONY CD cmd"); panic("Unknown SONY CD cmd");
} }
} }
} }
...@@ -1432,7 +1442,8 @@ init_module(void) ...@@ -1432,7 +1442,8 @@ init_module(void)
if (do_sony_cmd(cmd_buff, 1, status, (Byte *) & drive_config, 28, 1) == 0) { if (do_sony_cmd(cmd_buff, 1, status, (Byte *) & drive_config, 28, 1) == 0) {
/* was able to get the configuration, set drive mode as rest of init */ /* was able to get the configuration, set drive mode as rest of init */
#if DEBUG > 0 #if DEBUG > 0
if ( (status[0] & 0x7f) != 0 ) /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */
if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 )
printk("Inquiry command returned status = 0x%x\n", status[0]); printk("Inquiry command returned status = 0x%x\n", status[0]);
#endif #endif
cmd_buff[0] = SONY535_SET_DRIVE_MODE; cmd_buff[0] = SONY535_SET_DRIVE_MODE;
...@@ -1448,8 +1459,9 @@ init_module(void) ...@@ -1448,8 +1459,9 @@ init_module(void)
drive_config.product_rev_level); drive_config.product_rev_level);
printk(" using %d byte buffer\n", sony_buffer_size); printk(" using %d byte buffer\n", sony_buffer_size);
if (register_blkdev(MAJOR_NR, "cdu-535", &cdu_fops)) { if (register_blkdev(MAJOR_NR, CDU535_HANDLE, &cdu_fops)) {
printk("Unable to get major %d for sony CDU-535 cd\n", MAJOR_NR); printk("Unable to get major %d for %s\n",
MAJOR_NR, CDU535_MESSAGE_NAME);
#ifndef MODULE #ifndef MODULE
return mem_start; return mem_start;
#else #else
...@@ -1482,19 +1494,17 @@ init_module(void) ...@@ -1482,19 +1494,17 @@ init_module(void)
} }
} }
#ifndef MODULE
if (!initialized)
printk("Did not find a Sony CDU-535 drive\n");
else
snarf_region(sony_cd_base_io, 4);
return mem_start;
#else
if (!initialized) { if (!initialized) {
printk("Did not find a Sony CDU-535 drive\n"); printk("Did not find a " CDU535_MESSAGE_NAME " drive\n");
#ifdef MODULE
return -EIO; return -EIO;
#endif
} else { } else {
snarf_region(sony_cd_base_io, 4); request_region(sony_cd_base_io, 4, CDU535_HANDLE);
} }
#ifndef MODULE
return mem_start;
#else
return 0; return 0;
#endif #endif
} }
...@@ -1519,7 +1529,8 @@ sonycd535_setup(char *strings, int *ints) ...@@ -1519,7 +1529,8 @@ sonycd535_setup(char *strings, int *ints)
irq_used = ints[2]; irq_used = ints[2];
#endif #endif
if ((strings != NULL) && (*strings != '\0')) if ((strings != NULL) && (*strings != '\0'))
printk("Sony CDU-535: Warning: Unknown interface type: %s\n", strings); printk("%s: Warning: Unknown interface type: %s\n",
strings, CDU535_MESSAGE_NAME);
} }
#else /* MODULE */ #else /* MODULE */
...@@ -1532,16 +1543,16 @@ cleanup_module(void) ...@@ -1532,16 +1543,16 @@ cleanup_module(void)
printk("Sony 535 module in use, cannot remove\n"); printk("Sony 535 module in use, cannot remove\n");
return; return;
} }
if (unregister_blkdev(MAJOR_NR, "cdu-535") == (-EINVAL)) { release_region(sony_cd_base_io, 4);
printk("Uh oh, couldn't unregister cdu-535\n");
return;
}
kfree_s(sony_toc, sizeof (*sony_toc)); kfree_s(sony_toc, sizeof (*sony_toc));
kfree_s(last_sony_subcode, sizeof (*last_sony_subcode)); kfree_s(last_sony_subcode, sizeof (*last_sony_subcode));
for (i = 0; i < sony_buffer_sectors; i++) for (i = 0; i < sony_buffer_sectors; i++)
kfree_s(sony_buffer[i], 2048); kfree_s(sony_buffer[i], 2048);
kfree_s(sony_buffer, 4 * sony_buffer_sectors); kfree_s(sony_buffer, 4 * sony_buffer_sectors);
printk("cdu-535 module released\n"); if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL)
printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n");
else
printk(CDU535_HANDLE " module released\n");
} }
#endif /* MODULE */ #endif /* MODULE */
......
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
$(CC) $(CFLAGS) -c $< $(CC) $(CFLAGS) -c $<
OBJS = tty_io.o n_tty.o console.o keyboard.o serial.o \ OBJS = tty_io.o n_tty.o console.o keyboard.o serial.o \
tty_ioctl.o pty.o vt.o mem.o \ tty_ioctl.o pty.o vt.o mem.o vc_screen.o \
defkeymap.o uni_to_437.o vesa_blank.o defkeymap.o consolemap.o vesa_blank.o selection.o
SRCS = tty_io.c n_tty.c console.c keyboard.c serial.c \ SRCS = tty_io.c n_tty.c console.c keyboard.c serial.c \
tty_ioctl.c pty.c vt.c mem.c \ tty_ioctl.c pty.c vt.c mem.c vc_screen.c \
defkeymap.c uni_to_437.c vesa_blank.c defkeymap.c consolemap.c vesa_blank.c selection.c
ifdef CONFIG_CYCLADES ifdef CONFIG_CYCLADES
......
This diff is collapsed.
/*
* consolemap.c
*
* Mapping from internal code (such as Latin-1 or Unicode or IBM PC code)
* to font positions.
*
* aeb, 950210
*/
#include <linux/kd.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <asm/segment.h>
#include "consolemap.h"
static unsigned char * translations[] = {
/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */
(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
"\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
"\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
"\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
/* vt100 graphics */
(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0"
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ "
"\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304"
"\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\377\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
"\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
"\376\245\376\376\376\376\231\376\376\376\376\376\232\376\376\341"
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
"\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230",
/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */
(unsigned char *)
"\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000"
"\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",
/* 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"
};
/* the above mappings are not invertible - this is just a best effort */
static unsigned char * inv_translate = NULL;
static unsigned char inv_norm_transl[E_TABSZ];
static unsigned char * inverse_translations[4] = { NULL, NULL, NULL, NULL };
static void set_inverse_transl(int i)
{
int j;
unsigned char *p = translations[i];
unsigned char *q = inverse_translations[i];
if (!q) {
/* slightly messy to avoid calling kmalloc too early */
q = inverse_translations[i] = ((i == NORM_MAP)
? inv_norm_transl
: (unsigned char *) kmalloc(E_TABSZ, GFP_KERNEL));
if (!q)
return;
}
for (j=0; j<E_TABSZ; j++)
q[j] = 0;
for (j=0; j<E_TABSZ; j++)
if (q[p[j]] < 32) /* prefer '-' above SHY etc. */
q[p[j]] = j;
}
unsigned char *set_translate(int m)
{
if (!inverse_translations[m])
set_inverse_transl(m);
inv_translate = inverse_translations[m];
return translations[m];
}
/*
* Inverse translation is impossible for several reasons:
* 1. The translation maps are not 1-1
* 2. The text may have been written while a different translation map
* was active
* Still, it is now possible to a certain extent to cut and paste non-ASCII.
*/
unsigned char inverse_translate(unsigned char c) {
return ((inv_translate && inv_translate[c]) ? inv_translate[c] : c);
}
/*
* Load customizable translation table
* arg points to a 256 byte translation table.
*/
int con_set_trans(char * arg)
{
int i;
unsigned char *p = translations[USER_MAP];
i = verify_area(VERIFY_READ, (void *)arg, E_TABSZ);
if (i)
return i;
for (i=0; i<E_TABSZ ; i++)
p[i] = get_fs_byte(arg+i);
p[012] = p[014] = p[015] = p[033] = 0;
set_inverse_transl(USER_MAP);
return 0;
}
int con_get_trans(char * arg)
{
int i;
unsigned char *p = translations[USER_MAP];
i = verify_area(VERIFY_WRITE, (void *)arg, E_TABSZ);
if (i)
return i;
for (i=0; i<E_TABSZ ; i++) put_fs_byte(p[i],arg+i);
return 0;
}
/*
* Unicode -> current font conversion
*
* A font has at most 512 chars, usually 256.
* But one font position may represent several Unicode chars
* (and moreover, hashtables work best when they are not too full),
* so pick HASHSIZE somewhat larger than 512.
* Since there are likely to be long consecutive stretches
* (like U+0000 to U+00FF), HASHSTEP should not be too small.
* Searches longer than MAXHASHLEVEL steps are refused, unless
* requested explicitly.
*
* Note: no conversion tables are compiled in, so the user
* must supply an explicit mapping herself. See kbd-0.90 (or an
* earlier kernel version) for the default Unicode-to-PC mapping.
* Usually, the mapping will be loaded simultaneously with the font.
*/
#define HASHSIZE 641
#define HASHSTEP 189 /* yields hashlevel = 3 initially */
#define MAXHASHLEVEL 6
static struct unipair hashtable[HASHSIZE];
int hashtable_contents_valid = 0; /* cleared by setfont */
static unsigned int hashsize;
static unsigned int hashstep;
static unsigned int hashlevel;
static unsigned int maxhashlevel;
void
con_clear_unimap(struct unimapinit *ui) {
int i;
/* read advisory values for hash algorithm */
hashsize = ui->advised_hashsize;
if (hashsize < 256 || hashsize > HASHSIZE)
hashsize = HASHSIZE;
hashstep = (ui->advised_hashstep % hashsize);
if (hashstep < 64)
hashstep = HASHSTEP;
maxhashlevel = ui->advised_hashlevel;
if (!maxhashlevel)
maxhashlevel = MAXHASHLEVEL;
if (maxhashlevel > hashsize)
maxhashlevel = hashsize;
/* initialize */
hashlevel = 0;
for (i=0; i<hashsize; i++)
hashtable[i].unicode = 0xffff;
hashtable_contents_valid = 1;
}
int
con_set_unimap(ushort ct, struct unipair *list){
int i, lct;
ushort u, hu;
struct unimapinit hashdefaults = { 0, 0, 0 };
if (!hashtable_contents_valid)
con_clear_unimap(&hashdefaults);
while(ct) {
u = get_fs_word(&list->unicode);
i = u % hashsize;
lct = 1;
while ((hu = hashtable[i].unicode) != 0xffff && hu != u) {
if (lct++ >= maxhashlevel)
return -ENOMEM;
i += hashstep;
if (i >= hashsize)
i -= hashsize;
}
if (lct > hashlevel)
hashlevel = lct;
hashtable[i].unicode = u;
hashtable[i].fontpos = get_fs_word(&list->fontpos);
list++;
ct--;
}
return 0;
}
int
con_get_unimap(ushort ct, ushort *uct, struct unipair *list){
int i, ect;
ect = 0;
if (hashtable_contents_valid)
for (i = 0; i<hashsize; i++)
if (hashtable[i].unicode != 0xffff) {
if (ect++ < ct) {
put_fs_word(hashtable[i].unicode, &list->unicode);
put_fs_word(hashtable[i].fontpos, &list->fontpos);
list++;
}
}
put_fs_word(ect, uct);
return ((ect <= ct) ? 0 : -ENOMEM);
}
int
conv_uni_to_pc(unsigned long ucs) {
int i, h;
if (!hashtable_contents_valid || ucs < 0x20)
return -3;
if (ucs == 0xffff || ucs == 0xfffe)
return -1;
if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
return -2;
h = ucs % hashsize;
for (i = 0; i < hashlevel; i++) {
if (hashtable[h].unicode == ucs)
return hashtable[h].fontpos;
if ((h += hashstep) >= hashsize)
h -= hashsize;
}
return -4; /* not found */
}
/*
* consolemap.h
*
* Interface between console.c, selection.c and consolemap.c
*/
#define NORM_MAP 0
#define GRAF_MAP 1
#define NULL_MAP 2
#define USER_MAP 3
extern int hashtable_contents_valid;
extern unsigned char inverse_translate(unsigned char c);
extern unsigned char *set_translate(int m);
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/keyboard.h> #include <linux/keyboard.h>
extern int shift_state;
extern char *func_table[MAX_NR_FUNC]; extern char *func_table[MAX_NR_FUNC];
extern char func_buf[]; extern char func_buf[];
extern char *funcbufptr; extern char *funcbufptr;
......
...@@ -370,10 +370,22 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs) ...@@ -370,10 +370,22 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs)
prev_scancode = 0; prev_scancode = 0;
goto end_kbd_intr; goto end_kbd_intr;
} }
tty = ttytab[fg_console];
kbd = kbd_table + fg_console;
if ((raw_mode = (kbd->kbdmode == 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
values when finishing RAW mode or when changing VT's */
}
if (scancode == 0xff) { if (scancode == 0xff) {
/* in scancode mode 1, my ESC key generates 0xff */
/* the calculator keys on a FOCUS 9000 generate 0xff */ /* the calculator keys on a FOCUS 9000 generate 0xff */
#ifndef KBD_IS_FOCUS_9000 #ifndef KBD_IS_FOCUS_9000
#ifdef KBD_REPORT_ERR #ifdef KBD_REPORT_ERR
if (!raw_mode)
printk("keyboard error\n"); printk("keyboard error\n");
#endif #endif
#endif #endif
...@@ -381,14 +393,6 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs) ...@@ -381,14 +393,6 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs)
goto end_kbd_intr; goto end_kbd_intr;
} }
tty = ttytab[fg_console];
kbd = kbd_table + fg_console;
if ((raw_mode = (kbd->kbdmode == 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
values when finishing RAW mode or when changing VT's */
}
if (scancode == 0xe0 || scancode == 0xe1) { if (scancode == 0xe0 || scancode == 0xe1) {
prev_scancode = scancode; prev_scancode = scancode;
goto end_kbd_intr; goto end_kbd_intr;
...@@ -414,6 +418,7 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs) ...@@ -414,6 +418,7 @@ static void keyboard_interrupt(int irq, struct pt_regs *regs)
prev_scancode = 0; prev_scancode = 0;
} else { } else {
#ifdef KBD_REPORT_UNKN #ifdef KBD_REPORT_UNKN
if (!raw_mode)
printk("keyboard: unknown e1 escape sequence\n"); printk("keyboard: unknown e1 escape sequence\n");
#endif #endif
prev_scancode = 0; prev_scancode = 0;
...@@ -729,7 +734,7 @@ static void SAK(void) ...@@ -729,7 +734,7 @@ static void SAK(void)
* work. * work.
*/ */
reset_vc(fg_console); reset_vc(fg_console);
unblank_screen(); /* not in interrupt routine? */ do_unblank_screen(); /* not in interrupt routine? */
#endif #endif
} }
......
/*
* linux/drivers/char/selection.c
*
* This module exports the functions:
*
* 'int set_selection(const int arg)'
* 'void clear_selection(void)'
* 'int paste_selection(struct tty_struct *tty)'
* 'int sel_loadlut(const int arg)'
*
* Now that /dev/vcs exists, most of this can disappear again.
*/
#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include "vt_kern.h"
#include "consolemap.h"
#include "selection.h"
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
#define isspace(c) ((c) == ' ')
/* Variables for selection control. */
/* Use a dynamic buffer, instead of static (Dec 1994) */
int sel_cons = 0; /* must not be disallocated */
static volatile int sel_start = -1; /* cleared by clear_selection */
static int sel_end;
static int sel_buffer_lth = 0;
static char *sel_buffer = NULL;
#define sel_pos(n) inverse_translate(screen_word(sel_cons, n, 1) & 0xff)
/* clear_selection, highlight and highlight_pointer can be called
from interrupt (via scrollback/front) */
/* set reverse video on characters s-e of console with selection. */
inline static void
highlight(const int s, const int e) {
invert_screen(sel_cons, s, e-s+2, 1);
}
/* use complementary color to show the pointer */
inline static void
highlight_pointer(const int where) {
complement_pos(sel_cons, where);
}
/* remove the current selection highlight, if any,
from the console holding the selection. */
void
clear_selection(void) {
highlight_pointer(-1); /* hide the pointer */
if (sel_start != -1) {
highlight(sel_start, sel_end);
sel_start = -1;
}
}
/*
* User settable table: what characters are to be considered alphabetic?
* 256 bits
*/
static unsigned long inwordLut[8]={
0x00000000, /* control chars */
0x03FF0000, /* digits */
0x87FFFFFE, /* uppercase and '_' */
0x07FFFFFE, /* lowercase */
0x00000000,
0x00000000,
0xFF7FFFFF, /* latin-1 accented letters, not multiplication sign */
0xFF7FFFFF /* latin-1 accented letters, not division sign */
};
static inline int inword(const unsigned char c) {
return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1;
}
/* set inwordLut contents. Invoked by ioctl(). */
int sel_loadlut(const int arg)
{
int i = verify_area(VERIFY_READ, (char *) arg, 36);
if (i)
return i;
memcpy_fromfs(inwordLut, (unsigned long *)(arg+4), 32);
return 0;
}
/* does screen address p correspond to character at LH/RH edge of screen? */
static inline int atedge(const int p)
{
return (!(p % video_size_row) || !((p + 2) % video_size_row));
}
/* constrain v such that v <= u */
static inline unsigned short limit(const unsigned short v, const unsigned short u)
{
/* gcc miscompiles the ?: operator, so don't use it.. */
if (v > u)
return u;
return v;
}
/* set the current selection. Invoked by ioctl(). */
int set_selection(const int arg, struct tty_struct *tty)
{
int sel_mode, new_sel_start, new_sel_end, spc;
char *bp, *obp;
int i, ps, pe;
do_unblank_screen();
{ unsigned short *args, xs, ys, xe, ye;
args = (unsigned short *)(arg + 1);
xs = get_fs_word(args++) - 1;
ys = get_fs_word(args++) - 1;
xe = get_fs_word(args++) - 1;
ye = get_fs_word(args++) - 1;
sel_mode = get_fs_word(args);
xs = limit(xs, video_num_columns - 1);
ys = limit(ys, video_num_lines - 1);
xe = limit(xe, video_num_columns - 1);
ye = limit(ye, video_num_lines - 1);
ps = ys * video_size_row + (xs << 1);
pe = ye * video_size_row + (xe << 1);
if (sel_mode == 4) {
/* useful for screendump without selection highlights */
clear_selection();
return 0;
}
if (mouse_reporting() && (sel_mode & 16)) {
mouse_report(tty, sel_mode & 15, xs, ys);
return 0;
}
}
if (ps > pe) /* make sel_start <= sel_end */
{
int tmp = ps;
ps = pe;
pe = tmp;
}
if (sel_cons != fg_console) {
clear_selection();
sel_cons = fg_console;
}
switch (sel_mode)
{
case 0: /* character-by-character selection */
new_sel_start = ps;
new_sel_end = pe;
break;
case 1: /* word-by-word selection */
spc = isspace(sel_pos(ps));
for (new_sel_start = ps; ; ps -= 2)
{
if ((spc && !isspace(sel_pos(ps))) ||
(!spc && !inword(sel_pos(ps))))
break;
new_sel_start = ps;
if (!(ps % video_size_row))
break;
}
spc = isspace(sel_pos(pe));
for (new_sel_end = pe; ; pe += 2)
{
if ((spc && !isspace(sel_pos(pe))) ||
(!spc && !inword(sel_pos(pe))))
break;
new_sel_end = pe;
if (!((pe + 2) % video_size_row))
break;
}
break;
case 2: /* line-by-line selection */
new_sel_start = ps - ps % video_size_row;
new_sel_end = pe + video_size_row
- pe % video_size_row - 2;
break;
case 3:
highlight_pointer(pe);
return 0;
default:
return -EINVAL;
}
/* remove the pointer */
highlight_pointer(-1);
/* select to end of line if on trailing space */
if (new_sel_end > new_sel_start &&
!atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) {
for (pe = new_sel_end + 2; ; pe += 2)
if (!isspace(sel_pos(pe)) || atedge(pe))
break;
if (isspace(sel_pos(pe)))
new_sel_end = pe;
}
if (sel_start == -1) /* no current selection */
highlight(new_sel_start, new_sel_end);
else if (new_sel_start == sel_start)
{
if (new_sel_end == sel_end) /* no action required */
return 0;
else if (new_sel_end > sel_end) /* extend to right */
highlight(sel_end + 2, new_sel_end);
else /* contract from right */
highlight(new_sel_end + 2, sel_end);
}
else if (new_sel_end == sel_end)
{
if (new_sel_start < sel_start) /* extend to left */
highlight(new_sel_start, sel_start - 2);
else /* contract from left */
highlight(sel_start, new_sel_start - 2);
}
else /* some other case; start selection from scratch */
{
clear_selection();
highlight(new_sel_start, new_sel_end);
}
sel_start = new_sel_start;
sel_end = new_sel_end;
if (sel_buffer)
kfree(sel_buffer);
sel_buffer = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL);
if (!sel_buffer) {
printk("selection: kmalloc() failed\n");
clear_selection();
return -ENOMEM;
}
obp = bp = sel_buffer;
for (i = sel_start; i <= sel_end; i += 2) {
*bp = sel_pos(i);
if (!isspace(*bp++))
obp = bp;
if (! ((i + 2) % video_size_row)) {
/* strip trailing blanks from line and add newline,
unless non-space at end of line. */
if (obp != bp) {
bp = obp;
*bp++ = '\r';
}
obp = bp;
}
}
sel_buffer_lth = bp - sel_buffer;
return 0;
}
/* Insert the contents of the selection buffer into the queue of the
tty associated with the current console. Invoked by ioctl(). */
int paste_selection(struct tty_struct *tty)
{
struct wait_queue wait = { current, NULL };
char *bp = sel_buffer;
int c = sel_buffer_lth;
int l;
struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
if (!bp || !c)
return 0;
do_unblank_screen();
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&vt->paste_wait, &wait);
while (c) {
if (test_bit(TTY_THROTTLED, &tty->flags)) {
schedule();
continue;
}
l = MIN(c, tty->ldisc.receive_room(tty));
tty->ldisc.receive_buf(tty, bp, 0, l);
c -= l;
bp += l;
}
current->state = TASK_RUNNING;
return 0;
}
/*
* selection.h
*
* Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
*/
extern int sel_cons;
extern void clear_selection(void);
extern int set_selection(const int arg, struct tty_struct *tty);
extern int paste_selection(struct tty_struct *tty);
extern int sel_loadlut(const int arg);
extern int mouse_reporting(void);
extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
extern unsigned long video_num_columns;
extern unsigned long video_num_lines;
extern unsigned long video_size_row;
extern void do_unblank_screen(void);
extern unsigned short *screen_pos(int currcons, int w_offset, int viewed);
extern unsigned short screen_word(int currcons, int offset, int viewed);
extern void complement_pos(int currcons, int offset);
extern void invert_screen(int currcons, int offset, int count, int shift);
#define reverse_video_char(a) (((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77))
#define reverse_video_short(a) (((a) & 0x88ff) | \
(((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4))
/* this latter line used to have masks 0xf000 and 0x0f00, but selection
requires a self-inverse operation; moreover, the old version looks wrong */
extern void getconsxy(int currcons, char *p);
extern void putconsxy(int currcons, char *p);
/* how to access screen memory */
#ifdef __alpha__
static inline void scr_writew(unsigned short val, unsigned short * addr)
{
if ((long) addr < 0)
*addr = val;
else
writew(val, (unsigned long) addr);
}
static inline unsigned short scr_readw(unsigned short * addr)
{
if ((long) addr < 0)
return *addr;
return readw((unsigned long) addr);
}
#else
static inline void scr_writew(unsigned short val, unsigned short * addr)
{
*addr = val;
}
static inline unsigned short scr_readw(unsigned short * addr)
{
return *addr;
}
#endif
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include "kbd_kern.h" #include "kbd_kern.h"
#include "vt_kern.h" #include "vt_kern.h"
#include "selection.h"
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0) #define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
#define TTY_DEV MKDEV(TTYAUX_MAJOR,0) #define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
...@@ -69,14 +70,6 @@ ...@@ -69,14 +70,6 @@
#define TTY_PARANOIA_CHECK #define TTY_PARANOIA_CHECK
#define CHECK_TTY_COUNT #define CHECK_TTY_COUNT
#ifdef CONFIG_SELECTION
extern int set_selection(const int arg, struct tty_struct *tty);
extern int paste_selection(struct tty_struct *tty);
extern int sel_loadlut(const int arg);
extern int mouse_reporting(void);
extern int shift_state;
#endif /* CONFIG_SELECTION */
extern int do_screendump(unsigned long arg, int mode);
extern void do_blank_screen(int nopowersave); extern void do_blank_screen(int nopowersave);
extern void do_unblank_screen(void); extern void do_unblank_screen(void);
extern void set_vesa_blanking(const unsigned long arg); extern void set_vesa_blanking(const unsigned long arg);
...@@ -1247,6 +1240,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on) ...@@ -1247,6 +1240,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
return 0; return 0;
} }
#if 0
/* /*
* XXX does anyone use this anymore?!? * XXX does anyone use this anymore?!?
*/ */
...@@ -1278,6 +1272,7 @@ static int do_get_ps_info(unsigned long arg) ...@@ -1278,6 +1272,7 @@ static int do_get_ps_info(unsigned long arg)
put_fs_long(0, (unsigned long *)(ts->present+n)); put_fs_long(0, (unsigned long *)(ts->present+n));
return(0); return(0);
} }
#endif
static int tty_ioctl(struct inode * inode, struct file * file, static int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
...@@ -1453,20 +1448,22 @@ static int tty_ioctl(struct inode * inode, struct file * file, ...@@ -1453,20 +1448,22 @@ static int tty_ioctl(struct inode * inode, struct file * file,
switch (retval = get_fs_byte((char *)arg)) switch (retval = get_fs_byte((char *)arg))
{ {
case 0: case 0:
return do_screendump(arg,0); case 8:
case 9:
printk("TIOCLINUX (0/8/9) ioctl is gone - use /dev/vcs\n");
return -EINVAL;
#if 0
case 1: case 1:
printk("Deprecated TIOCLINUX (1) ioctl\n"); printk("Deprecated TIOCLINUX (1) ioctl\n");
return do_get_ps_info(arg); return do_get_ps_info(arg);
#ifdef CONFIG_SELECTION #endif
case 2: case 2:
return set_selection(arg, tty); return set_selection(arg, tty);
case 3: case 3:
return paste_selection(tty); return paste_selection(tty);
#endif /* CONFIG_SELECTION */
case 4: case 4:
do_unblank_screen(); do_unblank_screen();
return 0; return 0;
#ifdef CONFIG_SELECTION
case 5: case 5:
return sel_loadlut(arg); return sel_loadlut(arg);
case 6: case 6:
...@@ -1481,16 +1478,13 @@ static int tty_ioctl(struct inode * inode, struct file * file, ...@@ -1481,16 +1478,13 @@ static int tty_ioctl(struct inode * inode, struct file * file,
case 7: case 7:
put_fs_byte(mouse_reporting(),arg); put_fs_byte(mouse_reporting(),arg);
return 0; return 0;
#endif /* CONFIG_SELECTION */
case 8: /* second arg is 1 or 2 */
case 9: /* both are explained in console.c */
return do_screendump(arg,retval-7);
case 10: case 10:
set_vesa_blanking(arg); set_vesa_blanking(arg);
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;
} }
case TIOCTTYGSTRUCT: case TIOCTTYGSTRUCT:
retval = verify_area(VERIFY_WRITE, (void *) arg, retval = verify_area(VERIFY_WRITE, (void *) arg,
sizeof(struct tty_struct)); sizeof(struct tty_struct));
...@@ -1742,5 +1736,6 @@ long tty_init(long kmem_start) ...@@ -1742,5 +1736,6 @@ long tty_init(long kmem_start)
kmem_start = cy_init(kmem_start); kmem_start = cy_init(kmem_start);
#endif #endif
kmem_start = pty_init(kmem_start); kmem_start = pty_init(kmem_start);
kmem_start = vcs_init(kmem_start);
return kmem_start; return kmem_start;
} }
/*
* non-Latin-1 (>0x00ff) Unicode -> IBM CP437 conversion hash table
* Markus Kuhn
*/
#define IBM_HASHSIZE 146
#define IBM_HASHSTEP 19
#define IBM_HASHLEVEL 4
static struct {
unsigned short ucs; /* a Unicode code */
unsigned char ibm437; /* the corresponding IBM code */
} ibm_hash[IBM_HASHSIZE] = {
{0x221a,0xfb}, {0x2580,0xdf}, {0x2524,0xb4}, {0xffff,0x00}, {0x221e,0xec},
{0x20a7,0x9e}, {0x2126,0xea}, {0x253c,0xc5}, {0xffff,0x00}, {0x2588,0xdb},
{0x2666,0x04}, {0x2190,0x1b}, {0x2193,0x19}, {0x2665,0x03}, {0x2195,0x12},
{0x2663,0x05}, {0x2660,0x06}, {0x2590,0xde}, {0x2022,0x07}, {0x2592,0xb1},
{0x266c,0x0e}, {0x2502,0xb3}, {0x266a,0x0d}, {0x250c,0xda}, {0x258c,0xdd},
{0xffff,0x00}, {0xffff,0x00}, {0xffff,0x00}, {0xffff,0x00}, {0x2191,0x18},
{0x2261,0xf0}, {0x2514,0xc0}, {0x2192,0x1a}, {0x2264,0xf3}, {0x2194,0x1d},
{0x2591,0xb0}, {0x0393,0xe2}, {0x2593,0xb2}, {0x2500,0xc4}, {0x251c,0xc3},
{0x2205,0xed}, {0xffff,0x00}, {0x266b,0x0e}, {0x2518,0xd9}, {0x203c,0x13},
{0xffff,0x00}, {0x2642,0x0b}, {0x2564,0xd1}, {0x2640,0x0c}, {0x2566,0xcb},
{0x2561,0xb5}, {0x2560,0xcc}, {0x2563,0xb9}, {0x2562,0xb6}, {0x2510,0xbf},
{0x256c,0xce}, {0x2008,0x00}, {0x03a6,0xe8}, {0x2569,0xca}, {0x2568,0xd0},
{0x256b,0xd7}, {0x256a,0xd8}, {0x03a9,0xea}, {0xffff,0x00}, {0xffff,0x00},
{0x25c0,0x11}, {0x0398,0xe9}, {0x2567,0xcf}, {0xffff,0x00}, {0x2248,0xf7},
{0x03b1,0xe0}, {0x03a3,0xe4}, {0x2265,0xf2}, {0xffff,0x00}, {0x25cb,0x09},
{0x03b4,0xeb}, {0x2320,0xf4}, {0xffff,0x00}, {0xffff,0x00}, {0xffff,0x00},
{0x25c4,0x11}, {0xffff,0x00}, {0xffff,0x00}, {0x03bc,0xe6}, {0x2565,0xd2},
{0xffff,0x00}, {0x22c5,0xf9}, {0x2302,0x7f}, {0x25d9,0x0a}, {0x25d8,0x08},
{0xffff,0x00}, {0x03c4,0xe7}, {0xffff,0x00}, {0xffff,0x00}, {0x2555,0xb8},
{0x2554,0xc9}, {0x2557,0xbb}, {0x2556,0xb7}, {0x2551,0xba}, {0x2550,0xcd},
{0x2553,0xd6}, {0x2552,0xd5}, {0x255d,0xbc}, {0x255c,0xbd}, {0x255f,0xc7},
{0x2310,0xa9}, {0x2559,0xd3}, {0x2558,0xd4}, {0x255b,0xbe}, {0x255a,0xc8},
{0xffff,0x00}, {0x0192,0x9f}, {0x2319,0x1c}, {0x2321,0xf5}, {0xffff,0x00},
{0x25a0,0xfe}, {0xffff,0x00}, {0x21a8,0x17}, {0x263c,0x0f}, {0x25ac,0x16},
{0x263a,0x01}, {0x263b,0x02}, {0x03c3,0xe5}, {0xffff,0x00}, {0x255e,0xc6},
{0x03c0,0xe3}, {0x03b2,0xe1}, {0x2300,0xed}, {0xffff,0x00}, {0x25b6,0x10},
{0x207f,0xfc}, {0xffff,0x00}, {0x2208,0xee}, {0x25b2,0x1e}, {0x220e,0xfe},
{0x25bc,0x1f}, {0x212b,0x8f}, {0x252c,0xc2}, {0xffff,0x00}, {0x2229,0xef},
{0xffff,0x00}, {0x25ba,0x10}, {0xffff,0x00}, {0x2584,0xdc}, {0xffff,0x00},
{0x2534,0xc1}
};
/*
* Find the correct PC character set (CP437) code for a
* UCS character outside Latin-1 by hash lookup in ibm_hash[].
* Return -1 if character not available, return -2 for zero-width
* space characters.
*/
int
conv_uni_to_pc(unsigned long ucs)
{
int c = -1;
int i, h;
if (ucs == 0xffff || ucs == 0xfffe)
return -1;
if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
return -2;
h = (ucs ^ (ucs >> 8)) % IBM_HASHSIZE;
for (i = 0; i < IBM_HASHLEVEL && c == -1; i++)
if (ibm_hash[h].ucs == ucs)
c = ibm_hash[h].ibm437;
else
if ((h += IBM_HASHSTEP) >= IBM_HASHSIZE)
h -= IBM_HASHSIZE;
return c;
}
#if 0
/*
* Conversion from unicode to ibm pc character set (code page 437)
*
* aeb@cwi.nl, Dec 1993
*/
#define NOTFOUND 254 /* small square */
static struct unipc {
long unicode;
unsigned char pc;
} uni_to_pc[255] = {
{0x0020, 0x20}, {0x0021, 0x21}, {0x0022, 0x22}, {0x0023, 0x23},
{0x0024, 0x24}, {0x0025, 0x25}, {0x0026, 0x26}, {0x0027, 0x27},
{0x0028, 0x28}, {0x0029, 0x29}, {0x002A, 0x2A}, {0x002B, 0x2B},
{0x002C, 0x2C}, {0x002D, 0x2D}, {0x002E, 0x2E}, {0x002F, 0x2F},
{0x0030, 0x30}, {0x0031, 0x31}, {0x0032, 0x32}, {0x0033, 0x33},
{0x0034, 0x34}, {0x0035, 0x35}, {0x0036, 0x36}, {0x0037, 0x37},
{0x0038, 0x38}, {0x0039, 0x39}, {0x003A, 0x3A}, {0x003B, 0x3B},
{0x003C, 0x3C}, {0x003D, 0x3D}, {0x003E, 0x3E}, {0x003F, 0x3F},
{0x0040, 0x40}, {0x0041, 0x41}, {0x0042, 0x42}, {0x0043, 0x43},
{0x0044, 0x44}, {0x0045, 0x45}, {0x0046, 0x46}, {0x0047, 0x47},
{0x0048, 0x48}, {0x0049, 0x49}, {0x004A, 0x4A}, {0x004B, 0x4B},
{0x004C, 0x4C}, {0x004D, 0x4D}, {0x004E, 0x4E}, {0x004F, 0x4F},
{0x0050, 0x50}, {0x0051, 0x51}, {0x0052, 0x52}, {0x0053, 0x53},
{0x0054, 0x54}, {0x0055, 0x55}, {0x0056, 0x56}, {0x0057, 0x57},
{0x0058, 0x58}, {0x0059, 0x59}, {0x005A, 0x5A}, {0x005B, 0x5B},
{0x005C, 0x5C}, {0x005D, 0x5D}, {0x005E, 0x5E}, {0x005F, 0x5F},
{0x0060, 0x60}, {0x0061, 0x61}, {0x0062, 0x62}, {0x0063, 0x63},
{0x0064, 0x64}, {0x0065, 0x65}, {0x0066, 0x66}, {0x0067, 0x67},
{0x0068, 0x68}, {0x0069, 0x69}, {0x006A, 0x6A}, {0x006B, 0x6B},
{0x006C, 0x6C}, {0x006D, 0x6D}, {0x006E, 0x6E}, {0x006F, 0x6F},
{0x0070, 0x70}, {0x0071, 0x71}, {0x0072, 0x72}, {0x0073, 0x73},
{0x0074, 0x74}, {0x0075, 0x75}, {0x0076, 0x76}, {0x0077, 0x77},
{0x0078, 0x78}, {0x0079, 0x79}, {0x007A, 0x7A}, {0x007B, 0x7B},
{0x007C, 0x7C}, {0x007D, 0x7D}, {0x007E, 0x7E}, {0x00A0, 0xFF},
{0x00A1, 0xAD}, {0x00A2, 0x9B}, {0x00A3, 0x9C}, {0x00A5, 0x9D},
{0x00A7, 0x15}, {0x00AA, 0xA6}, {0x00AB, 0xAE}, {0x00AC, 0xAA},
{0x00B0, 0xF8}, {0x00B1, 0xF1}, {0x00B2, 0xFD}, {0x00B5, 0xE6},
{0x00B6, 0x14}, {0x00B7, 0xFA}, {0x00BA, 0xA7}, {0x00BB, 0xAF},
{0x00BC, 0xAC}, {0x00BD, 0xAB}, {0x00BF, 0xA8}, {0x00C4, 0x8E},
{0x00C5, 0x8F}, {0x00C6, 0x92}, {0x00C7, 0x80}, {0x00C9, 0x90},
{0x00D1, 0xA5}, {0x00D6, 0x99}, {0x00DC, 0x9A}, {0x00DF, 0xE1},
{0x00E0, 0x85}, {0x00E1, 0xA0}, {0x00E2, 0x83}, {0x00E4, 0x84},
{0x00E5, 0x86}, {0x00E6, 0x91}, {0x00E7, 0x87}, {0x00E8, 0x8A},
{0x00E9, 0x82}, {0x00EA, 0x88}, {0x00EB, 0x89}, {0x00EC, 0x8D},
{0x00ED, 0xA1}, {0x00EE, 0x8C}, {0x00EF, 0x8B}, {0x00F1, 0xA4},
{0x00F2, 0x95}, {0x00F3, 0xA2}, {0x00F4, 0x93}, {0x00F6, 0x94},
{0x00F7, 0xF6}, {0x00F9, 0x97}, {0x00FA, 0xA3}, {0x00FB, 0x96},
{0x00FC, 0x81}, {0x00FF, 0x98}, {0x0192, 0x9F}, {0x0393, 0xE2},
{0x0398, 0xE9}, {0x03A3, 0xE4}, {0x03A6, 0xE8}, {0x03A9, 0xEA},
{0x03B1, 0xE0}, {0x03B4, 0xEB}, {0x03B5, 0xEE}, {0x03C0, 0xE3},
{0x03C3, 0xE5}, {0x03C4, 0xE7}, {0x03C6, 0xED}, {0x2022, 0x07},
{0x203C, 0x13}, {0x207F, 0xFC}, {0x20A7, 0x9E}, {0x2190, 0x1B},
{0x2191, 0x18}, {0x2192, 0x1A}, {0x2193, 0x19}, {0x2194, 0x1D},
{0x2195, 0x12}, {0x21A8, 0x17}, {0x2219, 0xF9}, {0x221A, 0xFB},
{0x221E, 0xEC}, {0x221F, 0x1C}, {0x2229, 0xEF}, {0x2248, 0xF7},
{0x2261, 0xF0}, {0x2264, 0xF3}, {0x2265, 0xF2}, {0x2302, 0x7F},
{0x2310, 0xA9}, {0x2320, 0xF4}, {0x2321, 0xF5}, {0x2500, 0xC4},
{0x2502, 0xB3}, {0x250C, 0xDA}, {0x2510, 0xBF}, {0x2514, 0xC0},
{0x2518, 0xD9}, {0x251C, 0xC3}, {0x2524, 0xB4}, {0x252C, 0xC2},
{0x2534, 0xC1}, {0x253C, 0xC5}, {0x2550, 0xCD}, {0x2551, 0xBA},
{0x2552, 0xD5}, {0x2553, 0xD6}, {0x2554, 0xC9}, {0x2555, 0xB8},
{0x2556, 0xB7}, {0x2557, 0xBB}, {0x2558, 0xD4}, {0x2559, 0xD3},
{0x255A, 0xC8}, {0x255B, 0xBE}, {0x255C, 0xBD}, {0x255D, 0xBC},
{0x255E, 0xC6}, {0x255F, 0xC7}, {0x2560, 0xCC}, {0x2561, 0xB5},
{0x2562, 0xB6}, {0x2563, 0xB9}, {0x2564, 0xD1}, {0x2565, 0xD2},
{0x2566, 0xCB}, {0x2567, 0xCF}, {0x2568, 0xD0}, {0x2569, 0xCA},
{0x256A, 0xD8}, {0x256B, 0xD7}, {0x256C, 0xCE}, {0x2580, 0xDF},
{0x2584, 0xDC}, {0x2588, 0xDB}, {0x258C, 0xDD}, {0x2590, 0xDE},
{0x2591, 0xB0}, {0x2592, 0xB1}, {0x2593, 0xB2}, {0x25A0, 0xFE},
{0x25AC, 0x16}, {0x25B2, 0x1E}, {0x25BA, 0x10}, {0x25BC, 0x1F},
{0x25C4, 0x11}, {0x25CB, 0x09}, {0x25D8, 0x08}, {0x25D9, 0x0A},
{0x263A, 0x01}, {0x263B, 0x02}, {0x263C, 0x0F}, {0x2640, 0x0C},
{0x2642, 0x0B}, {0x2660, 0x06}, {0x2663, 0x05}, {0x2665, 0x03},
{0x2666, 0x04}, {0x266A, 0x0D}, {0x266B, 0x0E}
};
unsigned char
conv_uni_to_pc(unsigned long u) {
/* Binary search - no doubt this can be sped up using hash codes */
/* (or by table lookup if we are in the first half) */
int step = 128;
struct unipc *up = uni_to_pc + step - 1;
while(1) {
if(up->unicode == u)
return up->pc;
step >>= 1;
if(!step)
return NOTFOUND;
if(up->unicode < u)
up += step;
else
up -= step;
}
}
#endif
/*
* linux/drivers/char/vc_screen.c
*
* Provide access to virtual console memory.
* /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
* /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
* [minor: N]
*
* /dev/vcsaN: idem, but including attributes, and prefixed with
* the 4 bytes lines,columns,x,y (as screendump used to give)
* [minor: N+128]
*
* This replaces screendump and part of selection, so that the system
* administrator can control access using file system permissions.
*
* aeb@cwi.nl - efter Friedas begravelse - 950211
*/
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/fs.h>
#include <asm/segment.h>
#include "vt_kern.h"
#include "selection.h"
#define HEADER_SIZE 4
static inline int
vcs_size(struct inode *inode)
{
int size = video_num_lines * video_num_columns;
if (MINOR(inode->i_rdev) & 128)
size = 2*size + HEADER_SIZE;
return size;
}
static int
vcs_lseek(struct inode *inode, struct file *file, off_t offset, int orig)
{
int size = vcs_size(inode);
switch (orig) {
case 0:
file->f_pos = offset;
break;
case 1:
file->f_pos += offset;
break;
case 2:
file->f_pos = size + offset;
break;
default:
return -EINVAL;
}
if (file->f_pos < 0 || file->f_pos > size)
return -EINVAL;
return file->f_pos;
}
static int
vcs_read(struct inode *inode, struct file *file, char *buf, int count)
{
unsigned long p = file->f_pos;
unsigned int cons = MINOR(inode->i_rdev);
int viewed, attr, size, read;
char *buf0;
unsigned short *org;
attr = (cons & 128);
cons = (cons & 127);
if (cons == 0) {
cons = fg_console;
viewed = 1;
} else {
cons--;
viewed = 0;
}
if (!vc_cons_allocated(cons))
return -ENXIO;
size = vcs_size(inode);
if (count < 0 || p > size)
return -EINVAL;
if (count > size - p)
count = size - p;
buf0 = buf;
if (!attr) {
org = screen_pos(cons, p, viewed);
while (count-- > 0)
put_fs_byte(scr_readw(org++) & 0xff, buf++);
} else {
if (p < HEADER_SIZE) {
char header[HEADER_SIZE];
header[0] = (char) video_num_lines;
header[1] = (char) video_num_columns;
getconsxy(cons, header+2);
while (p < HEADER_SIZE && count-- > 0)
put_fs_byte(header[p++], buf++);
}
p -= HEADER_SIZE;
org = screen_pos(cons, p/2, viewed);
if ((p & 1) && count-- > 0)
put_fs_byte(scr_readw(org++) >> 8, buf++);
while (count > 1) {
put_fs_word(scr_readw(org++), buf);
buf += 2;
count -= 2;
}
if (count > 0)
put_fs_byte(scr_readw(org) & 0xff, buf++);
}
read = buf - buf0;
file->f_pos += read;
return read;
}
static int
vcs_write(struct inode *inode, struct file *file, char *buf, int count)
{
unsigned long p = file->f_pos;
unsigned int cons = MINOR(inode->i_rdev);
int viewed, attr, size, written;
char *buf0;
unsigned short *org;
attr = (cons & 128);
cons = (cons & 127);
if (cons == 0) {
cons = fg_console;
viewed = 1;
} else {
cons--;
viewed = 0;
}
if (!vc_cons_allocated(cons))
return -ENXIO;
size = vcs_size(inode);
if (count < 0 || p > size)
return -EINVAL;
if (count > size - p)
count = size - p;
buf0 = buf;
if (!attr) {
org = screen_pos(cons, p, viewed);
while (count-- > 0) {
scr_writew((scr_readw(org) & 0xff00) |
get_fs_byte(buf++), org);
org++;
}
} else {
if (p < HEADER_SIZE) {
char header[HEADER_SIZE];
getconsxy(cons, header+2);
while (p < HEADER_SIZE && count-- > 0)
header[p++] = get_fs_byte(buf++);
if (!viewed)
putconsxy(cons, header+2);
}
p -= HEADER_SIZE;
org = screen_pos(cons, p/2, viewed);
if ((p & 1) && count-- > 0) {
scr_writew((get_fs_byte(buf++) << 8) |
(scr_readw(org) & 0xff), org);
org++;
}
while (count > 1) {
scr_writew(get_fs_word(buf), org++);
buf += 2;
count -= 2;
}
if (count > 0)
scr_writew((scr_readw(org) & 0xff00) |
get_fs_byte(buf++), org);
}
written = buf - buf0;
file->f_pos += written;
return written;
}
static int
vcs_open(struct inode *inode, struct file *filp)
{
unsigned int cons = (MINOR(inode->i_rdev) & 127);
if(cons && !vc_cons_allocated(cons-1))
return -ENXIO;
return 0;
}
static struct file_operations vcs_fops = {
vcs_lseek, /* lseek */
vcs_read, /* read */
vcs_write, /* write */
NULL, /* readdir */
NULL, /* select */
NULL, /* ioctl */
NULL, /* mmap */
vcs_open, /* open */
NULL, /* release */
NULL /* fsync */
};
long vcs_init(long kmem_start)
{
if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
printk("unable to get major %d for vcs device", VCS_MAJOR);
return kmem_start;
}
...@@ -24,10 +24,13 @@ ...@@ -24,10 +24,13 @@
#include "kbd_kern.h" #include "kbd_kern.h"
#include "vt_kern.h" #include "vt_kern.h"
#include "diacr.h" #include "diacr.h"
#include "selection.h"
extern struct tty_driver console_driver; extern struct tty_driver console_driver;
extern int sel_cons;
#define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count) #define VT_IS_IN_USE(i) (console_driver.table[i] && console_driver.table[i]->count)
#define VT_BUSY(i) (VT_IS_IN_USE(i) || i == fg_console || i == sel_cons)
/* /*
* Console (vt and kd) routines, as defined by USL SVR4 manual, and by * Console (vt and kd) routines, as defined by USL SVR4 manual, and by
...@@ -62,6 +65,9 @@ extern unsigned int keymap_count; ...@@ -62,6 +65,9 @@ extern unsigned int keymap_count;
*/ */
extern int con_set_trans(char * table); extern int con_set_trans(char * table);
extern int con_get_trans(char * table); extern int con_get_trans(char * table);
extern void con_clear_unimap(struct unimapinit *ui);
extern int con_set_unimap(ushort ct, struct unipair *list);
extern int con_get_unimap(ushort ct, ushort *uct, struct unipair *list);
extern int con_set_font(char * fontmap); extern int con_set_font(char * fontmap);
extern int con_get_font(char * fontmap); extern int con_get_font(char * fontmap);
...@@ -792,12 +798,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -792,12 +798,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (arg == 0) { if (arg == 0) {
/* disallocate all unused consoles, but leave 0 */ /* disallocate all unused consoles, but leave 0 */
for (i=1; i<MAX_NR_CONSOLES; i++) for (i=1; i<MAX_NR_CONSOLES; i++)
if (! VT_IS_IN_USE(i) && i != fg_console) if (! VT_BUSY(i))
vc_disallocate(i); vc_disallocate(i);
} else { } else {
/* disallocate a single console, if possible */ /* disallocate a single console, if possible */
arg--; arg--;
if (VT_IS_IN_USE(arg) || arg == fg_console) if (VT_BUSY(arg))
return -EBUSY; return -EBUSY;
if (arg) /* leave 0 */ if (arg) /* leave 0 */
vc_disallocate(arg); vc_disallocate(arg);
...@@ -836,11 +842,60 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -836,11 +842,60 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (!perm) if (!perm)
return -EPERM; return -EPERM;
return con_set_trans((char *)arg); return con_set_trans((char *)arg);
/* con_set_trans() defined in console.c */
case GIO_SCRNMAP: case GIO_SCRNMAP:
return con_get_trans((char *)arg); return con_get_trans((char *)arg);
/* con_get_trans() defined in console.c */
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapinit));
if (i)
return i;
memcpy_fromfs(&ui, (void *)arg, sizeof(struct unimapinit));
con_clear_unimap(&ui);
return 0;
}
case PIO_UNIMAP:
{ struct unimapdesc *ud;
u_short ct;
struct unipair *list;
if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct unimapdesc));
if (i == 0) {
ud = (struct unimapdesc *) arg;
ct = get_fs_word(&ud->entry_ct);
list = (struct unipair *) get_fs_long(&ud->entries);
i = verify_area(VERIFY_READ, (void *) list,
ct*sizeof(struct unipair));
}
if (i)
return i;
return con_set_unimap(ct, list);
}
case GIO_UNIMAP:
{ struct unimapdesc *ud;
u_short ct;
struct unipair *list;
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct unimapdesc));
if (i == 0) {
ud = (struct unimapdesc *) arg;
ct = get_fs_word(&ud->entry_ct);
list = (struct unipair *) get_fs_long(&ud->entries);
if (ct)
i = verify_area(VERIFY_WRITE, (void *) list,
ct*sizeof(struct unipair));
}
if (i)
return i;
return con_get_unimap(ct, &(ud->entry_ct), list);
}
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
......
...@@ -270,7 +270,7 @@ el1_probe1(struct device *dev, int ioaddr) ...@@ -270,7 +270,7 @@ el1_probe1(struct device *dev, int ioaddr)
if (autoirq) if (autoirq)
dev->irq = autoirq; dev->irq = autoirq;
printk("%s: %s EtherLink at %#x, using %sIRQ %d.\n", printk("%s: %s EtherLink at %#lx, using %sIRQ %d.\n",
dev->name, mname, dev->base_addr, dev->name, mname, dev->base_addr,
autoirq ? "auto":"assigned ", dev->irq); autoirq ? "auto":"assigned ", dev->irq);
......
...@@ -228,7 +228,7 @@ int el3_probe(struct device *dev) ...@@ -228,7 +228,7 @@ int el3_probe(struct device *dev)
{ {
char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
printk("%s: 3c509 at %#3.3x tag %d, %s port, address ", printk("%s: 3c509 at %#3.3lx tag %d, %s port, address ",
dev->name, dev->base_addr, current_tag, if_names[dev->if_port]); dev->name, dev->base_addr, current_tag, if_names[dev->if_port]);
} }
......
...@@ -1485,7 +1485,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i, ...@@ -1485,7 +1485,7 @@ ppp_ioctl(struct tty_struct *tty, struct file *file, unsigned int i,
error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i)); error = verify_area (VERIFY_WRITE, (void *) l, sizeof (temp_i));
if (error == 0) { if (error == 0) {
put_fs_long (ppp->dev->base_addr, l); put_fs_long (ppp->dev->base_addr, l);
PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %d", ppp->dev->base_addr)); PRINTKN (3,(KERN_INFO "ppp_ioctl: get unit: %ld", ppp->dev->base_addr));
} }
break; break;
......
/* /*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters. * eata.c - Low-level driver for EATA/DMA SCSI host adapters.
* *
* 11 Feb 1995 rev. 1.17 for linux 1.1.91
* Now DEBUG_RESET is disabled by default.
* Register a board even if it does not assert DMA protocol support
* (DPT SK2011B does not report correctly the dmasup bit).
*
* 9 Feb 1995 rev. 1.16 for linux 1.1.90 * 9 Feb 1995 rev. 1.16 for linux 1.1.90
* Use host->wish_block instead of host->block. * Use host->wish_block instead of host->block.
* New list of Data Out SCSI commands. * New list of Data Out SCSI commands.
...@@ -124,6 +129,7 @@ ...@@ -124,6 +129,7 @@
#undef DEBUG_DETECT #undef DEBUG_DETECT
#undef DEBUG_INTERRUPT #undef DEBUG_INTERRUPT
#undef DEBUG_STATISTICS #undef DEBUG_STATISTICS
#undef DEBUG_RESET
#define MAX_TARGET 8 #define MAX_TARGET 8
#define MAX_IRQ 16 #define MAX_IRQ 16
...@@ -390,9 +396,9 @@ static inline int port_detect(ushort *port_base, unsigned int j, ...@@ -390,9 +396,9 @@ static inline int port_detect(ushort *port_base, unsigned int j,
if (*port_base & EISA_RANGE) { if (*port_base & EISA_RANGE) {
if (!info.haaval || info.ata || info.drqvld || !info.dmasup) { if (!info.haaval || info.ata || info.drqvld) {
printk("%s: unusable EISA board found (%d%d%d%d), detaching.\n", printk("%s: unusable EISA board found (%d%d%d), detaching.\n",
name, info.haaval, info.ata, info.drqvld, info.dmasup); name, info.haaval, info.ata, info.drqvld);
return FALSE; return FALSE;
} }
...@@ -401,9 +407,9 @@ static inline int port_detect(ushort *port_base, unsigned int j, ...@@ -401,9 +407,9 @@ static inline int port_detect(ushort *port_base, unsigned int j,
} }
else { else {
if (!info.haaval || info.ata || !info.drqvld || !info.dmasup) { if (!info.haaval || info.ata || !info.drqvld) {
printk("%s: unusable ISA board found (%d%d%d%d), detaching.\n", printk("%s: unusable ISA board found (%d%d%d), detaching.\n",
name, info.haaval, info.ata, info.drqvld, info.dmasup); name, info.haaval, info.ata, info.drqvld);
return FALSE; return FALSE;
} }
...@@ -411,6 +417,9 @@ static inline int port_detect(ushort *port_base, unsigned int j, ...@@ -411,6 +417,9 @@ static inline int port_detect(ushort *port_base, unsigned int j,
dma_channel = dma_channel_table[3 - info.drqx]; dma_channel = dma_channel_table[3 - info.drqx];
} }
if (!info.dmasup)
printk("%s: warning, DMA protocol support not asserted.\n", name);
if (subversion == ESA && !info.irq_tr) if (subversion == ESA && !info.irq_tr)
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
name, irq); name, irq);
...@@ -799,7 +808,11 @@ int eata2x_reset (Scsi_Cmnd *SCarg) { ...@@ -799,7 +808,11 @@ int eata2x_reset (Scsi_Cmnd *SCarg) {
} }
printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)); printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
#if defined (DEBUG_RESET)
do_trace = TRUE; do_trace = TRUE;
#endif
HD(j)->in_reset = TRUE; HD(j)->in_reset = TRUE;
sti(); sti();
time = jiffies; time = jiffies;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include <linux/scsicam.h> #include <linux/scsicam.h>
#define EATA_VERSION "1.16.00" #define EATA_VERSION "1.17.00"
int eata2x_detect(Scsi_Host_Template *); int eata2x_detect(Scsi_Host_Template *);
int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
......
...@@ -44,10 +44,10 @@ ...@@ -44,10 +44,10 @@
* Thanks also to Greg Hosler who did a lot of testing and * * Thanks also to Greg Hosler who did a lot of testing and *
* found quite a number of bugs during the development. * * found quite a number of bugs during the development. *
************************************************************ ************************************************************
* last change: 95/01/30 * * last change: 95/02/13 OS: Linux 1.1.91 or higher *
************************************************************/ ************************************************************/
/* Look in eata_dma.h for configuration information */ /* Look in eata_dma.h for configuration and revision information */
#ifdef MODULE #ifdef MODULE
#include <linux/module.h> #include <linux/module.h>
...@@ -63,12 +63,17 @@ ...@@ -63,12 +63,17 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/dma.h> #include <asm/dma.h>
#include "eata_dma.h" #include "../block/blk.h"
#include "scsi.h" #include "scsi.h"
#include "sd.h" #include "sd.h"
#include "hosts.h"
#include <linux/scsicam.h>
#include "eata_dma.h"
#if 0 #if EATA_DMA_PROC
#include "eata_dma_proc.c" #include "eata_dma_proc.h" /* If you're interested send me a mail */
ulong reads[13]; /* /proc/scsi probably won't get */
ulong writes[13]; /* into the kernel before pl. 1.3 */
#endif #endif
static uint ISAbases[] = static uint ISAbases[] =
...@@ -85,7 +90,7 @@ static unchar reg_IRQL[] = ...@@ -85,7 +90,7 @@ static unchar reg_IRQL[] =
static struct eata_sp status[MAXIRQ]; /* Statuspacket array */ static struct eata_sp status[MAXIRQ]; /* Statuspacket array */
static uint internal_command_finished = TRUE; static uint internal_command_finished = TRUE;
static unchar HBA_interpret = FALSE;
static struct geom_emul geometry; /* Drive 1 & 2 geometry */ static struct geom_emul geometry; /* Drive 1 & 2 geometry */
static ulong int_counter = 0; static ulong int_counter = 0;
...@@ -96,6 +101,10 @@ void eata_scsi_done (Scsi_Cmnd * SCpnt) ...@@ -96,6 +101,10 @@ void eata_scsi_done (Scsi_Cmnd * SCpnt)
return; return;
} }
#if EATA_DMA_PROC
#include "eata_dma_proc.c"
#endif
int eata_release(struct Scsi_Host *sh) int eata_release(struct Scsi_Host *sh)
{ {
if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq); if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
...@@ -235,7 +244,10 @@ void eata_int_handler(int irq, struct pt_regs * regs) ...@@ -235,7 +244,10 @@ void eata_int_handler(int irq, struct pt_regs * regs)
restore_flags(flags); restore_flags(flags);
if(cmd->scsi_done != eata_scsi_done) cmd->scsi_done(cmd); if(cmd->scsi_done != eata_scsi_done) cmd->scsi_done(cmd);
else internal_command_finished = TRUE; else {
internal_command_finished = TRUE;
HBA_interpret = FALSE;
}
save_flags(flags); save_flags(flags);
cli(); cli();
} }
...@@ -337,7 +349,7 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *)) ...@@ -337,7 +349,7 @@ int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
cp->DataIn = TRUE; /* Input mode */ cp->DataIn = TRUE; /* Input mode */
} }
if (done == (void *) eata_scsi_done) if (done == (void *) eata_scsi_done && HBA_interpret == TRUE)
cp->Interpret = TRUE; /* Interpret command */ cp->Interpret = TRUE; /* Interpret command */
if (cmd->use_sg) { if (cmd->use_sg) {
...@@ -699,7 +711,7 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) ...@@ -699,7 +711,7 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
return (FALSE); return (FALSE);
} }
if(gc->HAA_valid == FALSE || ntohl(gc->len) == 0x1c || ntohl(gc->len) == 0x1e) if(gc->HAA_valid == FALSE || ntohl(gc->len) <= 0x1e)
gc->MAX_CHAN = 0; gc->MAX_CHAN = 0;
if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6) if(strncmp("PM2322", &buff[16], 6) && strncmp("PM3021", &buff[16], 6)
...@@ -746,7 +758,6 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) ...@@ -746,7 +758,6 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
"This might be a PM2012 with a defective Firmware\n"); "This might be a PM2012 with a defective Firmware\n");
} }
size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/ size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
(gc->MAX_CHAN + 1)); (gc->MAX_CHAN + 1));
...@@ -824,11 +835,14 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt) ...@@ -824,11 +835,14 @@ int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
else else
hd->primary = TRUE; hd->primary = TRUE;
if (hd->bustype != 'I') if (hd->bustype != 'I') {
sh->unchecked_isa_dma = FALSE; sh->unchecked_isa_dma = FALSE;
else sh->wish_block = FALSE;
}
else {
sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */ sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */
sh->wish_block = TRUE; /* This will reduce performance */
}
if((hd->primary == TRUE) && (i == 0) && HARDCODED){ if((hd->primary == TRUE) && (i == 0) && HARDCODED){
geometry.drv[0].heads = HEADS0; geometry.drv[0].heads = HEADS0;
geometry.drv[0].sectors = SECTORS0; geometry.drv[0].sectors = SECTORS0;
......
...@@ -2,21 +2,16 @@ ...@@ -2,21 +2,16 @@
* Header file for eata_dma.c Linux EATA-DMA SCSI driver * * Header file for eata_dma.c Linux EATA-DMA SCSI driver *
* (c) 1993,94,95 Michael Neuffer * * (c) 1993,94,95 Michael Neuffer *
********************************************************* *********************************************************
* last change: 95/01/30 * * last change: 95/02/13 *
********************************************************/ ********************************************************/
#ifndef _EATA_DMA_H #ifndef _EATA_DMA_H
#define _EATA_DMA_H #define _EATA_DMA_H
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include <linux/scsicam.h>
#define VER_MAJOR 2 #define VER_MAJOR 2
#define VER_MINOR 3 #define VER_MINOR 3
#define VER_SUB "0a" #define VER_SUB "1a"
/************************************************************************ /************************************************************************
* Here you can configure your drives that are using a non-standard * * Here you can configure your drives that are using a non-standard *
...@@ -44,6 +39,7 @@ ...@@ -44,6 +39,7 @@
************************************************************************/ ************************************************************************/
#define CHECKPAL 0 /* EISA pal checking on/off */ #define CHECKPAL 0 /* EISA pal checking on/off */
#define EATA_DMA_PROC 0 /* proc-fs support */
/************************************************************************ /************************************************************************
* Debug options. * * Debug options. *
...@@ -132,19 +128,22 @@ int eata_release(struct Scsi_Host *); ...@@ -132,19 +128,22 @@ int eata_release(struct Scsi_Host *);
#define C_P_L_CURRENT_MAX 10 /* Until this limit in the mm is removed #define C_P_L_CURRENT_MAX 10 /* Until this limit in the mm is removed
* Kernels < 1.1.86 died horrible deaths * Kernels < 1.1.86 died horrible deaths
* if you used values >2. The memory management * if you used values >2. The memory management
* of pl.86 seems to cope with 10. * since pl1.1.86 seems to cope with up to 10
* queued commands per device.
*/ */
#define C_P_L_DIV 4 /* 1 <= C_P_L_DIV <= 8 #define C_P_L_DIV 4 /* 1 <= C_P_L_DIV <= 8
* You can use this parameter to fine-tune * You can use this parameter to fine-tune
* the driver. Depending on the number of * the driver. Depending on the number of
* devices and their ability to queue commands * devices and their speed and ability to queue
* you will get the best results with a value * commands, you will get the best results with a
* value
* ~= numdevices-(devices_unable_to_queue_commands/2) * ~= numdevices-(devices_unable_to_queue_commands/2)
* The reason for this is that the disk driver tents * The reason for this is that the disk driver
* to flood the queue, so that other drivers have * tends to flood the queue, so that other
* problems to queue commands themselves. This can * drivers have problems to queue commands
* for example result in the effect that the tape * themselves. This can for example result in
* stops during disk accesses. * the effect that the tape stops during disk
* accesses.
*/ */
#define FREE 0 #define FREE 0
......
...@@ -216,9 +216,6 @@ int next_scsi_host = 0; ...@@ -216,9 +216,6 @@ int next_scsi_host = 0;
void void
scsi_unregister(struct Scsi_Host * sh){ scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * shpnt; struct Scsi_Host * shpnt;
int j;
j = sh->extra_bytes;
if(scsi_hostlist == sh) if(scsi_hostlist == sh)
scsi_hostlist = sh->next; scsi_hostlist = sh->next;
...@@ -227,8 +224,14 @@ scsi_unregister(struct Scsi_Host * sh){ ...@@ -227,8 +224,14 @@ scsi_unregister(struct Scsi_Host * sh){
while(shpnt->next != sh) shpnt = shpnt->next; while(shpnt->next != sh) shpnt = shpnt->next;
shpnt->next = shpnt->next->next; shpnt->next = shpnt->next->next;
}; };
/* If we are removing the last host registered, it is safe to reuse
its host number (this avoids "holes" at boot time) (DB) */
if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag)
max_scsi_hosts--;
next_scsi_host--; next_scsi_host--;
scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + j); scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes);
} }
/* We call this when we come across a new host adapter. We only do this /* We call this when we come across a new host adapter. We only do this
......
...@@ -307,12 +307,15 @@ void scan_scsis (struct Scsi_Host * shpnt) ...@@ -307,12 +307,15 @@ void scan_scsis (struct Scsi_Host * shpnt)
struct Scsi_Device_Template * sdtpnt; struct Scsi_Device_Template * sdtpnt;
Scsi_Cmnd SCmd; Scsi_Cmnd SCmd;
memset(&SCmd, 0, sizeof(SCmd));
++in_scan_scsis; ++in_scan_scsis;
lun = 0; lun = 0;
type = -1; type = -1;
SCmd.next = NULL; SCmd.next = NULL;
SCmd.prev = NULL; SCmd.prev = NULL;
SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC); SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
SCmd.device = SDpnt; /* This was really needed! (DB) */
memset(SDpnt, 0, sizeof(Scsi_Device));
SDtail = scsi_devices; SDtail = scsi_devices;
if(scsi_devices) { if(scsi_devices) {
while(SDtail->next) SDtail = SDtail->next; while(SDtail->next) SDtail = SDtail->next;
...@@ -1913,33 +1916,48 @@ int scsi_free(void *obj, unsigned int len) ...@@ -1913,33 +1916,48 @@ int scsi_free(void *obj, unsigned int len)
pool */ pool */
static unsigned long scsi_init_memory_start = 0; static unsigned long scsi_init_memory_start = 0;
static unsigned long scsi_memory_lower_value = 0;
static unsigned long scsi_memory_upper_value = 0;
int scsi_loadable_module_flag; /* Set after we scan builtin drivers */ int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
void * scsi_init_malloc(unsigned int size, int priority) void * scsi_init_malloc(unsigned int size, int priority)
{ {
unsigned long retval; unsigned long retval;
if(scsi_loadable_module_flag) { #if 0 /* Use the statically allocated memory instead of kmalloc (DB) */
if(scsi_loadable_module_flag && !(priority & GFP_DMA))
#else
if(scsi_loadable_module_flag)
#endif
retval = (unsigned long) kmalloc(size, priority); retval = (unsigned long) kmalloc(size, priority);
} else { else {
/* /*
* Keep all memory aligned on 16-byte boundaries. Some host adaptors * Keep all memory aligned on 16-byte boundaries. Some host adaptors
* (e.g. BusLogic BT-445S) require DMA buffers to be aligned that way. * (e.g. BusLogic BT-445S) require DMA buffers to be aligned that way.
*/ */
size = (size + 15) & ~15; size = (size + 15) & ~15;
if(scsi_loadable_module_flag &&
(scsi_init_memory_start + size) > scsi_memory_upper_value) {
retval = 0;
printk("scsi_init_malloc: no more statically allocated memory.\n");
}
else {
retval = scsi_init_memory_start; retval = scsi_init_memory_start;
scsi_init_memory_start += size; scsi_init_memory_start += size;
} }
}
return (void *) retval; return (void *) retval;
} }
void scsi_init_free(char * ptr, unsigned int size) void scsi_init_free(char * ptr, unsigned int size)
{ /* FIXME - not right. We need to compare addresses to see whether this was { /* We need to compare addresses to see whether this was kmalloc'd or not */
kmalloc'd or not */
if((unsigned long) ptr > scsi_init_memory_start) { if((unsigned long) ptr >= scsi_init_memory_start ||
kfree(ptr); (unsigned long) ptr < scsi_memory_lower_value) kfree(ptr);
} else { else {
size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc(). */ size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc() */
if(((unsigned long) ptr) + size == scsi_init_memory_start) if(((unsigned long) ptr) + size == scsi_init_memory_start)
scsi_init_memory_start = (unsigned long) ptr; scsi_init_memory_start = (unsigned long) ptr;
} }
...@@ -1967,6 +1985,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end ...@@ -1967,6 +1985,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
scsi_loadable_module_flag = 0; scsi_loadable_module_flag = 0;
/* Align everything on 16-byte boundaries. */ /* Align everything on 16-byte boundaries. */
scsi_init_memory_start = (memory_start + 15) & ~ 15; scsi_init_memory_start = (memory_start + 15) & ~ 15;
scsi_memory_lower_value = scsi_init_memory_start;
timer_table[SCSI_TIMER].fn = scsi_main_timeout; timer_table[SCSI_TIMER].fn = scsi_main_timeout;
timer_table[SCSI_TIMER].expires = 0; timer_table[SCSI_TIMER].expires = 0;
...@@ -2068,7 +2087,20 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end ...@@ -2068,7 +2087,20 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
(*sdtpnt->finish)(); (*sdtpnt->finish)();
scsi_loadable_module_flag = 1; scsi_loadable_module_flag = 1;
#if 0 /* This allocates statically some extra memory to be used for modules,
until the kmalloc problem is fixed (DB) */
scsi_memory_upper_value = scsi_init_memory_start +
2 * (scsi_init_memory_start - scsi_memory_lower_value);
printk ("scsi memory: lower %p, upper %p.\n",
(void *)scsi_memory_lower_value, (void *)scsi_memory_upper_value);
return scsi_memory_upper_value;
#else
return scsi_init_memory_start; return scsi_init_memory_start;
#endif
} }
static void print_inquiry(unsigned char *data) static void print_inquiry(unsigned char *data)
...@@ -2292,7 +2324,8 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt) ...@@ -2292,7 +2324,8 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
commands */ commands */
for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next) for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
if(sdpnt->host->hostt == tpnt && *sdpnt->host->hostt->usage_count) return; if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count
&& *sdpnt->host->hostt->usage_count) return;
for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
{ {
......
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
#define IOCTL_RETRIES 3 #define IOCTL_RETRIES 3
/* The CDROM is fairly slow, so we need a little extra time */ /* The CDROM is fairly slow, so we need a little extra time */
#define IOCTL_TIMEOUT 2000 /* In fact, it is very slow if it has to spin up first */
#define IOCTL_TIMEOUT 3000
extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
#define ST_BLOCK_SIZE 1024 #define ST_BLOCK_SIZE 1024
#define ST_MAX_BUFFERS 2 #define ST_MAX_BUFFERS (2 + ST_EXTRA_DEVS)
#define ST_BUFFER_BLOCKS 32 #define ST_BUFFER_BLOCKS 32
...@@ -1948,7 +1948,7 @@ static void st_init() ...@@ -1948,7 +1948,7 @@ static void st_init()
} }
/* Allocate the buffers */ /* Allocate the buffers */
st_nbr_buffers = st_template.dev_noticed; st_nbr_buffers = st_template.dev_noticed + ST_EXTRA_DEVS;
if (st_nbr_buffers > st_max_buffers) if (st_nbr_buffers > st_max_buffers)
st_nbr_buffers = st_max_buffers; st_nbr_buffers = st_max_buffers;
st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers * st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers *
......
/* /*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
* *
* 11 Feb 1995 rev. 1.17 for linux 1.1.91
* U14F qualified to run with 32 sglists.
* Now DEBUG_RESET is disabled by default.
*
* 9 Feb 1995 rev. 1.16 for linux 1.1.90 * 9 Feb 1995 rev. 1.16 for linux 1.1.90
* Use host->wish_block instead of host->block. * Use host->wish_block instead of host->block.
* *
...@@ -69,8 +73,8 @@ ...@@ -69,8 +73,8 @@
* *
* Here a sample configuration using two U14F boards: * Here a sample configuration using two U14F boards:
* *
U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 16, Mbox 16, CmdLun 2, C1. U14F0: PORT 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, Mbox 16, CmdLun 2, C1.
U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 16, Mbox 16, CmdLun 2, C1. U14F1: PORT 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, Mbox 16, CmdLun 2, C1.
* *
* The boot controller must have its BIOS enabled, while other boards can * The boot controller must have its BIOS enabled, while other boards can
* have their BIOS disabled, or enabled to an higher address. * have their BIOS disabled, or enabled to an higher address.
...@@ -159,12 +163,14 @@ ...@@ -159,12 +163,14 @@
#undef DEBUG_DETECT #undef DEBUG_DETECT
#undef DEBUG_INTERRUPT #undef DEBUG_INTERRUPT
#undef DEBUG_STATISTICS #undef DEBUG_STATISTICS
#undef DEBUG_RESET
#define MAX_TARGET 8 #define MAX_TARGET 8
#define MAX_IRQ 16 #define MAX_IRQ 16
#define MAX_BOARDS 4 #define MAX_BOARDS 4
#define MAX_MAILBOXES 16 #define MAX_MAILBOXES 16
#define MAX_SGLIST 16 #define MAX_SGLIST 32
#define MAX_SAFE_SGLIST 16
#define MAX_CMD_PER_LUN 2 #define MAX_CMD_PER_LUN 2
#define FALSE 0 #define FALSE 0
...@@ -427,7 +433,6 @@ static inline int port_detect(ushort *port_base, unsigned int j, ...@@ -427,7 +433,6 @@ static inline int port_detect(ushort *port_base, unsigned int j,
if (HD(j)->subversion == ESA) { if (HD(j)->subversion == ESA) {
sh[j]->dma_channel = NO_DMA; sh[j]->dma_channel = NO_DMA;
sh[j]->unchecked_isa_dma = FALSE; sh[j]->unchecked_isa_dma = FALSE;
sh[j]->hostt->use_clustering = ENABLE_CLUSTERING;
sprintf(BN(j), "U34F%d", j); sprintf(BN(j), "U34F%d", j);
} }
else { else {
...@@ -435,8 +440,7 @@ static inline int port_detect(ushort *port_base, unsigned int j, ...@@ -435,8 +440,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
#if defined (HAVE_OLD_U14F_FIRMWARE) #if defined (HAVE_OLD_U14F_FIRMWARE)
sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
#else sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
sh[j]->hostt->use_clustering = ENABLE_CLUSTERING;
#endif #endif
sh[j]->dma_channel = dma_channel; sh[j]->dma_channel = dma_channel;
...@@ -456,6 +460,7 @@ static inline int port_detect(ushort *port_base, unsigned int j, ...@@ -456,6 +460,7 @@ static inline int port_detect(ushort *port_base, unsigned int j,
printk("%s: firmware %s is outdated, BIOS rev. should be 2.01.\n", printk("%s: firmware %s is outdated, BIOS rev. should be 2.01.\n",
BN(j), &HD(j)->board_id[32]); BN(j), &HD(j)->board_id[32]);
sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
} }
} }
...@@ -737,7 +742,11 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) { ...@@ -737,7 +742,11 @@ int u14_34f_reset(Scsi_Cmnd * SCarg) {
outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR); outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)); printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
#if defined (DEBUG_RESET)
do_trace = TRUE; do_trace = TRUE;
#endif
HD(j)->in_reset = TRUE; HD(j)->in_reset = TRUE;
sti(); sti();
time = jiffies; time = jiffies;
......
...@@ -10,7 +10,7 @@ int u14_34f_abort(Scsi_Cmnd *); ...@@ -10,7 +10,7 @@ int u14_34f_abort(Scsi_Cmnd *);
int u14_34f_reset(Scsi_Cmnd *); int u14_34f_reset(Scsi_Cmnd *);
int u14_34f_biosparam(Disk *, int, int *); int u14_34f_biosparam(Disk *, int, int *);
#define U14_34F_VERSION "1.16.00" #define U14_34F_VERSION "1.17.00"
#define ULTRASTOR_14_34F { \ #define ULTRASTOR_14_34F { \
NULL, /* Ptr for modules */ \ NULL, /* Ptr for modules */ \
...@@ -31,6 +31,6 @@ int u14_34f_biosparam(Disk *, int, int *); ...@@ -31,6 +31,6 @@ int u14_34f_biosparam(Disk *, int, int *);
0, /* cmd_per_lun, reset by detect */ \ 0, /* cmd_per_lun, reset by detect */ \
0, /* number of boards present */ \ 0, /* number of boards present */ \
1, /* unchecked isa dma, reset by detect */ \ 1, /* unchecked isa dma, reset by detect */ \
0, /* use_clustering, reset by detect */ \ ENABLE_CLUSTERING \
} }
#endif #endif
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/unistd.h> #include <linux/unistd.h>
typedef int (*sysfun_p)(); typedef int (*sysfun_p)(int);
extern sysfun_p sys_call_table[]; extern sysfun_p sys_call_table[];
#define SYS(name) (sys_call_table[__NR_##name]) #define SYS(name) (sys_call_table[__NR_##name])
......
...@@ -15,6 +15,15 @@ ...@@ -15,6 +15,15 @@
* Converted file_lock_table to a linked list from an array, which eliminates * Converted file_lock_table to a linked list from an array, which eliminates
* the limits on how many active file locks are open - Chad Page * the limits on how many active file locks are open - Chad Page
* (pageone@netcom.com), November 27, 1994 * (pageone@netcom.com), November 27, 1994
*
* Removed dependency on file descriptors. dup()'ed file descriptors now
* get the same locks as the original file descriptors, and a close() on
* any file descriptor removes ALL the locks on the file for the current
* process. Since locks still depend on the process id, locks are inherited
* after an exec() but not after a fork(). This agrees with POSIX, and both
* BSD and SVR4 practice.
* Andy Walker (andy@keo.kvaerner.no), February 14, 1994
*
*/ */
#define DEADLOCK_DETECTION #define DEADLOCK_DETECTION
...@@ -30,20 +39,22 @@ ...@@ -30,20 +39,22 @@
#define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */ #define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */
static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l);
unsigned int fd);
static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl); static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl);
static int overlap(struct file_lock *fl1, struct file_lock *fl2); static int overlap(struct file_lock *fl1, struct file_lock *fl2);
static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd); static int lock_it(struct file *filp, struct file_lock *caller);
static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl, static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl);
unsigned int fd);
static void free_lock(struct file_lock **fl); static void free_lock(struct file_lock **fl);
static void free_list_garbage_collect(void);
#ifdef DEADLOCK_DETECTION #ifdef DEADLOCK_DETECTION
int locks_deadlocked(int my_pid,int blocked_pid); int locks_deadlocked(int my_pid,int blocked_pid);
#endif #endif
#define FREE_LIST_GARBAGE_COLLECT 20
static struct file_lock *file_lock_table = NULL; static struct file_lock *file_lock_table = NULL;
static struct file_lock *file_lock_free_list = NULL; static struct file_lock *file_lock_free_list = NULL;
static int free_list_cnt = 0;
int fcntl_getlk(unsigned int fd, struct flock *l) int fcntl_getlk(unsigned int fd, struct flock *l)
{ {
...@@ -60,7 +71,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l) ...@@ -60,7 +71,7 @@ int fcntl_getlk(unsigned int fd, struct flock *l)
memcpy_fromfs(&flock, l, sizeof(flock)); memcpy_fromfs(&flock, l, sizeof(flock));
if (flock.l_type == F_UNLCK) if (flock.l_type == F_UNLCK)
return -EINVAL; return -EINVAL;
if (!copy_flock(filp, &file_lock, &flock, fd)) if (!copy_flock(filp, &file_lock, &flock))
return -EINVAL; return -EINVAL;
for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) { for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
...@@ -102,7 +113,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) ...@@ -102,7 +113,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
if (error) if (error)
return error; return error;
memcpy_fromfs(&flock, l, sizeof(flock)); memcpy_fromfs(&flock, l, sizeof(flock));
if (!copy_flock(filp, &file_lock, &flock, fd)) if (!copy_flock(filp, &file_lock, &flock))
return -EINVAL; return -EINVAL;
switch (file_lock.fl_type) { switch (file_lock.fl_type) {
case F_RDLCK : case F_RDLCK :
...@@ -159,7 +170,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) ...@@ -159,7 +170,7 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
* Lock doesn't conflict with any other lock ... * Lock doesn't conflict with any other lock ...
*/ */
return lock_it(filp, &file_lock, fd); return lock_it(filp, &file_lock);
} }
#ifdef DEADLOCK_DETECTION #ifdef DEADLOCK_DETECTION
...@@ -196,8 +207,7 @@ int locks_deadlocked(int my_pid,int blocked_pid) ...@@ -196,8 +207,7 @@ int locks_deadlocked(int my_pid,int blocked_pid)
* This function is called when the file is closed. * This function is called when the file is closed.
*/ */
void fcntl_remove_locks(struct task_struct *task, struct file *filp, void fcntl_remove_locks(struct task_struct *task, struct file *filp)
unsigned int fd)
{ {
struct file_lock *fl; struct file_lock *fl;
struct file_lock **before; struct file_lock **before;
...@@ -205,12 +215,12 @@ void fcntl_remove_locks(struct task_struct *task, struct file *filp, ...@@ -205,12 +215,12 @@ void fcntl_remove_locks(struct task_struct *task, struct file *filp,
/* Find first lock owned by caller ... */ /* Find first lock owned by caller ... */
before = &filp->f_inode->i_flock; before = &filp->f_inode->i_flock;
while ((fl = *before) && (task != fl->fl_owner || fd != fl->fl_fd)) while ((fl = *before) && task != fl->fl_owner)
before = &fl->fl_next; before = &fl->fl_next;
/* The list is sorted by owner and fd ... */ /* The list is sorted by owner and fd ... */
while ((fl = *before) && task == fl->fl_owner && fd == fl->fl_fd) while ((fl = *before) && task == fl->fl_owner)
free_lock(before); free_lock(before);
} }
...@@ -219,8 +229,7 @@ void fcntl_remove_locks(struct task_struct *task, struct file *filp, ...@@ -219,8 +229,7 @@ void fcntl_remove_locks(struct task_struct *task, struct file *filp,
* Result is a boolean indicating success. * Result is a boolean indicating success.
*/ */
static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l)
unsigned int fd)
{ {
off_t start; off_t start;
...@@ -243,7 +252,6 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, ...@@ -243,7 +252,6 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l,
if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0) if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0)
fl->fl_end = OFFSET_MAX; fl->fl_end = OFFSET_MAX;
fl->fl_owner = current; fl->fl_owner = current;
fl->fl_fd = fd;
fl->fl_wait = NULL; /* just for cleanliness */ fl->fl_wait = NULL; /* just for cleanliness */
return 1; return 1;
} }
...@@ -254,8 +262,7 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, ...@@ -254,8 +262,7 @@ static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l,
static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl)
{ {
if ( caller_fl->fl_owner == sys_fl->fl_owner if (caller_fl->fl_owner == sys_fl->fl_owner)
&& caller_fl->fl_fd == sys_fl->fl_fd)
return 0; return 0;
if (!overlap(caller_fl, sys_fl)) if (!overlap(caller_fl, sys_fl))
return 0; return 0;
...@@ -293,7 +300,7 @@ static int overlap(struct file_lock *fl1, struct file_lock *fl2) ...@@ -293,7 +300,7 @@ static int overlap(struct file_lock *fl1, struct file_lock *fl2)
* To all purists: Yes, I use a few goto's. Just pass on to the next function. * To all purists: Yes, I use a few goto's. Just pass on to the next function.
*/ */
static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) static int lock_it(struct file *filp, struct file_lock *caller)
{ {
struct file_lock *fl; struct file_lock *fl;
struct file_lock *left = 0; struct file_lock *left = 0;
...@@ -306,18 +313,14 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) ...@@ -306,18 +313,14 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
*/ */
before = &filp->f_inode->i_flock; before = &filp->f_inode->i_flock;
while ((fl = *before) && while ((fl = *before) && caller->fl_owner != fl->fl_owner)
(caller->fl_owner != fl->fl_owner ||
caller->fl_fd != fl->fl_fd))
before = &fl->fl_next; before = &fl->fl_next;
/* /*
* Look up all locks of this owner. * Look up all locks of this owner.
*/ */
while ( (fl = *before) while ((fl = *before) && caller->fl_owner == fl->fl_owner) {
&& caller->fl_owner == fl->fl_owner
&& caller->fl_fd == fl->fl_fd) {
/* /*
* Detect adjacent or overlapping regions (if same lock type) * Detect adjacent or overlapping regions (if same lock type)
*/ */
...@@ -417,7 +420,7 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) ...@@ -417,7 +420,7 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
return 0; return 0;
#endif #endif
} }
if (! (caller = alloc_lock(before, caller, fd))) if (! (caller = alloc_lock(before, caller)))
return -ENOLCK; return -ENOLCK;
} }
if (right) { if (right) {
...@@ -427,7 +430,7 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) ...@@ -427,7 +430,7 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
* have to allocate one more lock (in this case, even * have to allocate one more lock (in this case, even
* F_UNLCK may fail!). * F_UNLCK may fail!).
*/ */
if (! (left = alloc_lock(before, right, fd))) { if (! (left = alloc_lock(before, right))) {
if (! added) if (! added)
free_lock(before); free_lock(before);
return -ENOLCK; return -ENOLCK;
...@@ -446,10 +449,8 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) ...@@ -446,10 +449,8 @@ static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd)
* Modified to create a new node if no free entries available - Chad Page * Modified to create a new node if no free entries available - Chad Page
* *
*/ */
static struct file_lock *alloc_lock(struct file_lock **pos, static struct file_lock *alloc_lock(struct file_lock **pos,
struct file_lock *fl, struct file_lock *fl)
unsigned int fd)
{ {
struct file_lock *tmp; struct file_lock *tmp;
...@@ -468,6 +469,7 @@ static struct file_lock *alloc_lock(struct file_lock **pos, ...@@ -468,6 +469,7 @@ static struct file_lock *alloc_lock(struct file_lock **pos,
{ {
/* remove from free list */ /* remove from free list */
file_lock_free_list = tmp->fl_next; file_lock_free_list = tmp->fl_next;
free_list_cnt--;
} }
if (tmp->fl_owner != NULL) if (tmp->fl_owner != NULL)
...@@ -477,7 +479,6 @@ static struct file_lock *alloc_lock(struct file_lock **pos, ...@@ -477,7 +479,6 @@ static struct file_lock *alloc_lock(struct file_lock **pos,
*pos = tmp; *pos = tmp;
tmp->fl_owner = current; /* FIXME: needed? */ tmp->fl_owner = current; /* FIXME: needed? */
tmp->fl_fd = fd; /* FIXME: needed? */
tmp->fl_wait = NULL; tmp->fl_wait = NULL;
tmp->fl_type = fl->fl_type; tmp->fl_type = fl->fl_type;
...@@ -506,5 +507,15 @@ static void free_lock(struct file_lock **fl_p) ...@@ -506,5 +507,15 @@ static void free_lock(struct file_lock **fl_p)
file_lock_free_list = fl; file_lock_free_list = fl;
fl->fl_owner = NULL; /* for sanity checks */ fl->fl_owner = NULL; /* for sanity checks */
free_list_cnt++;
if (free_list_cnt == FREE_LIST_GARBAGE_COLLECT)
free_list_garbage_collect();
wake_up(&fl->fl_wait); wake_up(&fl->fl_wait);
} }
static void free_list_garbage_collect(void)
{
/* Do nothing for now */
return;
}
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/locks.h> #include <linux/locks.h>
extern int close_fp(struct file *filp, unsigned int fd); extern int close_fp(struct file *filp);
static int nfs_notify_change(struct inode *, struct iattr *); static int nfs_notify_change(struct inode *, struct iattr *);
static void nfs_put_inode(struct inode *); static void nfs_put_inode(struct inode *);
...@@ -54,8 +54,7 @@ static void nfs_put_inode(struct inode * inode) ...@@ -54,8 +54,7 @@ static void nfs_put_inode(struct inode * inode)
void nfs_put_super(struct super_block *sb) void nfs_put_super(struct super_block *sb)
{ {
/* No locks should be open on this, so 0 should be safe as a fd. */ close_fp(sb->u.nfs_sb.s_server.file);
close_fp(sb->u.nfs_sb.s_server.file, 0);
lock_super(sb); lock_super(sb);
sb->s_dev = 0; sb->s_dev = 0;
unlock_super(sb); unlock_super(sb);
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include <asm/segment.h> #include <asm/segment.h>
extern void fcntl_remove_locks(struct task_struct *, struct file *, unsigned int fd); extern void fcntl_remove_locks(struct task_struct *, struct file *);
asmlinkage int sys_ustat(int dev, struct ustat * ubuf) asmlinkage int sys_ustat(int dev, struct ustat * ubuf)
{ {
...@@ -477,7 +477,7 @@ asmlinkage int sys_creat(const char * pathname, int mode) ...@@ -477,7 +477,7 @@ asmlinkage int sys_creat(const char * pathname, int mode)
return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
} }
int close_fp(struct file *filp, unsigned int fd) int close_fp(struct file *filp)
{ {
struct inode *inode; struct inode *inode;
...@@ -487,7 +487,7 @@ int close_fp(struct file *filp, unsigned int fd) ...@@ -487,7 +487,7 @@ int close_fp(struct file *filp, unsigned int fd)
} }
inode = filp->f_inode; inode = filp->f_inode;
if (inode) if (inode)
fcntl_remove_locks(current, filp, fd); fcntl_remove_locks(current, filp);
if (filp->f_count > 1) { if (filp->f_count > 1) {
filp->f_count--; filp->f_count--;
return 0; return 0;
...@@ -511,7 +511,7 @@ asmlinkage int sys_close(unsigned int fd) ...@@ -511,7 +511,7 @@ asmlinkage int sys_close(unsigned int fd)
if (!(filp = current->files->fd[fd])) if (!(filp = current->files->fd[fd]))
return -EBADF; return -EBADF;
current->files->fd[fd] = NULL; current->files->fd[fd] = NULL;
return (close_fp (filp, fd)); return (close_fp (filp));
} }
/* /*
......
#define THREE_LEVEL
/* /*
* linux/fs/proc/array.c * linux/fs/proc/array.c
* *
...@@ -334,22 +335,31 @@ static struct task_struct ** get_task(pid_t pid) ...@@ -334,22 +335,31 @@ static struct task_struct ** get_task(pid_t pid)
return NULL; return NULL;
} }
static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr) static unsigned long get_phys_addr(struct task_struct * p, unsigned long ptr)
{ {
pgd_t *dir; pgd_t *page_dir;
pte_t *table, pte; pmd_t *page_middle;
pte_t pte;
if (!p || !*p || ptr >= TASK_SIZE) if (!p || ptr >= TASK_SIZE)
return 0; return 0;
dir = PAGE_DIR_OFFSET(*p,ptr); page_dir = pgd_offset(p,ptr);
if (pgd_none(*dir)) if (pgd_none(*page_dir))
return 0; return 0;
if (pgd_bad(*dir)) { if (pgd_bad(*page_dir)) {
printk("bad page directory entry %08lx\n", pgd_val(*dir)); printk("bad page directory entry %08lx\n", pgd_val(*page_dir));
pgd_clear(page_dir);
return 0; return 0;
} }
table = (pte_t *) (pgd_page(*dir) + PAGE_PTR(ptr)); page_middle = pmd_offset(page_dir,ptr);
pte = *table; if (pmd_none(*page_middle))
return 0;
if (pmd_bad(*page_middle)) {
printk("bad page middle entry %08lx\n", pmd_val(*page_middle));
pmd_clear(page_middle);
return 0;
}
pte = *pte_offset(page_middle,ptr);
if (!pte_present(pte)) if (!pte_present(pte))
return 0; return 0;
return pte_page(pte) + (ptr & ~PAGE_MASK); return pte_page(pte) + (ptr & ~PAGE_MASK);
...@@ -364,7 +374,7 @@ static int get_array(struct task_struct ** p, unsigned long start, unsigned long ...@@ -364,7 +374,7 @@ static int get_array(struct task_struct ** p, unsigned long start, unsigned long
if (start >= end) if (start >= end)
return result; return result;
for (;;) { for (;;) {
addr = get_phys_addr(p, start); addr = get_phys_addr(*p, start);
if (!addr) if (!addr)
goto ready; goto ready;
do { do {
...@@ -512,53 +522,107 @@ static int get_stat(int pid, char * buffer) ...@@ -512,53 +522,107 @@ static int get_stat(int pid, char * buffer)
wchan); wchan);
} }
static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
int * pages, int * shared, int * dirty, int * total)
{
pte_t * pte;
unsigned long end;
if (pmd_none(*pmd))
return;
if (pmd_bad(*pmd)) {
printk("statm_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
pmd_clear(pmd);
return;
}
pte = pte_offset(pmd, address);
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
pte_t page = *pte;
address += PAGE_SIZE;
pte++;
if (pte_none(page))
continue;
++*total;
if (!pte_present(page))
continue;
++*pages;
if (pte_dirty(page))
++*dirty;
if (pte_page(page) >= high_memory)
continue;
if (mem_map[MAP_NR(pte_page(page))] > 1)
++*shared;
} while (address < end);
}
static inline void statm_pmd_range(pgd_t * pgd, unsigned long address, unsigned long size,
int * pages, int * shared, int * dirty, int * total)
{
pmd_t * pmd;
unsigned long end;
if (pgd_none(*pgd))
return;
if (pgd_bad(*pgd)) {
printk("statm_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
pgd_clear(pgd);
return;
}
pmd = pmd_offset(pgd, address);
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
do {
statm_pte_range(pmd, address, end - address, pages, shared, dirty, total);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
}
static void statm_pgd_range(pgd_t * pgd, unsigned long address, unsigned long end,
int * pages, int * shared, int * dirty, int * total)
{
while (address < end) {
statm_pmd_range(pgd, address, end - address, pages, shared, dirty, total);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
pgd++;
}
}
static int get_statm(int pid, char * buffer) static int get_statm(int pid, char * buffer)
{ {
struct task_struct ** p = get_task(pid); struct task_struct ** p = get_task(pid);
pgd_t *pagedir;
pte_t *pte;
int i, j, tpag;
int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0;
if (!p || !*p) if (!p || !*p)
return 0; return 0;
tpag = (*p)->mm->end_code / PAGE_SIZE;
if ((*p)->state != TASK_ZOMBIE) { if ((*p)->state != TASK_ZOMBIE) {
pagedir = PAGE_DIR_OFFSET(*p, 0); struct vm_area_struct * vma = (*p)->mm->mmap;
for (i = 0; i < 0x300; ++i) {
if (pgd_none(pagedir[i])) { while (vma) {
tpag -= PTRS_PER_PAGE; pgd_t *pgd = pgd_offset(*p, vma->vm_start);
continue; int pages = 0, shared = 0, dirty = 0, total = 0;
}
if (pgd_bad(pagedir[i])) { statm_pgd_range(pgd, vma->vm_start, vma->vm_end, &pages, &shared, &dirty, &total);
printk("bad page table dir %08lx\n", pgd_val(pagedir[i])); resident += pages;
pgd_clear(pagedir+i); share += shared;
tpag -= PTRS_PER_PAGE; dt += dirty;
continue; size += total;
} if (vma->vm_flags & VM_EXECUTABLE)
pte = (pte_t *) pgd_page(pagedir[i]); trs += pages; /* text */
for (j = 0; j < PTRS_PER_PAGE; j++, pte++) { else if (vma->vm_flags & VM_GROWSDOWN)
if (!pte_none(*pte)) { drs += pages; /* stack */
++size; else if (vma->vm_end > 0x60000000)
if (pte_present(*pte)) { lrs += pages; /* library */
++resident;
if (tpag > 0)
++trs;
else else
++drs; drs += pages;
if (i >= 15 && i < 0x2f0) { vma = vma->vm_next;
++lrs;
if (pte_dirty(*pte))
++dt;
else
--drs;
}
if (pte_page(*pte) < high_memory && mem_map[MAP_NR(pte_page(*pte))] > 1)
++share;
}
}
--tpag;
}
} }
} }
return sprintf(buffer,"%d %d %d %d %d %d %d\n", return sprintf(buffer,"%d %d %d %d %d %d %d\n",
......
...@@ -81,7 +81,6 @@ extern unsigned long rdusp(void); ...@@ -81,7 +81,6 @@ extern unsigned long rdusp(void);
#define halt() __asm__ __volatile__(".long 0"); #define halt() __asm__ __volatile__(".long 0");
#define move_to_user_mode() printk("Null move_to_user_mode\n")
#define switch_to(x) panic("switch_to() not yet done") #define switch_to(x) panic("switch_to() not yet done")
#ifndef mb #ifndef mb
......
...@@ -132,12 +132,18 @@ extern inline int pte_none(pte_t pte) { return !pte_val(pte); } ...@@ -132,12 +132,18 @@ extern inline int pte_none(pte_t pte) { return !pte_val(pte); }
extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; }
extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] > 1; } extern inline int pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)] > 1; }
extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
extern inline void pte_reuse(pte_t * ptep)
{
if (!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
mem_map[MAP_NR(ptep)]++;
}
extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); } extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; } extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; }
extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; } extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; }
extern inline int pmd_inuse(pmd_t *pmdp) { return 0; } extern inline int pmd_inuse(pmd_t *pmdp) { return 0; }
extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; } extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; }
extern inline void pmd_reuse(pmd_t * pmdp) { }
#ifdef THREE_LEVEL #ifdef THREE_LEVEL
/* /*
...@@ -150,6 +156,11 @@ extern inline int pgd_bad(pgd_t pgd) { return 0; } ...@@ -150,6 +156,11 @@ extern inline int pgd_bad(pgd_t pgd) { return 0; }
extern inline int pgd_present(pgd_t pgd) { return 1; } extern inline int pgd_present(pgd_t pgd) { return 1; }
extern inline int pgd_inuse(pgd_t * pgdp) { return mem_map[MAP_NR(pgdp)] > 1; } extern inline int pgd_inuse(pgd_t * pgdp) { return mem_map[MAP_NR(pgdp)] > 1; }
extern inline void pgd_clear(pgd_t * pgdp) { } extern inline void pgd_clear(pgd_t * pgdp) { }
extern inline void pgd_reuse(pgd_t * pgdp)
{
if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
mem_map[MAP_NR(pgdp)]++;
}
#else #else
/* /*
* These are the old (and incorrect) ones needed for code that doesn't * These are the old (and incorrect) ones needed for code that doesn't
......
...@@ -3,21 +3,6 @@ ...@@ -3,21 +3,6 @@
#include <asm/segment.h> #include <asm/segment.h>
#define move_to_user_mode() \
__asm__ __volatile__ ("movl %%esp,%%eax\n\t" \
"pushl %0\n\t" \
"pushl %%eax\n\t" \
"pushfl\n\t" \
"pushl %1\n\t" \
"pushl $1f\n\t" \
"iret\n" \
"1:\tmovl %0,%%eax\n\t" \
"mov %%ax,%%ds\n\t" \
"mov %%ax,%%es\n\t" \
"mov %%ax,%%fs\n\t" \
"mov %%ax,%%gs" \
: /* no outputs */ :"i" (USER_DS), "i" (USER_CS):"ax")
/* /*
* Entry into gdt where to find first TSS. GDT layout: * Entry into gdt where to find first TSS. GDT layout:
* 0 - nul * 0 - nul
......
...@@ -269,7 +269,6 @@ struct file_lock { ...@@ -269,7 +269,6 @@ struct file_lock {
struct file_lock *fl_next; /* singly linked list */ struct file_lock *fl_next; /* singly linked list */
struct file_lock *fl_nextlink; struct file_lock *fl_nextlink;
struct task_struct *fl_owner; /* NULL if on free list, for sanity checks */ struct task_struct *fl_owner; /* NULL if on free list, for sanity checks */
unsigned int fl_fd; /* File descriptor for this lock */
struct wait_queue *fl_wait; struct wait_queue *fl_wait;
char fl_type; char fl_type;
char fl_whence; char fl_whence;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* 4 - /dev/tty* * 4 - /dev/tty*
* 5 - /dev/tty; /dev/cua* * 5 - /dev/tty; /dev/cua*
* 6 - lp * 6 - lp
* 7 - UNUSED * 7 - /dev/vcs*
* 8 - scsi disk * 8 - scsi disk
* 9 - scsi tape * 9 - scsi tape
* 10 - mice * 10 - mice
...@@ -57,7 +57,7 @@ ...@@ -57,7 +57,7 @@
#define TTY_MAJOR 4 #define TTY_MAJOR 4
#define TTYAUX_MAJOR 5 #define TTYAUX_MAJOR 5
#define LP_MAJOR 6 #define LP_MAJOR 6
/* unused: 7 */ #define VCS_MAJOR 7
#define SCSI_DISK_MAJOR 8 #define SCSI_DISK_MAJOR 8
#define SCSI_TAPE_MAJOR 9 #define SCSI_TAPE_MAJOR 9
#define MOUSE_MAJOR 10 #define MOUSE_MAJOR 10
......
...@@ -185,7 +185,7 @@ extern void do_no_page(struct vm_area_struct * vma, unsigned long address, int w ...@@ -185,7 +185,7 @@ extern void do_no_page(struct vm_area_struct * vma, unsigned long address, int w
extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem); extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem);
extern void mem_init(unsigned long start_mem, unsigned long end_mem); extern void mem_init(unsigned long start_mem, unsigned long end_mem);
extern void show_mem(void); extern void show_mem(void);
extern void oom(struct task_struct * task); extern void oom(struct task_struct * tsk);
extern void si_meminfo(struct sysinfo * val); extern void si_meminfo(struct sysinfo * val);
/* vmalloc.c */ /* vmalloc.c */
......
...@@ -278,6 +278,10 @@ extern long lp_init(long); ...@@ -278,6 +278,10 @@ extern long lp_init(long);
extern long con_init(long); extern long con_init(long);
extern long pty_init(long); extern long pty_init(long);
extern long tty_init(long); extern long tty_init(long);
extern long vcs_init(long);
#ifdef CONFIG_CYCLADES
extern long cy_init(long);
#endif
extern int tty_paranoia_check(struct tty_struct *tty, dev_t device, extern int tty_paranoia_check(struct tty_struct *tty, dev_t device,
const char *routine); const char *routine);
......
...@@ -420,7 +420,6 @@ asmlinkage void start_kernel(void) ...@@ -420,7 +420,6 @@ asmlinkage void start_kernel(void)
printk(linux_banner); printk(linux_banner);
move_to_user_mode();
if (!fork()) /* we count on this going ok */ if (!fork()) /* we count on this going ok */
init(); init();
/* /*
......
...@@ -67,7 +67,7 @@ extern int sys_tz; ...@@ -67,7 +67,7 @@ extern int sys_tz;
extern int request_dma(unsigned int dmanr, char * deviceID); extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr); extern void free_dma(unsigned int dmanr);
extern int close_fp(struct file *filp, unsigned int fd); extern int close_fp(struct file *filp);
extern void (* iABI_hook)(struct pt_regs * regs); extern void (* iABI_hook)(struct pt_regs * regs);
struct symbol_table symbol_table = { struct symbol_table symbol_table = {
......
#define THREE_LEVEL
/* /*
* linux/mm/filemmap.c * linux/mm/filemmap.c
* *
...@@ -28,7 +29,7 @@ ...@@ -28,7 +29,7 @@
* though. * though.
*/ */
static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned long address, static unsigned long filemap_nopage(struct vm_area_struct * area, unsigned long address,
unsigned long page, int no_share) unsigned long page, int no_share)
{ {
struct inode * inode = area->vm_inode; struct inode * inode = area->vm_inode;
...@@ -61,12 +62,13 @@ static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned lon ...@@ -61,12 +62,13 @@ static unsigned long file_mmap_nopage(struct vm_area_struct * area, unsigned lon
* - the "swapout()" function needs to swap out the page to * - the "swapout()" function needs to swap out the page to
* the shared file instead of using the swap device. * the shared file instead of using the swap device.
*/ */
static inline void file_mmap_sync_page(struct vm_area_struct * vma, static void filemap_sync_page(struct vm_area_struct * vma,
unsigned long offset, unsigned long offset,
unsigned long page) unsigned long page)
{ {
struct buffer_head * bh; struct buffer_head * bh;
printk("msync: %ld: [%08lx]\n", offset, page);
bh = buffer_pages[MAP_NR(page)]; bh = buffer_pages[MAP_NR(page)];
if (bh) { if (bh) {
/* whee.. just mark the buffer heads dirty */ /* whee.. just mark the buffer heads dirty */
...@@ -78,60 +80,94 @@ static inline void file_mmap_sync_page(struct vm_area_struct * vma, ...@@ -78,60 +80,94 @@ static inline void file_mmap_sync_page(struct vm_area_struct * vma,
return; return;
} }
/* we'll need to go fetch the buffer heads etc.. RSN */ /* we'll need to go fetch the buffer heads etc.. RSN */
printk("msync: %ld: [%08lx]\n", offset, page);
printk("Can't handle non-shared page yet\n"); printk("Can't handle non-shared page yet\n");
return; return;
} }
static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start, static inline void filemap_sync_pte(pte_t * pte, struct vm_area_struct *vma,
size_t size, unsigned int flags) unsigned long address, unsigned int flags)
{ {
pgd_t * dir; pte_t page = *pte;
unsigned long poff, pcnt;
if (!pte_present(page))
size = size >> PAGE_SHIFT; return;
dir = PAGE_DIR_OFFSET(current,start); if (!pte_dirty(page))
poff = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); return;
start -= vma->vm_start;
pcnt = PTRS_PER_PAGE - poff;
if (pcnt > size)
pcnt = size;
for ( ; size > 0; ++dir, size -= pcnt, pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
pte_t *page_table;
unsigned long pc;
if (pgd_none(*dir)) {
poff = 0;
start += pcnt*PAGE_SIZE;
continue;
}
if (pgd_bad(*dir)) {
printk("file_mmap_sync: bad page directory entry %08lx.\n", pgd_val(*dir));
pgd_clear(dir);
poff = 0;
start += pcnt*PAGE_SIZE;
continue;
}
page_table = poff + (pte_t *) pgd_page(*dir);
poff = 0;
for (pc = pcnt; pc--; page_table++, start += PAGE_SIZE) {
pte_t pte;
pte = *page_table;
if (!pte_present(pte))
continue;
if (!pte_dirty(pte))
continue;
if (flags & MS_INVALIDATE) { if (flags & MS_INVALIDATE) {
pte_clear(page_table); pte_clear(pte);
} else { } else {
mem_map[MAP_NR(pte_page(pte))]++; mem_map[MAP_NR(pte_page(page))]++;
*page_table = pte_mkclean(pte); *pte = pte_mkclean(page);
} }
file_mmap_sync_page(vma, start, pte_page(pte)); filemap_sync_page(vma, address - vma->vm_start, pte_page(page));
free_page(pte_page(pte)); free_page(pte_page(page));
}
static inline void filemap_sync_pte_range(pmd_t * pmd,
unsigned long address, unsigned long size,
struct vm_area_struct *vma, unsigned long offset, unsigned int flags)
{
pte_t * pte;
unsigned long end;
if (pmd_none(*pmd))
return;
if (pmd_bad(*pmd)) {
printk("filemap_sync_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
pmd_clear(pmd);
return;
} }
pte = pte_offset(pmd, address);
offset += address & PMD_MASK;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
filemap_sync_pte(pte, vma, address + offset, flags);
address += PAGE_SIZE;
pte++;
} while (address < end);
}
static inline void filemap_sync_pmd_range(pgd_t * pgd,
unsigned long address, unsigned long size,
struct vm_area_struct *vma, unsigned int flags)
{
pmd_t * pmd;
unsigned long offset, end;
if (pgd_none(*pgd))
return;
if (pgd_bad(*pgd)) {
printk("filemap_sync_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
pgd_clear(pgd);
return;
}
pmd = pmd_offset(pgd, address);
offset = address & PMD_MASK;
address &= ~PMD_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
do {
filemap_sync_pte_range(pmd, address, end - address, vma, offset, flags);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
}
static void filemap_sync(struct vm_area_struct * vma, unsigned long address,
size_t size, unsigned int flags)
{
pgd_t * dir;
unsigned long end = address + size;
dir = pgd_offset(current, address);
while (address < end) {
filemap_sync_pmd_range(dir, address, end - address, vma, flags);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
} }
invalidate(); invalidate();
return; return;
...@@ -140,17 +176,17 @@ static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start, ...@@ -140,17 +176,17 @@ static void file_mmap_sync(struct vm_area_struct * vma, unsigned long start,
/* /*
* This handles area unmaps.. * This handles area unmaps..
*/ */
static void file_mmap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len) static void filemap_unmap(struct vm_area_struct *vma, unsigned long start, size_t len)
{ {
file_mmap_sync(vma, start, len, MS_ASYNC); filemap_sync(vma, start, len, MS_ASYNC);
} }
/* /*
* This handles complete area closes.. * This handles complete area closes..
*/ */
static void file_mmap_close(struct vm_area_struct * vma) static void filemap_close(struct vm_area_struct * vma)
{ {
file_mmap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC); filemap_sync(vma, vma->vm_start, vma->vm_end - vma->vm_start, MS_ASYNC);
} }
/* /*
...@@ -160,7 +196,7 @@ static void file_mmap_close(struct vm_area_struct * vma) ...@@ -160,7 +196,7 @@ static void file_mmap_close(struct vm_area_struct * vma)
* so we have to either write it out or just forget it. We currently * so we have to either write it out or just forget it. We currently
* forget it.. * forget it..
*/ */
void file_mmap_swapout(struct vm_area_struct * vma, void filemap_swapout(struct vm_area_struct * vma,
unsigned long offset, unsigned long offset,
pte_t *page_table) pte_t *page_table)
{ {
...@@ -175,14 +211,14 @@ void file_mmap_swapout(struct vm_area_struct * vma, ...@@ -175,14 +211,14 @@ void file_mmap_swapout(struct vm_area_struct * vma,
*/ */
static struct vm_operations_struct file_shared_mmap = { static struct vm_operations_struct file_shared_mmap = {
NULL, /* open */ NULL, /* open */
file_mmap_close, /* close */ filemap_close, /* close */
file_mmap_unmap, /* unmap */ filemap_unmap, /* unmap */
NULL, /* protect */ NULL, /* protect */
file_mmap_sync, /* sync */ filemap_sync, /* sync */
NULL, /* advise */ NULL, /* advise */
file_mmap_nopage, /* nopage */ filemap_nopage, /* nopage */
NULL, /* wppage */ NULL, /* wppage */
file_mmap_swapout, /* swapout */ filemap_swapout, /* swapout */
NULL, /* swapin */ NULL, /* swapin */
}; };
...@@ -199,7 +235,7 @@ static struct vm_operations_struct file_private_mmap = { ...@@ -199,7 +235,7 @@ static struct vm_operations_struct file_private_mmap = {
NULL, /* protect */ NULL, /* protect */
NULL, /* sync */ NULL, /* sync */
NULL, /* advise */ NULL, /* advise */
file_mmap_nopage, /* nopage */ filemap_nopage, /* nopage */
NULL, /* wppage */ NULL, /* wppage */
NULL, /* swapout */ NULL, /* swapout */
NULL, /* swapin */ NULL, /* swapin */
...@@ -221,9 +257,11 @@ int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct ...@@ -221,9 +257,11 @@ int generic_mmap(struct inode * inode, struct file * file, struct vm_area_struct
if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) { if (vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) {
static int nr = 0; static int nr = 0;
ops = &file_shared_mmap; ops = &file_shared_mmap;
#ifndef SHARED_MMAP_REALLY_WORKS /* it doesn't, yet */
if (nr++ < 5) if (nr++ < 5)
printk("%s tried to do a shared writeable mapping\n", current->comm); printk("%s tried to do a shared writeable mapping\n", current->comm);
return -EINVAL; return -EINVAL;
#endif
} }
} }
if (!IS_RDONLY(inode)) { if (!IS_RDONLY(inode)) {
......
...@@ -222,7 +222,7 @@ int clone_page_tables(struct task_struct * tsk) ...@@ -222,7 +222,7 @@ int clone_page_tables(struct task_struct * tsk)
pgd_t * pg_dir; pgd_t * pg_dir;
pg_dir = pgd_offset(current, 0); pg_dir = pgd_offset(current, 0);
mem_map[MAP_NR(pg_dir)]++; pgd_reuse(pg_dir);
SET_PAGE_DIR(tsk, pg_dir); SET_PAGE_DIR(tsk, pg_dir);
return 0; return 0;
} }
...@@ -265,6 +265,7 @@ static inline int copy_one_pmd(pmd_t * old_pmd, pmd_t * new_pmd) ...@@ -265,6 +265,7 @@ static inline int copy_one_pmd(pmd_t * old_pmd, pmd_t * new_pmd)
} }
old_pte = pte_offset(old_pmd, 0); old_pte = pte_offset(old_pmd, 0);
if (pte_inuse(old_pte)) { if (pte_inuse(old_pte)) {
pte_reuse(old_pte);
*new_pmd = *old_pmd; *new_pmd = *old_pmd;
return 0; return 0;
} }
...@@ -293,6 +294,7 @@ static inline int copy_one_pgd(pgd_t * old_pgd, pgd_t * new_pgd) ...@@ -293,6 +294,7 @@ static inline int copy_one_pgd(pgd_t * old_pgd, pgd_t * new_pgd)
} }
old_pmd = pmd_offset(old_pgd, 0); old_pmd = pmd_offset(old_pgd, 0);
if (pmd_inuse(old_pmd)) { if (pmd_inuse(old_pmd)) {
pmd_reuse(old_pmd);
*new_pgd = *old_pgd; *new_pgd = *old_pgd;
return 0; return 0;
} }
......
#define THREE_LEVEL
/* /*
* linux/mm/mprotect.c * linux/mm/mprotect.c
* *
...@@ -17,44 +18,69 @@ ...@@ -17,44 +18,69 @@
#include <asm/system.h> #include <asm/system.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot) static inline void change_pte_range(pmd_t * pmd, unsigned long address,
unsigned long size, pgprot_t newprot)
{ {
pgd_t *dir; pte_t * pte;
pte_t *page_table, entry; unsigned long end;
unsigned long offset;
int nr; if (pmd_none(*pmd))
return;
dir = PAGE_DIR_OFFSET(current, start); if (pmd_bad(*pmd)) {
offset = (start >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); printk("change_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
nr = (end - start) >> PAGE_SHIFT; pmd_clear(pmd);
while (nr > 0) { return;
if (pgd_none(*dir)) {
dir++;
nr = nr - PTRS_PER_PAGE + offset;
offset = 0;
continue;
}
if (pgd_bad(*dir)) {
printk("Bad page dir entry %08lx\n", pgd_val(*dir));
pgd_clear(dir);
dir++;
nr = nr - PTRS_PER_PAGE + offset;
offset = 0;
continue;
} }
page_table = offset + (pte_t *) pgd_page(*dir); pte = pte_offset(pmd, address);
offset = PTRS_PER_PAGE - offset; address &= ~PMD_MASK;
if (offset > nr) end = address + size;
offset = nr; if (end > PMD_SIZE)
nr = nr - offset; end = PMD_SIZE;
do { do {
entry = *page_table; pte_t entry = *pte;
if (pte_present(entry)) if (pte_present(entry))
*page_table = pte_modify(entry, newprot); *pte = pte_modify(entry, newprot);
++page_table; address += PAGE_SIZE;
} while (--offset); pte++;
} while (address < end);
}
static inline void change_pmd_range(pgd_t * pgd, unsigned long address,
unsigned long size, pgprot_t newprot)
{
pmd_t * pmd;
unsigned long end;
if (pgd_none(*pgd))
return;
if (pgd_bad(*pgd)) {
printk("change_pmd_range: bad pgd (%08lx)\n", pgd_val(*pgd));
pgd_clear(pgd);
return;
}
pmd = pmd_offset(pgd, address);
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
do {
change_pte_range(pmd, address, end - address, newprot);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
}
static void change_protection(unsigned long start, unsigned long end, pgprot_t newprot)
{
pgd_t *dir;
dir = pgd_offset(current, start);
while (start < end) {
change_pmd_range(dir, start, end - start, newprot);
start = (start + PGDIR_SIZE) & PGDIR_MASK;
dir++; dir++;
} }
invalidate();
return; return;
} }
......
#define THREE_LEVEL
/* /*
* linux/mm/swap.c * linux/mm/swap.c
* *
...@@ -387,11 +388,89 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, p ...@@ -387,11 +388,89 @@ static inline int try_to_swap_out(struct vm_area_struct* vma, unsigned offset, p
*/ */
#define SWAP_RATIO 128 #define SWAP_RATIO 128
static inline int swap_out_pmd(struct vm_area_struct * vma, pmd_t *dir,
unsigned long address, unsigned long size, unsigned long offset)
{
pte_t * pte;
unsigned long end;
if (pmd_none(*dir))
return 0;
if (pmd_bad(*dir)) {
printk("swap_out_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
pmd_clear(dir);
return 0;
}
pte = pte_offset(dir, address);
offset += address & PMD_MASK;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
switch (try_to_swap_out(vma, offset+address-vma->vm_start, pte)) {
case 0:
break;
case 1:
vma->vm_task->mm->rss--;
/* continue with the following page the next time */
vma->vm_task->mm->swap_address = address + offset + PAGE_SIZE;
return 1;
default:
vma->vm_task->mm->rss--;
break;
}
address += PAGE_SIZE;
pte++;
} while (address < end);
return 0;
}
static inline int swap_out_pgd(struct vm_area_struct * vma, pgd_t *dir,
unsigned long address, unsigned long size)
{
pmd_t * pmd;
unsigned long offset, end;
if (pgd_none(*dir))
return 0;
if (pgd_bad(*dir)) {
printk("swap_out_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
pgd_clear(dir);
return 0;
}
pmd = pmd_offset(dir, address);
offset = address & PGDIR_MASK;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
do {
if (swap_out_pmd(vma, pmd, address, end - address, offset))
return 1;
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
return 0;
}
static int swap_out_vma(struct vm_area_struct * vma, pgd_t *pgdir,
unsigned long start, unsigned long end)
{
while (start < end) {
if (swap_out_pgd(vma, pgdir, start, end - start))
return 1;
start = (start + PGDIR_SIZE) & PGDIR_MASK;
pgdir++;
}
return 0;
}
static int swap_out_process(struct task_struct * p) static int swap_out_process(struct task_struct * p)
{ {
pgd_t *pgdir;
unsigned long address; unsigned long address;
unsigned long offset;
struct vm_area_struct* vma; struct vm_area_struct* vma;
/* /*
...@@ -409,60 +488,14 @@ static int swap_out_process(struct task_struct * p) ...@@ -409,60 +488,14 @@ static int swap_out_process(struct task_struct * p)
if (address < vma->vm_start) if (address < vma->vm_start)
address = vma->vm_start; address = vma->vm_start;
pgdir = PAGE_DIR_OFFSET(p, address);
offset = address & ~PGDIR_MASK;
address &= PGDIR_MASK;
for ( ; address < TASK_SIZE ; pgdir++, address = address + PGDIR_SIZE, offset = 0) {
pte_t *pg_table;
if (pgd_none(*pgdir))
continue;
if (pgd_bad(*pgdir)) {
printk("Bad page directory at address %08lx: %08lx\n", address, pgd_val(*pgdir));
pgd_clear(pgdir);
continue;
}
pg_table = (pte_t *) pgd_page(*pgdir);
if (mem_map[MAP_NR((unsigned long) pg_table)] & MAP_PAGE_RESERVED)
continue;
pg_table += offset >> PAGE_SHIFT;
/*
* Go through this page table.
*/
for( ; offset < ~PGDIR_MASK ; pg_table++, offset += PAGE_SIZE) {
/*
* Update vma again..
*/
for (;;) { for (;;) {
if (address+offset < vma->vm_end) if (swap_out_vma(vma, pgd_offset(p, address), address, vma->vm_end))
break; return 1;
vma = vma->vm_next; vma = vma->vm_next;
if (!vma) if (!vma)
return 0; return 0;
address = vma->vm_start;
} }
switch(try_to_swap_out(vma, offset+address-vma->vm_start, pg_table)) {
case 0:
break;
case 1:
p->mm->rss--;
/* continue with the following page the next time */
p->mm->swap_address = address + offset + PAGE_SIZE;
return 1;
default:
p->mm->rss--;
break;
}
}
}
/*
* Finish work with this process, if we reached the end of the page
* directory.
*/
return 0;
} }
static int swap_out(unsigned int priority) static int swap_out(unsigned int priority)
...@@ -748,77 +781,157 @@ void show_free_areas(void) ...@@ -748,77 +781,157 @@ void show_free_areas(void)
/* /*
* Trying to stop swapping from a file is fraught with races, so * Trying to stop swapping from a file is fraught with races, so
* we repeat quite a bit here when we have to pause. swapoff() * we repeat quite a bit here when we have to pause. swapoff()
* isn't exactly timing-critical, so who cares? * isn't exactly timing-critical, so who cares (but this is /really/
* inefficient, ugh).
*
* We return 1 after having slept, which makes the process start over
* from the beginning for this process..
*/ */
static int try_to_unuse(unsigned int type) static inline int unuse_pte(struct vm_area_struct * vma, unsigned long address,
pte_t *dir, unsigned int type, unsigned long page)
{ {
int nr; pte_t pte = *dir;
unsigned long tmp = 0;
struct task_struct *p;
nr = 0;
/*
* When we have to sleep, we restart the whole algorithm from the same
* task we stopped in. That at least rids us of all races.
*/
repeat:
for (; nr < NR_TASKS ; nr++) {
pgd_t * page_dir;
int i;
p = task[nr];
if (!p)
continue;
page_dir = PAGE_DIR_OFFSET(p, 0);
for (i = 0 ; i < PTRS_PER_PAGE ; page_dir++, i++) {
int j;
pte_t *page_table;
if (pgd_none(*page_dir))
continue;
if (pgd_bad(*page_dir)) {
printk("bad page directory entry [%d] %08lx\n", i, pgd_val(*page_dir));
pgd_clear(page_dir);
continue;
}
page_table = (pte_t *) pgd_page(*page_dir);
if (mem_map[MAP_NR((unsigned long) page_table)] & MAP_PAGE_RESERVED)
continue;
for (j = 0 ; j < PTRS_PER_PAGE ; page_table++, j++) {
pte_t pte;
pte = *page_table;
if (pte_none(pte)) if (pte_none(pte))
continue; return 0;
if (pte_present(pte)) { if (pte_present(pte)) {
unsigned long page = pte_page(pte); unsigned long page = pte_page(pte);
if (page >= high_memory) if (page >= high_memory)
continue; return 0;
if (!in_swap_cache(page)) if (!in_swap_cache(page))
continue; return 0;
if (SWP_TYPE(in_swap_cache(page)) != type) if (SWP_TYPE(in_swap_cache(page)) != type)
continue; return 0;
delete_from_swap_cache(page); delete_from_swap_cache(page);
*page_table = pte_mkdirty(pte); *dir = pte_mkdirty(pte);
continue; return 0;
} }
if (SWP_TYPE(pte_val(pte)) != type) if (SWP_TYPE(pte_val(pte)) != type)
continue; return 0;
if (!tmp) { read_swap_page(pte_val(pte), (char *) page);
if (!(tmp = __get_free_page(GFP_KERNEL))) if (pte_val(*dir) != pte_val(pte)) {
return -ENOMEM; free_page(page);
goto repeat; return 1;
} }
read_swap_page(pte_val(pte), (char *) tmp); *dir = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
if (pte_val(*page_table) != pte_val(pte)) ++vma->vm_task->mm->rss;
goto repeat;
*page_table = pte_mkwrite(pte_mkdirty(mk_pte(tmp, PAGE_COPY)));
++p->mm->rss;
swap_free(pte_val(pte)); swap_free(pte_val(pte));
tmp = 0; return 1;
}
static inline int unuse_pmd(struct vm_area_struct * vma, pmd_t *dir,
unsigned long address, unsigned long size, unsigned long offset,
unsigned int type, unsigned long page)
{
pte_t * pte;
unsigned long end;
if (pmd_none(*dir))
return 0;
if (pmd_bad(*dir)) {
printk("unuse_pmd: bad pmd (%08lx)\n", pmd_val(*dir));
pmd_clear(dir);
return 0;
} }
pte = pte_offset(dir, address);
offset += address & PMD_MASK;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
do {
if (unuse_pte(vma, offset+address-vma->vm_start, pte, type, page))
return 1;
address += PAGE_SIZE;
pte++;
} while (address < end);
return 0;
}
static inline int unuse_pgd(struct vm_area_struct * vma, pgd_t *dir,
unsigned long address, unsigned long size,
unsigned int type, unsigned long page)
{
pmd_t * pmd;
unsigned long offset, end;
if (pgd_none(*dir))
return 0;
if (pgd_bad(*dir)) {
printk("unuse_pgd: bad pgd (%08lx)\n", pgd_val(*dir));
pgd_clear(dir);
return 0;
}
pmd = pmd_offset(dir, address);
offset = address & PGDIR_MASK;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
do {
if (unuse_pmd(vma, pmd, address, end - address, offset, type, page))
return 1;
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address < end);
return 0;
}
static int unuse_vma(struct vm_area_struct * vma, pgd_t *pgdir,
unsigned long start, unsigned long end,
unsigned int type, unsigned long page)
{
while (start < end) {
if (unuse_pgd(vma, pgdir, start, end - start, type, page))
return 1;
start = (start + PGDIR_SIZE) & PGDIR_MASK;
pgdir++;
}
return 0;
}
static int unuse_process(struct task_struct * p, unsigned int type, unsigned long page)
{
struct vm_area_struct* vma;
/*
* Go through process' page directory.
*/
vma = p->mm->mmap;
while (vma) {
pgd_t * pgd = pgd_offset(p, vma->vm_start);
if (unuse_vma(vma, pgd, vma->vm_start, vma->vm_end, type, page))
return 1;
vma = vma->vm_next;
}
return 0;
}
/*
* To avoid races, we repeat for each process after having
* swapped something in. That gets rid of a few pesky races,
* and "swapoff" isn't exactly timing critical.
*/
static int try_to_unuse(unsigned int type)
{
int nr;
unsigned long page = get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
nr = 0;
while (nr < NR_TASKS) {
if (task[nr]) {
if (unuse_process(task[nr], type, page)) {
page = get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
continue;
} }
} }
free_page(tmp); nr++;
}
free_page(page);
return 0; return 0;
} }
......
...@@ -841,7 +841,7 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, ...@@ -841,7 +841,7 @@ int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev,
/* /*
* Find an entry * Find an entry
*/ */
entry = arp_lookup(paddr, 0); entry = arp_lookup(paddr, 1);
if (entry != NULL) /* It exists */ if (entry != NULL) /* It exists */
{ {
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
* Alan Cox : 100 backlog just doesn't cut it when * Alan Cox : 100 backlog just doesn't cut it when
* you start doing multicast video 8) * you start doing multicast video 8)
* Alan Cox : Rewrote net_bh and list manager. * Alan Cox : Rewrote net_bh and list manager.
* Alan Cox : Fix ETH_P_ALL echoback lengths.
* *
* Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have * Cleaned up and recommented by Alan Cox 2nd April 1994. I hope to have
* the rest as well commented in the end. * the rest as well commented in the end.
...@@ -398,6 +399,11 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) ...@@ -398,6 +399,11 @@ void dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
struct sk_buff *skb2; struct sk_buff *skb2;
if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
break; break;
/*
* The protocol knows this has (for other paths) been taken off
* and adds it back.
*/
skb2->len-=skb->dev->hard_header_len;
ptype->func(skb2, skb->dev, ptype); ptype->func(skb2, skb->dev, ptype);
nitcount--; nitcount--;
} }
......
...@@ -2052,19 +2052,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt ...@@ -2052,19 +2052,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
if(level!=SOL_IP) if(level!=SOL_IP)
return -EOPNOTSUPP; return -EOPNOTSUPP;
#ifdef CONFIG_IP_MULTICAST
if(optname==IP_MULTICAST_TTL)
{
unsigned char ucval;
ucval=get_fs_byte((unsigned char *)optval);
printk("MC TTL %d\n", ucval);
if(ucval<1||ucval>255)
return -EINVAL;
sk->ip_mc_ttl=(int)ucval;
return 0;
}
#endif
switch(optname) switch(optname)
{ {
case IP_TOS: case IP_TOS:
...@@ -2082,19 +2069,16 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt ...@@ -2082,19 +2069,16 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
sk->ip_ttl=val; sk->ip_ttl=val;
return 0; return 0;
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
#ifdef GCC_WORKS
case IP_MULTICAST_TTL: case IP_MULTICAST_TTL:
{ {
unsigned char ucval; unsigned char ucval;
ucval=get_fs_byte((unsigned char *)optval); ucval=get_fs_byte((unsigned char *)optval);
printk("MC TTL %d\n", ucval);
if(ucval<1||ucval>255) if(ucval<1||ucval>255)
return -EINVAL; return -EINVAL;
sk->ip_mc_ttl=(int)ucval; sk->ip_mc_ttl=(int)ucval;
return 0; return 0;
} }
#endif
case IP_MULTICAST_LOOP: case IP_MULTICAST_LOOP:
{ {
unsigned char ucval; unsigned char ucval;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment