fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / ia64 / hp / sim / simserial.c
index 3812778..324ea75 100644 (file)
@@ -16,7 +16,6 @@
  * 07/30/02 D. Mosberger       Replace sti()/cli() with explicit spinlocks & local irq masking
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/fcntl.h>
 #include <linux/mm.h>
 #include <linux/slab.h>
+#include <linux/capability.h>
 #include <linux/console.h>
 #include <linux/module.h>
 #include <linux/serial.h>
 #include <linux/serialP.h>
+#include <linux/sysrq.h>
 
 #include <asm/irq.h>
 #include <asm/hw_irq.h>
 #define KEYBOARD_INTR  3       /* must match with simulator! */
 
 #define NR_PORTS       1       /* only one port for now */
-#define SERIAL_INLINE  1
 
-#ifdef SERIAL_INLINE
-#define _INLINE_ inline
-#endif
-
-#ifndef MIN
-#define MIN(a,b)       ((a) < (b) ? (a) : (b))
-#endif
-
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
 
 #define SSC_GETCHAR    21
 
@@ -100,7 +92,7 @@ static struct serial_uart_config uart_config[] = {
        { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
                  UART_STARTECH },
        { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
-       { 0, 0}
+       { NULL, 0}
 };
 
 struct tty_driver *hp_simserial_driver;
@@ -110,7 +102,6 @@ static struct async_struct *IRQ_ports[NR_IRQS];
 static struct console *console;
 
 static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
 
 extern struct console *console_drivers; /* from kernel/printk.c */
 
@@ -133,13 +124,13 @@ static void rs_stop(struct tty_struct *tty)
 
 static void rs_start(struct tty_struct *tty)
 {
-#if SIMSERIAL_DEBUG
+#ifdef SIMSERIAL_DEBUG
        printk("rs_start: tty->stopped=%d tty->hw_stopped=%d tty->flow_stopped=%d\n",
                tty->stopped, tty->hw_stopped, tty->flow_stopped);
 #endif
 }
 
-static  void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
+static  void receive_chars(struct tty_struct *tty)
 {
        unsigned char ch;
        static unsigned char seen_esc = 0;
@@ -153,26 +144,25 @@ static  void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
                                seen_esc = 2;
                                continue;
                        } else if ( seen_esc == 2 ) {
-                               if ( ch == 'P' ) show_state();          /* F1 key */
-#ifdef CONFIG_KDB
-                               if ( ch == 'S' )
-                                       kdb(KDB_REASON_KEYBOARD, 0, (kdb_eframe_t) regs);
+                               if ( ch == 'P' ) /* F1 */
+                                       show_state();
+#ifdef CONFIG_MAGIC_SYSRQ
+                               if ( ch == 'S' ) { /* F4 */
+                                       do
+                                               ch = ia64_ssc(0, 0, 0, 0,
+                                                             SSC_GETCHAR);
+                                       while (!ch);
+                                       handle_sysrq(ch, NULL);
+                               }
 #endif
-
                                seen_esc = 0;
                                continue;
                        }
                }
                seen_esc = 0;
-               if (tty->flip.count >= TTY_FLIPBUF_SIZE) break;
-
-               *tty->flip.char_buf_ptr = ch;
 
-               *tty->flip.flag_buf_ptr = 0;
-
-               tty->flip.flag_buf_ptr++;
-               tty->flip.char_buf_ptr++;
-               tty->flip.count++;
+               if (tty_insert_flip_char(tty, ch, TTY_NORMAL) == 0)
+                       break;
        }
        tty_flip_buffer_push(tty);
 }
@@ -180,7 +170,7 @@ static  void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
 /*
  * This is the serial driver's interrupt routine for a single port
  */
-static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
 {
        struct async_struct * info;
 
@@ -197,7 +187,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * r
         * pretty simple in our case, because we only get interrupts
         * on inbound traffic
         */
-       receive_chars(info->tty, regs);
+       receive_chars(info->tty);
        return IRQ_HANDLED;
 }
 
@@ -219,7 +209,7 @@ static void do_serial_bh(void)
 }
 #endif
 
-static void do_softint(void *private_)
+static void do_softint(struct work_struct *private_)
 {
        printk(KERN_ERR "simserial: do_softint called\n");
 }
@@ -241,7 +231,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
        local_irq_restore(flags);
 }
 
-static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
+static void transmit_chars(struct async_struct *info, int *intr_done)
 {
        int count;
        unsigned long flags;
@@ -275,7 +265,7 @@ static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
         * Then from the beginning of the buffer until necessary
         */
 
-       count = MIN(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE),
+       count = min(CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE),
                    SERIAL_XMIT_SIZE - info->xmit.tail);
        console->write(console, info->xmit.buf+info->xmit.tail, count);
 
@@ -305,7 +295,7 @@ static void rs_flush_chars(struct tty_struct *tty)
 }
 
 
-static int rs_write(struct tty_struct * tty, int from_user,
+static int rs_write(struct tty_struct * tty,
                    const unsigned char *buf, int count)
 {
        int     c, ret = 0;
@@ -314,58 +304,22 @@ static int rs_write(struct tty_struct * tty, int from_user,
 
        if (!tty || !info->xmit.buf || !tmp_buf) return 0;
 
-       if (from_user) {
-               down(&tmp_buf_sem);
-               while (1) {
-                       int c1;
-                       c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-                       if (count < c)
-                               c = count;
-                       if (c <= 0)
-                               break;
-
-                       c -= copy_from_user(tmp_buf, buf, c);
-                       if (!c) {
-                               if (!ret)
-                                       ret = -EFAULT;
-                               break;
-                       }
-
-                       local_irq_save(flags);
-                       {
-                               c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail,
-                                                      SERIAL_XMIT_SIZE);
-                               if (c1 < c)
-                                       c = c1;
-                               memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
-                               info->xmit.head = ((info->xmit.head + c) &
-                                                  (SERIAL_XMIT_SIZE-1));
-                       }
-                       local_irq_restore(flags);
-
-                       buf += c;
-                       count -= c;
-                       ret += c;
-               }
-               up(&tmp_buf_sem);
-       } else {
-               local_irq_save(flags);
-               while (1) {
-                       c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
-                       if (count < c)
-                               c = count;
-                       if (c <= 0) {
-                               break;
-                       }
-                       memcpy(info->xmit.buf + info->xmit.head, buf, c);
-                       info->xmit.head = ((info->xmit.head + c) &
-                                          (SERIAL_XMIT_SIZE-1));
-                       buf += c;
-                       count -= c;
-                       ret += c;
+       local_irq_save(flags);
+       while (1) {
+               c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
+               if (count < c)
+                       c = count;
+               if (c <= 0) {
+                       break;
                }
-               local_irq_restore(flags);
+               memcpy(info->xmit.buf + info->xmit.head, buf, c);
+               info->xmit.head = ((info->xmit.head + c) &
+                                  (SERIAL_XMIT_SIZE-1));
+               buf += c;
+               count -= c;
+               ret += c;
        }
+       local_irq_restore(flags);
        /*
         * Hey, we transmit directly from here in our case
         */
@@ -534,7 +488,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
 
 #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
 
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        unsigned int cflag = tty->termios->c_cflag;
 
@@ -601,7 +555,7 @@ static void shutdown(struct async_struct * info)
 
                if (info->xmit.buf) {
                        free_page((unsigned long) info->xmit.buf);
-                       info->xmit.buf = 0;
+                       info->xmit.buf = NULL;
                }
 
                if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -674,12 +628,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty);
        if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
        info->event = 0;
-       info->tty = 0;
+       info->tty = NULL;
        if (info->blocked_open) {
-               if (info->close_delay) {
-                       current->state = TASK_INTERRUPTIBLE;
-                       schedule_timeout(info->close_delay);
-               }
+               if (info->close_delay)
+                       schedule_timeout_interruptible(info->close_delay);
                wake_up_interruptible(&info->open_wait);
        }
        info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
@@ -716,7 +668,7 @@ static void rs_hangup(struct tty_struct *tty)
        info->event = 0;
        state->count = 0;
        info->flags &= ~ASYNC_NORMAL_ACTIVE;
-       info->tty = 0;
+       info->tty = NULL;
        wake_up_interruptible(&info->open_wait);
 }
 
@@ -732,12 +684,11 @@ static int get_async_struct(int line, struct async_struct **ret_info)
                *ret_info = sstate->info;
                return 0;
        }
-       info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+       info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
        if (!info) {
                sstate->count--;
                return -ENOMEM;
        }
-       memset(info, 0, sizeof(struct async_struct));
        init_waitqueue_head(&info->open_wait);
        init_waitqueue_head(&info->close_wait);
        init_waitqueue_head(&info->delta_msr_wait);
@@ -746,7 +697,7 @@ static int get_async_struct(int line, struct async_struct **ret_info)
        info->flags = sstate->flags;
        info->xmit_fifo_size = sstate->xmit_fifo_size;
        info->line = line;
-       INIT_WORK(&info->work, do_softint, info);
+       INIT_WORK(&info->work, do_softint);
        info->state = sstate;
        if (sstate->info) {
                kfree(info);
@@ -762,7 +713,7 @@ startup(struct async_struct *info)
 {
        unsigned long flags;
        int     retval=0;
-       irqreturn_t (*handler)(int, void *, struct pt_regs *);
+       irq_handler_t handler;
        struct serial_state *state= info->state;
        unsigned long page;
 
@@ -817,7 +768,7 @@ startup(struct async_struct *info)
        /*
         * Insert serial port into IRQ chain.
         */
-       info->prev_port = 0;
+       info->prev_port = NULL;
        info->next_port = IRQ_ports[state->irq];
        if (info->next_port)
                info->next_port->prev_port = info;
@@ -988,7 +939,7 @@ static inline void show_serial_version(void)
        printk(KERN_INFO " no serial options enabled\n");
 }
 
-static struct tty_operations hp_ops = {
+static const struct tty_operations hp_ops = {
        .open = rs_open,
        .close = rs_close,
        .write = rs_write,
@@ -1016,7 +967,7 @@ static struct tty_operations hp_ops = {
 static int __init
 simrs_init (void)
 {
-       int                     i;
+       int                     i, rc;
        struct serial_state     *state;
 
        if (!ia64_platform_is("hpsim"))
@@ -1051,11 +1002,14 @@ simrs_init (void)
                if (state->type == PORT_UNKNOWN) continue;
 
                if (!state->irq) {
-                       state->irq = assign_irq_vector(AUTO_ASSIGN);
+                       if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
+                               panic("%s: out of interrupt vectors!\n",
+                                     __FUNCTION__);
+                       state->irq = rc;
                        ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
                }
 
-               printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n",
+               printk(KERN_INFO "ttyS%d at 0x%04lx (irq = %d) is a %s\n",
                       state->line,
                       state->port, state->irq,
                       uart_config[state->type].name);