Commit 8c78000c authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.3

parent aea252fa
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 2
SUBLEVEL = 3
ARCH = i386
......
......@@ -28,6 +28,7 @@ struct screen_info {
unsigned short orig_video_ega_bx;
unsigned short orig_video_ega_cx;
unsigned char orig_video_lines;
unsigned char orig_video_isVGA;
};
/*
......
......@@ -160,10 +160,12 @@ good_sig:
int 0x10
mov bx,ax
mov ax,#0x5019
movb [15],#0 ! by default, no VGA
cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower
jne novga
jne novga
movb [15],#1 ! we've detected a VGA
call chsvga
novga: mov [14],ax
novga: mov [14],al
mov ah,#0x03 ! read cursor pos
xor bh,bh ! clear bh
int 0x10 ! save it in known place, con_init fetches
......
......@@ -17,6 +17,8 @@ lib.a: $(OBJS)
dep:
modules:
#
# include a dependency file if one exists
#
......
......@@ -37,6 +37,12 @@
* 'int con_set_font(char *data, int ch512)'
* 'int con_adjust_height(int fontheight)'
*
* 'int con_get_cmap(char *)'
* 'int con_set_cmap(char *)'
*
* 'int reset_palette(int currcons)'
* 'void set_palette(void)'
*
* 'void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)'
* 'int mouse_reporting(void)'
*
......@@ -67,10 +73,14 @@
*
* Improved loadable font/UTF-8 support by H. Peter Anvin, Feb 1995
*
* improved scrollback, plus colour palette handling, by Simon Tatham
* 17-Jun-95 <sgt20@cam.ac.uk>
*
*/
#define BLANK 0x0020
#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */
#define CAN_LOAD_PALETTE /* undefine if the user must not do this */
/* A bitmap for codes <32. A bit of 1 indicates that the code
* corresponding to that bit number invokes some special action
......@@ -145,6 +155,8 @@ extern void vesa_blank(void);
extern void vesa_unblank(void);
extern void compute_shiftstate(void);
extern int conv_uni_to_pc(long ucs);
extern void reset_palette (int currcons) ;
extern void set_palette (void) ;
/* Description of the hardware situation */
static unsigned char video_type; /* Type of display being used */
......@@ -164,7 +176,7 @@ static int printable = 0; /* Is console ready for printing? */
/* these two also used in in vt.c */
int video_mode_512ch = 0; /* 512-character mode */
unsigned long video_font_height; /* Height of current screen font */
static unsigned long video_scan_lines; /* Number of scan lines on screen */
unsigned long video_scan_lines; /* Number of scan lines on screen */
static unsigned short console_charmask = 0x0ff;
static unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
......@@ -224,6 +236,7 @@ struct vc_data {
unsigned char vc_utf_count;
long vc_utf_char;
unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */
unsigned short * vc_translate;
unsigned char vc_G0_charset;
unsigned char vc_G1_charset;
......@@ -296,6 +309,7 @@ static struct vc {
#define ulcolor (vc_cons[currcons].d->vc_ulcolor)
#define halfcolor (vc_cons[currcons].d->vc_halfcolor)
#define tab_stop (vc_cons[currcons].d->vc_tab_stop)
#define palette (vc_cons[currcons].d->vc_palette)
#define vcmode (vt_cons[currcons]->vc_mode)
#define structsize (sizeof(struct vc_data) + sizeof(struct vt_struct))
......@@ -490,6 +504,14 @@ void vc_disallocate(unsigned int currcons)
static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
8,12,10,14, 9,13,11,15 };
/* the default colour table, for VGA+ colour systems */
static int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
static int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
static int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
/*
* gotoxy() must verify all boundaries, because the arguments
* might also be negative. If the given position is out of
......@@ -523,10 +545,14 @@ static void gotoxy(int currcons, int new_x, int new_y)
}
/*
* *Very* limited hardware scrollback support..
* Hardware scrollback support
*/
static unsigned short __real_origin;
static unsigned short __origin; /* offset of currently displayed screen */
static unsigned short __origin; /* offset of currently displayed screen */
#define last_lpos (((video_mem_term-video_mem_base)/video_num_columns/2)-video_num_lines+1)
#define last_origin_rel ( last_lpos * video_num_columns )
#define last_origin ( video_mem_base + last_origin_rel * 2 )
static unsigned short __scrollback_mode; /* 1 means scrollback can wrap */
static inline void __set_origin(unsigned short offset)
{
......@@ -549,8 +575,27 @@ void scrollback(int lines)
lines = video_num_lines/2;
lines *= video_num_columns;
lines = __origin - lines;
if (lines < 0)
lines = 0;
if (__scrollback_mode == 0) {
if (lines < 0)
lines = 0;
} else {
int s_top = __real_origin+video_num_lines*video_num_columns ;
if (lines < 0) {
int count ;
unsigned short * d = (unsigned short *) video_mem_base;
unsigned short * s = (unsigned short *) last_origin;
lines += last_origin_rel;
/* in case the top part of the screen has been modified since
* the scroll wrapped, copy the top bit back to the bottom */
count = (video_num_lines-1)*video_num_columns;
while (count) {
count--;
scr_writew(scr_readw(d++),s++);
}
} else if (__origin > __real_origin && lines < s_top)
lines = s_top ;
}
__set_origin(lines);
}
......@@ -559,15 +604,26 @@ void scrollfront(int lines)
if (!lines)
lines = video_num_lines/2;
lines *= video_num_columns;
lines = __origin + lines;
if (lines > __real_origin)
lines = __real_origin;
if (__origin > __real_origin) {
/* assume __scrollback_mode == 1 */
lines += __origin;
if (lines >= last_origin_rel) {
lines -= last_origin_rel ;
if (lines > __real_origin)
lines = __real_origin;
}
} else {
lines += __origin;
if (lines > __real_origin)
lines = __real_origin;
}
__set_origin(lines);
}
static void set_origin(int currcons)
{
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC
&& video_type != VIDEO_TYPE_EGAM)
return;
if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS)
return;
......@@ -614,7 +670,8 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
if (b > video_num_lines || t >= b)
return;
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM)
if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_VGAC
&& video_type != VIDEO_TYPE_EGAM)
hardscroll = 0;
else if (t || b != video_num_lines)
hardscroll = 0;
......@@ -622,7 +679,7 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
origin += video_size_row;
pos += video_size_row;
scr_end += video_size_row;
if (scr_end > video_mem_end) {
if (origin >= last_origin) {
unsigned short * d = (unsigned short *) video_mem_start;
unsigned short * s = (unsigned short *) origin;
unsigned int count;
......@@ -641,6 +698,8 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
pos -= origin-video_mem_start;
origin = video_mem_start;
has_scrolled = 1;
if (currcons == fg_console)
__scrollback_mode = 1;
} else {
unsigned short * d;
unsigned int count;
......@@ -651,6 +710,8 @@ static void scrup(int currcons, unsigned int t, unsigned int b)
count--;
scr_writew(video_erase_char, d++);
}
if (scr_end > last_origin) /* we've wrapped into kept region */
__scrollback_mode = 0;
}
set_origin(currcons);
} else {
......@@ -1266,7 +1327,8 @@ static void restore_cur(int currcons)
}
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
EShash, ESsetG0, ESsetG1, ESpercent, ESignore };
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
ESpalette };
static void reset_terminal(int currcons, int do_clear)
{
......@@ -1515,6 +1577,9 @@ static int con_write(struct tty_struct * tty, int from_user,
case '[':
vc_state = ESsquare;
continue;
case ']':
vc_state = ESnonstd;
continue;
case '%':
vc_state = ESpercent;
continue;
......@@ -1560,6 +1625,36 @@ static int con_write(struct tty_struct * tty, int from_user,
continue;
}
continue;
case ESnonstd:
if (c=='P') { /* palette escape sequence */
for (npar=0; npar<NPAR; npar++)
par[npar] = 0 ;
npar = 0 ;
vc_state = ESpalette;
continue;
} else if (c=='R') { /* reset palette */
reset_palette (currcons);
vc_state = ESnormal;
} else
vc_state = ESnormal;
continue;
case ESpalette:
if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
if (npar==7) {
int i = par[0]*3, j = 1;
palette[i] = 16*par[j++];
palette[i++] += par[j++];
palette[i] = 16*par[j++];
palette[i++] += par[j++];
palette[i] = 16*par[j++];
palette[i] += par[j];
set_palette() ;
vc_state = ESnormal;
}
} else
vc_state = ESnormal;
continue;
case ESsquare:
for(npar = 0 ; npar < NPAR ; npar++)
par[npar] = 0;
......@@ -1853,6 +1948,7 @@ static void con_unthrottle(struct tty_struct *tty)
static void vc_init(unsigned int currcons, unsigned long rows, unsigned long cols, int do_clear)
{
long base = (long) vc_scrbuf[currcons];
int j, k ;
video_num_columns = cols;
video_num_lines = rows;
......@@ -1863,6 +1959,11 @@ static void vc_init(unsigned int currcons, unsigned long rows, unsigned long col
scr_end = base + video_screen_size;
video_mem_end = base + video_screen_size;
reset_vc(currcons);
for (j=k=0; j<16; j++) {
vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
}
def_color = 0x07; /* white */
ulcolor = 0x0f; /* bold white */
halfcolor = 0x08; /* grey */
......@@ -1925,6 +2026,7 @@ long con_init(long kmem_start)
con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
video_page = ORIG_VIDEO_PAGE; /* never used */
__scrollback_mode = 0 ;
timer_table[BLANK_TIMER].fn = blank_screen;
timer_table[BLANK_TIMER].expires = 0;
......@@ -1943,16 +2045,14 @@ long con_init(long kmem_start)
video_type = VIDEO_TYPE_EGAM;
video_mem_term = 0xb8000;
display_desc = "EGA+";
request_region(0x3b4,2,"ega+");
request_region(0x3b0,16,"ega");
}
else
{
video_type = VIDEO_TYPE_MDA;
video_mem_term = 0xb2000;
display_desc = "*MDA";
request_region(0x3b4,2,"mda");
request_region(0x3b8,1,"mda");
request_region(0x3bf,1,"mda");
request_region(0x3b0,16,"mda");
}
}
else /* If not, it is color. */
......@@ -1963,10 +2063,44 @@ long con_init(long kmem_start)
video_port_val = 0x3d5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
video_type = VIDEO_TYPE_EGAC;
video_mem_term = 0xc0000;
display_desc = "EGA+";
request_region(0x3d4,2,"ega+");
int i ;
video_mem_term = 0xc0000;
if (!ORIG_VIDEO_ISVGA) {
video_type = VIDEO_TYPE_EGAC;
display_desc = "EGA";
request_region(0x3c0,32,"ega");
} else {
video_type = VIDEO_TYPE_VGAC;
display_desc = "VGA+";
request_region(0x3c0,32,"vga+");
/* get 64K rather than 32K of video RAM */
video_mem_base = 0xa0000 ;
video_mem_term = 0xb0000 ;
outb_p (6, 0x3ce) ;
outb_p (6, 0x3cf) ;
/* normalise the palette registers, to point the * 16 screen colours to the first 16 DAC entries */
for (i=0; i<16; i++) {
inb_p (0x3da) ;
outb_p (i, 0x3c0) ;
outb_p (i, 0x3c0) ;
}
outb_p (0x20, 0x3c0) ;
/* now set the DAC registers back to their default
* values */
for (i=0; i<16; i++) {
outb_p (color_table[i], 0x3c8) ;
outb_p (default_red[i], 0x3c9) ;
outb_p (default_grn[i], 0x3c9) ;
outb_p (default_blu[i], 0x3c9) ;
}
}
}
else
{
......@@ -1982,6 +2116,8 @@ long con_init(long kmem_start)
/* Due to kmalloc roundup allocating statically is more efficient -
so provide MIN_NR_CONSOLES for people with very little memory */
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
int j, k ;
vc_cons[currcons].d = (struct vc_data *) kmem_start;
kmem_start += sizeof(struct vc_data);
vt_cons[currcons] = (struct vt_struct *) kmem_start;
......@@ -1990,7 +2126,12 @@ long con_init(long kmem_start)
kmem_start += video_screen_size;
kmalloced = 0;
screenbuf_size = video_screen_size;
vc_init(currcons, video_num_lines, video_num_columns, currcons);
vc_init(currcons, video_num_lines, video_num_columns, currcons);
for (j=k=0; j<16; j++) {
vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
}
}
currcons = fg_console = 0;
......@@ -2008,7 +2149,8 @@ long con_init(long kmem_start)
can figure out the appropriate screen size should we load
a different font */
if ( video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_EGAM )
if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
|| video_type == VIDEO_TYPE_EGAM )
{
video_font_height = ORIG_VIDEO_POINTS;
/* This may be suboptimal but is a safe bet - go with it */
......@@ -2031,6 +2173,7 @@ static void get_scrmem(int currcons)
{
memcpyw((unsigned short *)vc_scrbuf[currcons],
(unsigned short *)origin, video_screen_size);
__scrollback_mode = 0 ;
origin = video_mem_start = (unsigned long)vc_scrbuf[currcons];
scr_end = video_mem_end = video_mem_start + video_screen_size;
pos = origin + y*video_size_row + (x<<1);
......@@ -2098,7 +2241,8 @@ void do_blank_screen(int nopowersave)
set_origin(fg_console);
get_scrmem(fg_console);
unblank_origin = origin;
memsetw((void *)blank_origin, BLANK, video_mem_term-blank_origin);
memsetw((void *)blank_origin, BLANK,
2*video_num_lines*video_num_columns);
hide_cursor();
console_blanked = fg_console + 1;
......@@ -2247,9 +2391,9 @@ static int set_get_font(char * arg, int set, int ch512)
/* no use to "load" CGA... */
if (video_type == VIDEO_TYPE_EGAC) {
if (video_type == VIDEO_TYPE_EGAC || video_type == VIDEO_TYPE_VGAC) {
charmap = colourmap;
beg = 0x0e;
beg = (video_type == VIDEO_TYPE_VGAC ? 0x06 : 0x0e) ;
} else if (video_type == VIDEO_TYPE_EGAM) {
charmap = blackwmap;
beg = 0x0a;
......@@ -2344,6 +2488,94 @@ static int set_get_font(char * arg, int set, int ch512)
#endif
}
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
static int set_get_cmap(unsigned char * arg, int set) {
#ifdef CAN_LOAD_PALETTE
int i;
/* no use to set colourmaps in less than colour VGA */
if (video_type != VIDEO_TYPE_VGAC)
return -EINVAL;
i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
if (i)
return i;
for (i=0; i<16; i++) {
if (set) {
default_red[i] = get_user(arg++) ;
default_grn[i] = get_user(arg++) ;
default_blu[i] = get_user(arg++) ;
} else {
put_user (default_red[i], arg++) ;
put_user (default_grn[i], arg++) ;
put_user (default_blu[i], arg++) ;
}
}
if (set) {
for (i=0; i<MAX_NR_CONSOLES; i++)
if (vc_cons_allocated(i)) {
int j, k ;
for (j=k=0; j<16; j++) {
vc_cons[i].d->vc_palette[k++] = default_red[j];
vc_cons[i].d->vc_palette[k++] = default_grn[j];
vc_cons[i].d->vc_palette[k++] = default_blu[j];
}
}
set_palette() ;
}
return 0;
#else
return -EINVAL;
#endif
}
/*
* Load palette into the EGA/VGA DAC registers. arg points to a colour
* map, 3 bytes per colour, 16 colours, range from 0 to 255.
*/
int con_set_cmap (unsigned char *arg)
{
return set_get_cmap (arg,1);
}
int con_get_cmap (unsigned char *arg)
{
return set_get_cmap (arg,0);
}
void reset_palette (int currcons)
{
int j, k ;
for (j=k=0; j<16; j++) {
palette[k++] = default_red[j];
palette[k++] = default_grn[j];
palette[k++] = default_blu[j];
}
set_palette() ;
}
void set_palette (void)
{
int i, j ;
if (video_type != VIDEO_TYPE_VGAC || console_blanked ||
vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
return ;
for (i=j=0; i<16; i++) {
outb_p (color_table[i], dac_reg) ;
outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
}
}
/*
* Load font into the EGA/VGA character generator. arg points to a 8192
* byte map, 32 bytes per character. Only first H of them are used for
......@@ -2379,9 +2611,9 @@ int con_adjust_height(unsigned long fontheight)
int rows, maxscan;
unsigned char ovr, vde, fsr, curs, cure;
if (fontheight > 32 ||
(video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
return -EINVAL;
if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
return -EINVAL;
if ( fontheight == video_font_height || fontheight == 0 )
return 0;
......
......@@ -102,6 +102,9 @@ static int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
static int tty_fasync(struct inode * inode, struct file * filp, int on);
extern void reset_palette(int currcons) ;
extern void set_palette(void) ;
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
......@@ -497,6 +500,7 @@ void reset_vc(unsigned int new_console)
vt_cons[new_console]->vt_mode.frsig = 0;
vt_cons[new_console]->vt_pid = -1;
vt_cons[new_console]->vt_newvt = -1;
reset_palette (new_console) ;
}
/*
......@@ -561,6 +565,10 @@ void complete_change_console(unsigned int new_console)
do_blank_screen(1);
}
/* Set the colour palette for this VT */
if (vt_cons[new_console]->vc_mode == KD_TEXT)
set_palette() ;
/*
* Wake anyone waiting for their VT to activate
*/
......
......@@ -63,7 +63,8 @@ extern void do_unblank_screen(void);
extern unsigned int keymap_count;
/*
* routines to load custom translation table and EGA/VGA font from console.c
* routines to load custom translation table, EGA/VGA font and
* VGA colour palette from console.c
*/
extern int con_set_trans_old(char * table);
extern int con_get_trans_old(char * table);
......@@ -74,10 +75,14 @@ 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, int ch512);
extern int con_get_font(char * fontmap);
extern int con_set_cmap(unsigned char *cmap);
extern int con_get_cmap(unsigned char *cmap);
extern void reset_palette(int currcons);
extern int con_adjust_height(unsigned long fontheight);
extern int video_mode_512ch;
extern unsigned long video_font_height;
extern unsigned long video_scan_lines;
/*
* these are the valid i/o ports we're allowed to change. they map all the
......@@ -95,13 +100,13 @@ extern unsigned long video_font_height;
* tty.
*/
static void
static int
kd_size_changed(int row, int col)
{
struct task_struct *p;
int i;
if ( !row && !col ) return;
if ( !row && !col ) return 0;
for ( i = 0 ; i < MAX_NR_CONSOLES ; i++ )
{
......@@ -120,6 +125,8 @@ kd_size_changed(int row, int col)
send_sig(SIGWINCH, p, 1);
}
}
return 0;
}
/*
......@@ -864,7 +871,61 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return i;
ll = get_fs_word(&vtsizes->v_rows);
cc = get_fs_word(&vtsizes->v_cols);
return vc_resize(ll, cc);
i = vc_resize(ll, cc);
return i ? i : kd_size_changed(ll, cc);
}
case VT_RESIZEX:
{
struct vt_consize *vtconsize = (struct vt_consize *) arg;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
return -EPERM;
i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
if (i)
return i;
ll = get_fs_word(&vtconsize->v_rows);
cc = get_fs_word(&vtconsize->v_cols);
vlin = get_fs_word(&vtconsize->v_vlin);
clin = get_fs_word(&vtconsize->v_clin);
vcol = get_fs_word(&vtconsize->v_vcol);
ccol = get_fs_word(&vtconsize->v_ccol);
vlin = vlin ? vlin : video_scan_lines;
if ( clin )
{
if ( ll )
{
if ( ll != vlin/clin )
return EINVAL; /* Parameters don't add up */
}
else
ll = vlin/clin;
}
if ( vcol && ccol )
{
if ( cc )
{
if ( cc != vcol/ccol )
return EINVAL;
}
else
cc = vcol/ccol;
}
if ( clin > 32 )
return EINVAL;
if ( vlin )
video_scan_lines = vlin;
if ( clin )
video_font_height = clin;
i = vc_resize(ll, cc);
if (i)
return i;
kd_size_changed(ll, cc);
return 0;
}
case PIO_FONT:
......@@ -882,6 +943,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return con_get_font((char *)arg);
/* con_get_font() defined in console.c */
case PIO_CMAP:
if (!perm)
return -EPERM;
return con_set_cmap((char *)arg);
/* con_set_cmap() defined in console.c */
case GIO_CMAP:
return con_get_cmap((char *)arg);
/* con_get_cmap() defined in console.c */
case PIO_FONTX:
{
struct consolefontdesc cfdarg;
......@@ -903,9 +974,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (i)
return i;
i = con_adjust_height(cfdarg.charheight);
if (i <= 0) return i;
kd_size_changed(i, 0);
return 0;
return (i <= 0) ? i : kd_size_changed(i, 0);
} else
return -EINVAL;
}
......
......@@ -16,9 +16,9 @@
This is not a complete driver, it must be combined with board-specific
code such as ne.c, wd.c, 3c503.c, etc.
13/04/95 -- Don't blindly swallow ENISR_RDC interrupts for non-shared
memory cards. We need to follow these closely for neX000 cards.
Plus other minor cleanups. -- Paul Gortmaker
Changelog:
Paul Gortmaker : remove set_bit lock, other cleanups.
*/
......@@ -129,7 +129,6 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
int e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) dev->priv;
int length, send_length;
unsigned long flags;
/*
* We normally shouldn't be called if dev->tbusy is set, but the
......@@ -177,22 +176,14 @@ static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
if (skb->len <= 0)
return 0;
save_flags(flags);
cli();
/* Block a timer-based transmit from overlapping. */
if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) {
printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n",
dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1,
ei_local->tx2, ei_local->lasttx);
restore_flags(flags);
return 1;
}
/* Mask interrupts from the ethercard. */
outb_p(0x00, e8390_base + EN0_IMR);
if (dev->interrupt) {
printk("%s: Tx request while isr active.\n",dev->name);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
return 1;
}
ei_local->irqlock = 1;
restore_flags(flags);
send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
......@@ -314,17 +305,17 @@ void ei_interrupt(int irq, struct pt_regs * regs)
outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
}
/* Ignore any RDC interrupts that make it back to here. */
if (interrupts & ENISR_RDC) {
if (dev->mem_start)
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
}
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
}
if ((interrupts & ~ENISR_RDC) && ei_debug) {
if (interrupts && ei_debug) {
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
if (nr_serviced == MAX_SERVICE) {
if (nr_serviced >= MAX_SERVICE) {
printk("%s: Too much work at interrupt, status %#2.2x\n",
dev->name, interrupts);
outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
......@@ -501,7 +492,7 @@ static void ei_receive(struct device *dev)
ei_local->current_page = next_frame;
outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
}
/* If any worth-while packets have been received, dev_rint()
/* If any worth-while packets have been received, netif_rx()
has done a mark_bh(NET_BH) for us and will work on them
when we get to the bottom-half routine. */
......
......@@ -45,12 +45,12 @@ struct ei_device {
unsigned word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */
unsigned txing:1; /* Transmit Active */
unsigned irqlock:1; /* 8390's intrs disabled when '1'. */
unsigned dmaing:1; /* Remote DMA Active */
unsigned pingpong:1; /* Using the ping-pong driver */
unsigned char tx_start_page, rx_start_page, stop_page;
unsigned char current_page; /* Read pointer in buffer */
unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */
unsigned char txqueue; /* Tx Packet buffer queue length. */
unsigned char dmaing; /* Remote DMA (Tx/Rx/Active) */
short tx1, tx2; /* Packet lengths for ping-pong tx. */
short lasttx; /* Alpha version consistency check. */
unsigned char reg0; /* Register '0' in a WD8013 */
......
......@@ -16,12 +16,10 @@
boards. Currently it supports the NE1000, NE2000, many clones,
and some Cabletron products.
13/04/95 -- Change in philosophy. We now monitor ENISR_RDC for
handshaking the Tx PIO xfers. If we don't get a RDC within a
reasonable period of time, we know the 8390 has gone south, and we
kick the board before it locks the system. Also use set_bit() to
create atomic locks on the PIO xfers, and added some defines
that the end user can play with to save memory. -- Paul Gortmaker
Changelog:
Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made
sanity checks and bad clone support optional.
*/
......@@ -335,6 +333,7 @@ ne_reset_8390(struct device *dev)
if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies);
ei_status.txing = 0;
ei_status.dmaing = 0;
outb_p(tmp, NE_BASE + NE_RESET);
/* This check _should_not_ be necessary, omit eventually. */
......@@ -343,10 +342,11 @@ ne_reset_8390(struct device *dev)
printk("%s: ne_reset_8390() did not complete.\n", dev->name);
break;
}
outb_p(ENISR_RESET, NE_BASE + NE_RESET); /* Ack intr. */
}
/* Block input and output, similar to the Crynwr packet driver. If you
porting to a new ethercard look at the packet driver source for hints.
are porting to a new ethercard, look at the packet driver source for hints.
The NEx000 doesn't share it on-board packet memory -- you have to put
the packet out through the "remote DMA" dataport using outb. */
......@@ -359,7 +359,7 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
int nic_base = dev->base_addr;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (set_bit(0,(void*)&ei_status.dmaing)) {
if (ei_status.dmaing) {
if (ei_debug > 0)
printk("%s: DMAing conflict in ne_block_input "
"[DMAstat:%d][irqlock:%d][intr:%d].\n",
......@@ -367,7 +367,7 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
dev->interrupt);
return 0;
}
ei_status.dmaing |= 0x02;
ei_status.dmaing |= 0x01;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
outb_p(count & 0xff, nic_base + EN0_RCNTLO);
outb_p(count >> 8, nic_base + EN0_RCNTHI);
......@@ -409,7 +409,7 @@ ne_block_input(struct device *dev, int count, char *buf, int ring_offset)
}
#endif
outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
ei_status.dmaing &= ~0x03;
ei_status.dmaing &= ~0x01;
return ring_offset + count;
}
......@@ -430,7 +430,7 @@ ne_block_output(struct device *dev, int count,
count++;
/* This *shouldn't* happen. If it does, it's the last thing you'll see */
if (set_bit(0,(void*)&ei_status.dmaing)) {
if (ei_status.dmaing) {
if (ei_debug > 0)
printk("%s: DMAing conflict in ne_block_output."
"[DMAstat:%d][irqlock:%d][intr:%d]\n",
......@@ -438,7 +438,7 @@ ne_block_output(struct device *dev, int count,
dev->interrupt);
return;
}
ei_status.dmaing |= 0x04;
ei_status.dmaing |= 0x01;
/* We should already be in page 0, but to be safe... */
outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
......@@ -510,7 +510,7 @@ ne_block_output(struct device *dev, int count,
}
outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
ei_status.dmaing &= ~0x05;
ei_status.dmaing &= ~0x01;
return;
}
......
......@@ -504,6 +504,9 @@ ppp_close(struct tty_struct *tty)
ppp_release (ppp);
PRINTKN (2,(KERN_INFO "ppp: channel %s closing.\n", ppp->dev->name));
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
}
}
......@@ -612,9 +615,6 @@ ppp_dev_close(struct device *dev)
PRINTKN (2,(KERN_INFO "ppp: channel %s going down for IP packets!\n",
dev->name));
CHECK_PPP(-ENXIO);
#ifdef MODULE
MOD_DEC_USE_COUNT;
#endif
return 0;
}
......
......@@ -78,7 +78,7 @@ static void padzero(unsigned long elf_bss)
}
}
unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, unsigned int interp_load_addr, int ibcs)
{
unsigned long *argv,*envp, *dlinfo;
unsigned long * sp;
......@@ -129,11 +129,11 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
put_fs_long(7,dlinfo++); put_fs_long(interp_load_addr,dlinfo++);
put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
};
}
put_fs_long((unsigned long)argc,--sp);
current->mm->arg_start = (unsigned long) p;
......@@ -159,7 +159,7 @@ unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exe
an ELF header */
static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
struct inode * interpreter_inode)
struct inode * interpreter_inode, unsigned int *interp_load_addr)
{
struct file * file;
struct elf_phdr *elf_phdata = NULL;
......@@ -184,7 +184,7 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
(!interpreter_inode->i_op ||
!interpreter_inode->i_op->default_file_ops->mmap)){
return 0xffffffff;
};
}
/* Now read in all of the header information */
......@@ -202,52 +202,32 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
if (elf_exec_fileno < 0) return 0xffffffff;
file = current->files->fd[elf_exec_fileno];
/*
* First calculate the maximum range of VMA that we need to
* use, and then allocate the entire thing. Then unmap
* and remap the individual portions of the file to the
* correct address.
*/
if( interp_elf_ex->e_type == ET_DYN )
{
int maxvma = 0;
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
if(eppnt->p_type == PT_LOAD) {
if( maxvma < eppnt->p_vaddr + eppnt->p_memsz)
maxvma = eppnt->p_vaddr + eppnt->p_memsz;
}
error = do_mmap(file, 0, maxvma, PROT_READ,
MAP_PRIVATE | MAP_DENYWRITE, 0);
if(error < 0 && error > -1024) goto oops; /* Real error */
load_addr = error;
SYS(munmap)(load_addr, maxvma);
}
else
{
/*
* For normal executables, we do not use this offset,
* since the vaddr field contains an absolute address.
*/
load_addr = 0;
}
eppnt = elf_phdata;
for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
if(eppnt->p_type == PT_LOAD) {
int elf_prot = (eppnt->p_flags & PF_R) ? PROT_READ : 0;
int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
int elf_prot = 0;
unsigned long vaddr = 0;
if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
if (interp_elf_ex->e_type == ET_EXEC) {
elf_type |= MAP_FIXED;
vaddr = eppnt->p_vaddr;
}
error = do_mmap(file,
load_addr + (eppnt->p_vaddr & 0xfffff000),
eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
vaddr & 0xfffff000,
eppnt->p_filesz + (vaddr & 0xfff),
elf_prot,
MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED,
elf_type,
eppnt->p_offset & 0xfffff000);
if(error < 0 && error > -1024) break; /* Real error */
if(!load_addr && interp_elf_ex->e_type == ET_DYN)
load_addr = error;
/*
* Find the end of the file mapping for this phdr, and keep
* track of the largest address we see for this.
......@@ -265,7 +245,6 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
/* Now use mmap to map the library into memory. */
oops:
SYS(close)(elf_exec_fileno);
if(error < 0 && error > -1024) {
kfree(elf_phdata);
......@@ -288,6 +267,7 @@ static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
MAP_FIXED|MAP_PRIVATE, 0);
kfree(elf_phdata);
*interp_load_addr = load_addr;
return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
}
......@@ -358,7 +338,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned int elf_bss, k, elf_brk;
int retval;
char * elf_interpreter;
unsigned int elf_entry;
unsigned int elf_entry, interp_load_addr = 0;
int status;
unsigned int start_code, end_code, end_data;
unsigned int elf_stack;
......@@ -385,7 +365,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
!bprm->inode->i_op->default_file_ops->mmap)){
MOD_DEC_USE_COUNT;
return -ENOEXEC;
};
}
/* Now read in all of the header information */
......@@ -440,25 +420,30 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
#if 0
printk("Using ELF interpreter %s\n", elf_interpreter);
#endif
if(retval >= 0)
if(retval >= 0) {
old_fs = get_fs(); /* This could probably be optimized */
set_fs(get_ds());
retval = namei(elf_interpreter, &interpreter_inode);
set_fs(old_fs);
}
if(retval >= 0)
retval = read_exec(interpreter_inode,0,bprm->buf,128, 1);
if(retval >= 0){
if(retval >= 0) {
interp_ex = *((struct exec *) bprm->buf); /* exec-header */
interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
};
}
if(retval < 0) {
kfree (elf_phdata);
kfree(elf_interpreter);
MOD_DEC_USE_COUNT;
return retval;
};
};
kfree (elf_phdata);
kfree(elf_interpreter);
MOD_DEC_USE_COUNT;
return retval;
}
}
elf_ppnt++;
};
}
/* Some simple consistency checks for the interpreter */
if(elf_interpreter){
......@@ -468,7 +453,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
kfree(elf_phdata);
MOD_DEC_USE_COUNT;
return -ELIBACC;
};
}
/* Now figure out which format our binary is */
if((N_MAGIC(interp_ex) != OMAGIC) &&
(N_MAGIC(interp_ex) != ZMAGIC) &&
......@@ -485,7 +470,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
kfree(elf_phdata);
MOD_DEC_USE_COUNT;
return -ELIBBAD;
};
}
}
/* OK, we are done with that, now set up the arg stuff,
......@@ -501,8 +486,8 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if(elf_interpreter) {
bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
bprm->argc++;
};
};
}
}
if (!bprm->p) {
if(elf_interpreter) {
kfree(elf_interpreter);
......@@ -548,7 +533,7 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
load_aout_interp(&interp_ex, interpreter_inode);
if(interpreter_type & 2) elf_entry =
load_elf_interp(&interp_elf_ex, interpreter_inode);
load_elf_interp(&interp_elf_ex, interpreter_inode, &interp_load_addr);
old_fs = get_fs();
set_fs(get_ds());
......@@ -562,8 +547,8 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
send_sig(SIGSEGV, current, 0);
MOD_DEC_USE_COUNT;
return 0;
};
};
}
}
if(elf_ppnt->p_type == PT_LOAD) {
......@@ -593,9 +578,9 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
if(end_data < k) end_data = k;
k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
if(k > elf_brk) elf_brk = k;
};
}
elf_ppnt++;
};
}
set_fs(old_fs);
kfree(elf_phdata);
......@@ -627,7 +612,8 @@ load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
bprm->argc,
bprm->envc,
(interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
load_addr,
load_addr,
interp_load_addr,
(interpreter_type == INTERPRETER_AOUT ? 0 : 1));
if(interpreter_type == INTERPRETER_AOUT)
current->mm->arg_start += strlen(passed_fileno) + 1;
......@@ -714,7 +700,7 @@ load_elf_library(int fd){
(!inode->i_op || !inode->i_op->default_file_ops->mmap)){
MOD_DEC_USE_COUNT;
return -ENOEXEC;
};
}
/* Now read in all of the header information */
......@@ -737,7 +723,7 @@ load_elf_library(int fd){
kfree(elf_phdata);
MOD_DEC_USE_COUNT;
return -ENOEXEC;
};
}
while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
......
......@@ -45,11 +45,11 @@ static int fillonedir(void * __buf, char * name, int namlen, off_t offset, ino_t
return -EINVAL;
buf->count++;
dirent = buf->dirent;
put_fs_long(ino, &dirent->d_ino);
put_fs_long(offset, &dirent->d_offset);
put_fs_word(namlen, &dirent->d_namlen);
put_user(ino, &dirent->d_ino);
put_user(offset, &dirent->d_offset);
put_user(namlen, &dirent->d_namlen);
memcpy_tofs(dirent->d_name, name, namlen);
put_fs_byte(0, dirent->d_name + namlen);
put_user(0, dirent->d_name + namlen);
return 0;
}
......@@ -106,10 +106,10 @@ static int filldir(void * __buf, char * name, int namlen, off_t offset, ino_t in
put_user(offset, &dirent->d_off);
dirent = buf->current;
buf->previous = dirent;
put_fs_long(ino, &dirent->d_ino);
put_fs_word(reclen, &dirent->d_reclen);
put_user(ino, &dirent->d_ino);
put_user(reclen, &dirent->d_reclen);
memcpy_tofs(dirent->d_name, name, namlen);
put_fs_byte(0, dirent->d_name + namlen);
put_user(0, dirent->d_name + namlen);
((char *) dirent) += reclen;
buf->current = dirent;
buf->count -= reclen;
......
......@@ -15,6 +15,9 @@ struct consolefontdesc {
char *chardata; /* font data in expanded form */
};
#define GIO_CMAP 0x4B70 /* gets colour palette on VGA+ */
#define PIO_CMAP 0x4B71 /* sets colour palette on VGA+ */
#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
#define KDMKTONE 0x4B30 /* generate tone */
......@@ -129,6 +132,6 @@ struct kbkeycode {
/* note: 0x4B00-0x4B4E all have had a value at some time;
don't reuse for the time being */
/* note: 0x4B60-0x4B6C used above */
/* note: 0x4B60-0x4B6C, 0x4B70, 0x4B71 used above */
#endif /* _LINUX_KD_H */
......@@ -44,6 +44,7 @@ struct screen_info {
unsigned short orig_video_ega_bx;
unsigned short orig_video_ega_cx;
unsigned char orig_video_lines;
unsigned char orig_video_isVGA;
unsigned short orig_video_points;
};
......@@ -58,12 +59,14 @@ extern struct screen_info screen_info;
#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx)
#define ORIG_VIDEO_EGA_CX (screen_info.orig_video_ega_cx)
#define ORIG_VIDEO_LINES (screen_info.orig_video_lines)
#define ORIG_VIDEO_ISVGA (screen_info.orig_video_isVGA)
#define ORIG_VIDEO_POINTS (screen_info.orig_video_points)
#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */
#define VIDEO_TYPE_CGA 0x11 /* CGA Display */
#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */
#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */
#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */
#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */
/*
* This character is the same as _POSIX_VDISABLE: it cannot be used as
......
......@@ -39,4 +39,14 @@ struct vt_sizes {
};
#define VT_RESIZE 0x5609 /* set kernel's idea of screensize */
struct vt_consize {
ushort v_rows; /* number of rows */
ushort v_cols; /* number of columns */
ushort v_vlin; /* number of pixel rows on screen */
ushort v_clin; /* number of pixel rows per character */
ushort v_vcol; /* number of pixel columns on screen */
ushort v_ccol; /* number of pixel columns per character */
};
#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */
#endif /* _LINUX_VT_H */
......@@ -39,6 +39,7 @@
#include <linux/netdevice.h>
#ifdef CONFIG_INET
#include <linux/ip.h>
#include <linux/etherdevice.h>
#include <net/protocol.h>
#include <net/arp.h>
#include <net/tcp.h>
......@@ -303,6 +304,7 @@ struct symbol_table symbol_table = {
X(register_netdev),
X(unregister_netdev),
X(ether_setup),
X(eth_type_trans),
X(alloc_skb),
X(kfree_skb),
X(dev_kfree_skb),
......
......@@ -30,3 +30,12 @@ NORET_TYPE void panic(const char * fmt, ...)
sys_sync();
for(;;);
}
/*
* GCC 2.5.8 doesn't always optimize correctly; see include/asm/segment.h
*/
int bad_user_access_length(void)
{
panic("bad_user_access_length executed (not cool, dude)");
}
......@@ -831,10 +831,6 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
if (pte_dirty(from)) {
if (!(from_area->vm_flags & VM_SHARED))
return 0;
if (pte_write(from)) {
printk("nonwritable, but dirty, shared page\n");
return 0;
}
}
/* is the page reasonable at all? */
if (pte_page(from) >= high_memory)
......@@ -869,10 +865,6 @@ static int try_to_share(unsigned long to_address, struct vm_area_struct * to_are
if (in_swap_cache(pte_page(from))) {
if (!(from_area->vm_flags & VM_SHARED))
return 0;
if (!pte_write(from)) {
printk("nonwritable, but dirty, shared page\n");
return 0;
}
}
copy_page(pte_page(from), newpage);
*to_table = mk_pte(newpage, to_area->vm_page_prot);
......
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