Commit 4cb8ac91 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.0.17

parent 6d58893f
...@@ -1104,7 +1104,7 @@ interface. PD is the Motorola Public Domain Interface and ICD is the ...@@ -1104,7 +1104,7 @@ interface. PD is the Motorola Public Domain Interface and ICD is the
commercial interface by P\&E. commercial interface by P\&E.
\begin{devicelist} \begin{devicelist}
\major{54}{Electrocardiognosis Holter serial card} \major{54}{}{char }{Electrocardiognosis Holter serial card}
\minor{0}{/dev/holter0}{First Holter port} \minor{0}{/dev/holter0}{First Holter port}
\minor{1}{/dev/holter1}{Second Holter port} \minor{1}{/dev/holter1}{Second Holter port}
\minor{2}{/dev/holter2}{Third Holter port} \minor{2}{/dev/holter2}{Third Holter port}
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 0 PATCHLEVEL = 0
SUBLEVEL = 16 SUBLEVEL = 17
ARCH = i386 ARCH = i386
......
/* /*
* linux/drivers/block/cmd640.c Version 1.01 Aug 12, 1996 * linux/drivers/block/cmd640.c Version 1.02 Sep 01, 1996
* *
* Copyright (C) 1995-1996 Linus Torvalds & authors (see below) * Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
*/ */
...@@ -94,9 +94,12 @@ ...@@ -94,9 +94,12 @@
* Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems * Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems
* Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7" * Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7"
* ("fast" is necessary for 32bit I/O in some systems) * ("fast" is necessary for 32bit I/O in some systems)
* Version 1.02 fix bug that resulted in slow "setup times"
* (patch courtesy of Zoltan Hidvegi)
*/ */
#undef REALLY_SLOW_IO /* most systems can safely undef this */ #undef REALLY_SLOW_IO /* most systems can safely undef this */
#define CMD640_PREFETCH_MASKS 1
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -408,9 +411,11 @@ static void check_prefetch (unsigned int index) ...@@ -408,9 +411,11 @@ static void check_prefetch (unsigned int index)
drive->no_io_32bit = 1; drive->no_io_32bit = 1;
drive->io_32bit = 0; drive->io_32bit = 0;
} else { } else {
#if CMD640_PREFETCH_MASKS
drive->no_unmask = 1; drive->no_unmask = 1;
drive->no_io_32bit = 0;
drive->unmask = 0; drive->unmask = 0;
#endif
drive->no_io_32bit = 0;
} }
} }
...@@ -454,8 +459,10 @@ static void set_prefetch_mode (unsigned int index, int mode) ...@@ -454,8 +459,10 @@ static void set_prefetch_mode (unsigned int index, int mode)
cli(); cli();
b = get_cmd640_reg(reg); b = get_cmd640_reg(reg);
if (mode) { /* want prefetch on? */ if (mode) { /* want prefetch on? */
#if CMD640_PREFETCH_MASKS
drive->no_unmask = 1; drive->no_unmask = 1;
drive->unmask = 0; drive->unmask = 0;
#endif
drive->no_io_32bit = 0; drive->no_io_32bit = 0;
b &= ~prefetch_masks[index]; /* enable prefetch */ b &= ~prefetch_masks[index]; /* enable prefetch */
} else { } else {
...@@ -556,9 +563,10 @@ static void program_drive_counts (unsigned int index) ...@@ -556,9 +563,10 @@ static void program_drive_counts (unsigned int index)
* Convert setup_count to internal chipset representation * Convert setup_count to internal chipset representation
*/ */
switch (setup_count) { switch (setup_count) {
case 4: setup_count = 0x00; case 4: setup_count = 0x00; break;
case 3: setup_count = 0x80; case 3: setup_count = 0x80; break;
case 2: setup_count = 0x40; case 1:
case 2: setup_count = 0x40; break;
default: setup_count = 0xc0; /* case 5 */ default: setup_count = 0xc0; /* case 5 */
} }
......
...@@ -4067,12 +4067,16 @@ static int floppy_grab_irq_and_dma(void) ...@@ -4067,12 +4067,16 @@ static int floppy_grab_irq_and_dma(void)
if (fd_request_irq()) { if (fd_request_irq()) {
DPRINT("Unable to grab IRQ%d for the floppy driver\n", DPRINT("Unable to grab IRQ%d for the floppy driver\n",
FLOPPY_IRQ); FLOPPY_IRQ);
MOD_DEC_USE_COUNT;
usage_count--;
return -1; return -1;
} }
if (fd_request_dma()) { if (fd_request_dma()) {
DPRINT("Unable to grab DMA%d for the floppy driver\n", DPRINT("Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA); FLOPPY_DMA);
fd_free_irq(); fd_free_irq();
MOD_DEC_USE_COUNT;
usage_count--;
return -1; return -1;
} }
for (fdc = 0; fdc < N_FDC; fdc++) for (fdc = 0; fdc < N_FDC; fdc++)
...@@ -4098,7 +4102,6 @@ static void floppy_release_irq_and_dma(void) ...@@ -4098,7 +4102,6 @@ static void floppy_release_irq_and_dma(void)
return; return;
} }
INT_ON; INT_ON;
MOD_DEC_USE_COUNT;
fd_disable_dma(); fd_disable_dma();
fd_free_dma(); fd_free_dma();
fd_disable_irq(); fd_disable_irq();
...@@ -4131,6 +4134,7 @@ static void floppy_release_irq_and_dma(void) ...@@ -4131,6 +4134,7 @@ static void floppy_release_irq_and_dma(void)
if (floppy_tq.sync) if (floppy_tq.sync)
printk("task queue still active\n"); printk("task queue still active\n");
#endif #endif
MOD_DEC_USE_COUNT;
} }
......
This diff is collapsed.
...@@ -1433,34 +1433,34 @@ static int con_write(struct tty_struct * tty, int from_user, ...@@ -1433,34 +1433,34 @@ static int con_write(struct tty_struct * tty, int from_user,
tc = translate[toggle_meta ? (c|0x80) : c]; tc = translate[toggle_meta ? (c|0x80) : c];
} }
/* If the original code was < 32 we only allow a /* If the original code was a control character we
* glyph to be displayed if the code is not normally * only allow a glyph to be displayed if the code is
* used (such as for cursor movement) or if the * not normally used (such as for cursor movement) or
* disp_ctrl mode has been explicitly enabled. * if the disp_ctrl mode has been explicitly enabled.
* Note: ESC is *never* allowed to be displayed as * Certain characters (as given by the CTRL_ALWAYS
* that would disable all escape sequences! * bitmap) are always displayed as control characters,
* To display font position 0x1B, go into UTF mode * as the console would be pretty useless without
* and display character U+F01B, or change the mapping. * them; to display an arbitrary font position use the
*/ * direct-to-font zone in UTF-8 mode.
ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS */
: CTRL_ACTION) >> c) & 1)))); ok = tc && (c >= 32 ||
(!utf && !(((disp_ctrl ? CTRL_ALWAYS
: CTRL_ACTION) >> c) & 1)))
&& (c != 127 || disp_ctrl);
if (vc_state == ESnormal && ok) { if (vc_state == ESnormal && ok) {
/* Now try to find out how to display it */ /* Now try to find out how to display it */
tc = conv_uni_to_pc(tc); tc = conv_uni_to_pc(tc);
if ( tc == -4 ) if ( tc == -4 ) {
{ /* If we got -4 (not found) then see if we have
/* If we got -4 (not found) then see if we have defined a replacement character (U+FFFD) */
defined a replacement character (U+FFFD) */ tc = conv_uni_to_pc(0xfffd);
tc = conv_uni_to_pc(0xfffd); } else if ( tc == -3 ) {
} /* Bad hash table -- hope for the best */
else if ( tc == -3 ) tc = c;
{ }
/* Bad hash table -- hope for the best */
tc = c;
}
if (tc & ~console_charmask) if (tc & ~console_charmask)
continue; /* Conversion failed */ continue; /* Conversion failed */
if (need_wrap) { if (need_wrap) {
cr(currcons); cr(currcons);
......
...@@ -311,7 +311,7 @@ int fdc_interrupt_wait(int time) ...@@ -311,7 +311,7 @@ int fdc_interrupt_wait(int time)
int current_blocked = current->blocked; int current_blocked = current->blocked;
static int resetting = 0; static int resetting = 0;
if (wait_intr) { if (waitqueue_active(&wait_intr)) {
TRACE(1, "error: nested call"); TRACE(1, "error: nested call");
return -EIO; /* return error... */ return -EIO; /* return error... */
} }
......
...@@ -771,7 +771,7 @@ fdc_isr(void) ...@@ -771,7 +771,7 @@ fdc_isr(void)
} }
seek_completed = 1; seek_completed = 1;
fdc_mode = fdc_idle; fdc_mode = fdc_idle;
} else if (!wait_intr) { } else if (!waitqueue_active(&wait_intr)) {
if (expected_stray_interrupts == 0) { if (expected_stray_interrupts == 0) {
TRACE(2, "unexpected stray interrupt"); TRACE(2, "unexpected stray interrupt");
} else { } else {
......
...@@ -795,7 +795,7 @@ static int read_chan(struct tty_struct *tty, struct file *file, ...@@ -795,7 +795,7 @@ static int read_chan(struct tty_struct *tty, struct file *file,
current->timeout = (unsigned long) -1; current->timeout = (unsigned long) -1;
if (time) if (time)
tty->minimum_to_wake = 1; tty->minimum_to_wake = 1;
else if (!tty->read_wait || else if (!waitqueue_active(&tty->read_wait) ||
(tty->minimum_to_wake > minimum)) (tty->minimum_to_wake > minimum))
tty->minimum_to_wake = minimum; tty->minimum_to_wake = minimum;
} else { } else {
...@@ -907,7 +907,7 @@ static int read_chan(struct tty_struct *tty, struct file *file, ...@@ -907,7 +907,7 @@ static int read_chan(struct tty_struct *tty, struct file *file,
} }
remove_wait_queue(&tty->read_wait, &wait); remove_wait_queue(&tty->read_wait, &wait);
if (!tty->read_wait) if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = minimum; tty->minimum_to_wake = minimum;
current->state = TASK_RUNNING; current->state = TASK_RUNNING;
...@@ -991,7 +991,7 @@ static int normal_select(struct tty_struct * tty, struct inode * inode, ...@@ -991,7 +991,7 @@ static int normal_select(struct tty_struct * tty, struct inode * inode,
return 1; return 1;
if (tty_hung_up_p(file)) if (tty_hung_up_p(file))
return 1; return 1;
if (!tty->read_wait) { if (!waitqueue_active(&tty->read_wait)) {
if (MIN_CHAR(tty) && !TIME_CHAR(tty)) if (MIN_CHAR(tty) && !TIME_CHAR(tty))
tty->minimum_to_wake = MIN_CHAR(tty); tty->minimum_to_wake = MIN_CHAR(tty);
else else
......
...@@ -1349,7 +1349,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on) ...@@ -1349,7 +1349,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
return retval; return retval;
if (on) { if (on) {
if (!tty->read_wait) if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1; tty->minimum_to_wake = 1;
if (filp->f_owner == 0) { if (filp->f_owner == 0) {
if (tty->pgrp) if (tty->pgrp)
...@@ -1358,7 +1358,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on) ...@@ -1358,7 +1358,7 @@ static int tty_fasync(struct inode * inode, struct file * filp, int on)
filp->f_owner = current->pid; filp->f_owner = current->pid;
} }
} else { } else {
if (!tty->fasync && !tty->read_wait) if (!tty->fasync && !waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = N_TTY_BUF_SIZE; tty->minimum_to_wake = N_TTY_BUF_SIZE;
} }
return 0; return 0;
......
...@@ -90,7 +90,7 @@ extern void enable_irq(unsigned int); ...@@ -90,7 +90,7 @@ extern void enable_irq(unsigned int);
"outb %al,$0x21\n\t" \ "outb %al,$0x21\n\t" \
"jmp 1f\n" \ "jmp 1f\n" \
"1:\tjmp 1f\n" \ "1:\tjmp 1f\n" \
"1:\tmovb $0x60+"#nr",%al\n\t" \ "1:\tmovb $0xE0+"#nr",%al\n\t" \
"outb %al,$0x20\n\t" "outb %al,$0x20\n\t"
#define ACK_SECOND(mask,nr) \ #define ACK_SECOND(mask,nr) \
...@@ -102,11 +102,11 @@ extern void enable_irq(unsigned int); ...@@ -102,11 +102,11 @@ extern void enable_irq(unsigned int);
"outb %al,$0xA1\n\t" \ "outb %al,$0xA1\n\t" \
"jmp 1f\n" \ "jmp 1f\n" \
"1:\tjmp 1f\n" \ "1:\tjmp 1f\n" \
"1:\tmovb $0x60+"#nr",%al\n\t" \ "1:\tmovb $0xE0+"#nr",%al\n\t" \
"outb %al,$0xA0\n\t" \ "outb %al,$0xA0\n\t" \
"jmp 1f\n" \ "jmp 1f\n" \
"1:\tjmp 1f\n" \ "1:\tjmp 1f\n" \
"1:\tmovb $0x62,%al\n\t" \ "1:\tmovb $0xE2,%al\n\t" \
"outb %al,$0x20\n\t" "outb %al,$0x20\n\t"
#define UNBLK_FIRST(mask) \ #define UNBLK_FIRST(mask) \
......
...@@ -134,16 +134,38 @@ ...@@ -134,16 +134,38 @@
/* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ /* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */
#define READ_AUDIO 0 #define READ_AUDIO 0
/* Optimizations for the Teac CD-55A drive read performance.
* SBP_TEAC_SPEED can be changed here, or one can set the
* variable "teac" when loading as a module.
* Valid settings are:
* 0 - very slow - the recommended "DISTRIBUTION 1" setup.
* 1 - 2x performance with little overhead. No busy waiting.
* 2 - 4x performance with 5ms overhead per read. Busy wait.
*
* Setting SBP_TEAC_SPEED or the variable 'teac' to anything
* other than 0 may cause problems. If you run into them, first
* change SBP_TEAC_SPEED back to 0 and see if your drive responds
* normally. If yes, you are "allowed" to report your case - to help
* me with the driver, not to solve your hassle. Dont mail if you
* simply are stuck into your own "tuning" experiments, you know?
*/
#define SBP_TEAC_SPEED 1
/*==========================================================================*/ /*==========================================================================*/
/*==========================================================================*/ /*==========================================================================*/
/* /*
* nothing to change below here if you are not experimenting * nothing to change below here if you are not fully aware what you're doing
*/ */
#ifndef _LINUX_SBPCD_H #ifndef _LINUX_SBPCD_H
#define _LINUX_SBPCD_H #define _LINUX_SBPCD_H
/*==========================================================================*/ /*==========================================================================*/
/*==========================================================================*/ /*==========================================================================*/
/*
* driver's own read_ahead, data mode
*/
#define SBP_BUFFER_FRAMES 8
#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */
#undef FUTURE #undef FUTURE
#undef SAFE_MIXED #undef SAFE_MIXED
...@@ -151,10 +173,15 @@ ...@@ -151,10 +173,15 @@
#define TEST_UPC 0 #define TEST_UPC 0
#define SPEA_TEST 0 #define SPEA_TEST 0
#define TEST_STI 0 #define TEST_STI 0
#define OLD_BUSY 0
#undef PATH_CHECK #undef PATH_CHECK
#ifndef SOUND_BASE #ifndef SOUND_BASE
#define SOUND_BASE 0 #define SOUND_BASE 0
#endif #endif
#if DISTRIBUTION
#undef SBP_TEAC_SPEED
#define SBP_TEAC_SPEED 0
#endif
/*==========================================================================*/ /*==========================================================================*/
/* /*
* DDI interface definitions * DDI interface definitions
......
...@@ -260,8 +260,8 @@ struct task_struct { ...@@ -260,8 +260,8 @@ struct task_struct {
#define PF_DUMPCORE 0x00000200 /* dumped core */ #define PF_DUMPCORE 0x00000200 /* dumped core */
#define PF_SIGNALED 0x00000400 /* killed by a signal */ #define PF_SIGNALED 0x00000400 /* killed by a signal */
#define PF_STARTING 0x00000100 /* being created */ #define PF_STARTING 0x00000002 /* being created */
#define PF_EXITING 0x00000200 /* getting shut down */ #define PF_EXITING 0x00000004 /* getting shut down */
#define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */ #define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */
#define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */ #define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */
......
...@@ -161,6 +161,7 @@ extern void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcph ...@@ -161,6 +161,7 @@ extern void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcph
extern void tcp_enqueue_partial(struct sk_buff *, struct sock *); extern void tcp_enqueue_partial(struct sk_buff *, struct sock *);
extern struct sk_buff * tcp_dequeue_partial(struct sock *); extern struct sk_buff * tcp_dequeue_partial(struct sock *);
extern void tcp_shrink_skb(struct sock *,struct sk_buff *,u32);
/* tcp_input.c */ /* tcp_input.c */
extern void tcp_cache_zap(void); extern void tcp_cache_zap(void);
......
...@@ -978,10 +978,11 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) ...@@ -978,10 +978,11 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len)
/* /*
* Maybe we can take some stuff off of the write queue, * Maybe we can take some stuff off of the write queue,
* and put it onto the xmit queue. * and put it onto the xmit queue.
* FIXME: (?) There is bizarre case being tested here, to check if * There is bizarre case being tested here, to check if
* the data at the head of the queue ends before the start of * the data at the head of the queue ends before the start of
* the sequence we already ACKed. This does not appear to be * the sequence we already ACKed. This is not an error,
* a case that can actually occur. Why are we testing it? * it can occur when we send a packet directly off of the write_queue
* in a zero window probe.
*/ */
if (!skb_queue_empty(&sk->write_queue) && if (!skb_queue_empty(&sk->write_queue) &&
......
...@@ -325,35 +325,38 @@ void tcp_write_xmit(struct sock *sk) ...@@ -325,35 +325,38 @@ void tcp_write_xmit(struct sock *sk)
skb_unlink(skb); skb_unlink(skb);
/* /*
* See if we really need to send the packet. * See if we really need to send the whole packet.
*/ */
if (before(skb->end_seq, sk->rcv_ack_seq +1)) if (before(skb->end_seq, sk->rcv_ack_seq +1)) {
{
/* /*
* This is acked data. We can discard it. This * This is acked data. We can discard it.
* cannot currently occur. * This implies the packet was sent out
* of the write queue by a zero window probe.
*/ */
sk->retransmits = 0; sk->retransmits = 0;
kfree_skb(skb, FREE_WRITE); kfree_skb(skb, FREE_WRITE);
if (!sk->dead) if (!sk->dead)
sk->write_space(sk); sk->write_space(sk);
} } else {
else
{
struct tcphdr *th; struct tcphdr *th;
struct iphdr *iph; struct iphdr *iph;
int size; int size;
/*
* put in the ack seq and window at this point rather than earlier,
* in order to keep them monotonic. We really want to avoid taking
* back window allocations. That's legal, but RFC1122 says it's frowned on.
* Ack and window will in general have changed since this packet was put
* on the write queue.
*/
iph = skb->ip_hdr; iph = skb->ip_hdr;
th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2)); th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2));
/* See if we need to shrink the leading packet on
* the retransmit queue. Strictly speaking, we
* should never need to do this, but some buggy TCP
* implementations get confused if you send them
* a packet that contains both old and new data. (Feh!)
* Soooo, we have this uglyness here.
*/
if (after(sk->rcv_ack_seq,skb->seq+th->syn+th->fin))
tcp_shrink_skb(sk,skb,sk->rcv_ack_seq);
size = skb->len - (((unsigned char *) th) - skb->data); size = skb->len - (((unsigned char *) th) - skb->data);
#ifndef CONFIG_NO_PATH_MTU_DISCOVERY #ifndef CONFIG_NO_PATH_MTU_DISCOVERY
if (size > sk->mtu - sizeof(struct iphdr)) if (size > sk->mtu - sizeof(struct iphdr))
...@@ -363,6 +366,13 @@ void tcp_write_xmit(struct sock *sk) ...@@ -363,6 +366,13 @@ void tcp_write_xmit(struct sock *sk)
} }
#endif #endif
/*
* put in the ack seq and window at this point rather than earlier,
* in order to keep them monotonic. We really want to avoid taking
* back window allocations. That's legal, but RFC1122 says it's frowned on.
* Ack and window will in general have changed since this packet was put
* on the write queue.
*/
th->ack_seq = htonl(sk->acked_seq); th->ack_seq = htonl(sk->acked_seq);
th->window = htons(tcp_select_window(sk)); th->window = htons(tcp_select_window(sk));
...@@ -1190,3 +1200,56 @@ void tcp_send_probe0(struct sock *sk) ...@@ -1190,3 +1200,56 @@ void tcp_send_probe0(struct sock *sk)
sk->prot->retransmits ++; sk->prot->retransmits ++;
tcp_reset_xmit_timer (sk, TIME_PROBE0, sk->rto); tcp_reset_xmit_timer (sk, TIME_PROBE0, sk->rto);
} }
/*
* Remove the portion of a packet that has already been sent.
* Needed to deal with buggy TCP implementations that can't deal
* with seeing a packet that contains some data that has already
* been received.
*/
void tcp_shrink_skb(struct sock *sk, struct sk_buff *skb, u32 ack)
{
struct iphdr *iph;
struct tcphdr *th;
unsigned char *old, *new;
unsigned long len;
int diff;
/*
* Recover the buffer pointers
*/
iph = (struct iphdr *)skb->ip_hdr;
th = (struct tcphdr *)(((char *)iph) +(iph->ihl << 2));
/* how much data are we droping from the tcp frame */
diff = ack - skb->seq;
/* how much data are we keeping in the tcp frame */
len = (skb->end_seq - (th->fin + th->syn)) - ack;
/* pointers to new start of remaining data, and old start */
new = (unsigned char *)th + th->doff*4;
old = new+diff;
/* Update our starting seq number */
skb->seq = ack;
th->seq = htonl(ack);
iph->tot_len = htons(ntohs(iph->tot_len)-diff);
/* Get the partial checksum for the IP options */
if (th->doff*4 - sizeof(*th) > 0)
skb->csum = csum_partial((void *)(th+1),
th->doff*4-sizeof(*th),0);
else
skb->csum = 0;
/* Copy the good data down and get it's checksum */
skb->csum = csum_partial_copy((void *)old,(void *)new,len,skb->csum);
/* shorten the skb */
skb_trim(skb,skb->len-diff);
/* Checksum the shrunk buffer */
tcp_send_check(th, sk->saddr, sk->daddr,
th->doff * 4 + len , skb);
}
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