drm/drm_crtc: return -EFAULT on copy_to_user errors
[safe/jmp/linux-2.6] / drivers / serial / 68328serial.c
index b88a7c1..3046386 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/config.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
@@ -34,9 +33,9 @@
 #include <linux/keyboard.h>
 #include <linux/init.h>
 #include <linux/pm.h>
-#include <linux/pm_legacy.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/gfp.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -68,7 +67,6 @@
 #endif
 
 static struct m68k_serial m68k_soft[NR_PORTS];
-struct m68k_serial *IRQ_ports[NR_IRQS];
 
 static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
 
@@ -86,9 +84,6 @@ extern wait_queue_head_t keypress_wait;
 
 struct tty_driver *serial_driver;
 
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL     1
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -131,17 +126,6 @@ static int m68328_console_baud    = CONSOLE_BAUD_RATE;
 static int m68328_console_cbaud   = DEFAULT_CBAUD;
 
 
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */
-
 static inline int serial_paranoia_check(struct m68k_serial *info,
                                        char *name, const char *routine)
 {
@@ -170,8 +154,6 @@ static int baud_table[] = {
        0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
        9600, 19200, 38400, 57600, 115200, 0 };
 
-#define BAUD_TABLE_SIZE (sizeof(baud_table)/sizeof(baud_table[0]))
-
 /* Sets or clears DTR/RTS on the requested line */
 static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
 {
@@ -211,16 +193,16 @@ static void rs_stop(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_stop"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        uart->ustcnt &= ~USTCNT_TXEN;
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
-static void rs_put_char(char ch)
+static int rs_put_char(char ch)
 {
         int flags, loops = 0;
 
-        save_flags(flags); cli();
+        local_irq_save(flags);
 
        while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
                loops++;
@@ -229,7 +211,8 @@ static void rs_put_char(char ch)
 
        UTX_TXDATA = ch;
         udelay(5);
-        restore_flags(flags);
+        local_irq_restore(flags);
+        return 1;
 }
 
 static void rs_start(struct tty_struct *tty)
@@ -241,7 +224,7 @@ static void rs_start(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_start"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
 #ifdef USE_INTS
                uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
@@ -249,7 +232,7 @@ static void rs_start(struct tty_struct *tty)
                uart->ustcnt |= USTCNT_TXEN;
 #endif
        }
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 /* Drop into either the boot monitor or kadb upon receiving a break
@@ -264,7 +247,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status)
 {
 #if 0
        if(status & DCD) {
-               if((info->tty->termios->c_cflag & CRTSCTS) &&
+               if((info->port.tty->termios->c_cflag & CRTSCTS) &&
                   ((info->curregs[3] & AUTO_ENAB)==0)) {
                        info->curregs[3] |= AUTO_ENAB;
                        info->pendregs[3] |= AUTO_ENAB;
@@ -287,10 +270,9 @@ static void status_handle(struct m68k_serial *info, unsigned short status)
        return;
 }
 
-static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
-                         unsigned short rx)
+static void receive_chars(struct m68k_serial *info, unsigned short rx)
 {
-       struct tty_struct *tty = info->tty;
+       struct tty_struct *tty = info->port.tty;
        m68328_uart *uart = &uart_addr[info->line];
        unsigned char ch, flag;
 
@@ -327,14 +309,6 @@ static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
                if(!tty)
                        goto clear_and_exit;
                
-               /*
-                * Make sure that we do not overflow the buffer
-                */
-               if (tty_request_buffer_room(tty, 1) == 0) {
-                       tty_schedule_flip(tty);
-                       return;
-               }
-
                flag = TTY_NORMAL;
 
                if(rx & URX_PARITY_ERROR) {
@@ -369,7 +343,7 @@ static void transmit_chars(struct m68k_serial *info)
                goto clear_and_return;
        }
 
-       if((info->xmit_cnt <= 0) || info->tty->stopped) {
+       if((info->xmit_cnt <= 0) || info->port.tty->stopped) {
                /* That's peculiar... TX ints off */
                uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
                goto clear_and_return;
@@ -397,37 +371,33 @@ clear_and_return:
 /*
  * This is the serial driver's generic interrupt routine
  */
-irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t rs_interrupt(int irq, void *dev_id)
 {
-       struct m68k_serial * info;
+       struct m68k_serial *info = dev_id;
        m68328_uart *uart;
        unsigned short rx;
        unsigned short tx;
 
-       info = IRQ_ports[irq];
-       if(!info)
-           return IRQ_NONE;
-
        uart = &uart_addr[info->line];
        rx = uart->urx.w;
 
 #ifdef USE_INTS
        tx = uart->utx.w;
 
-       if (rx & URX_DATA_READY) receive_chars(info, regs, rx);
+       if (rx & URX_DATA_READY) receive_chars(info, rx);
        if (tx & UTX_TX_AVAIL)   transmit_chars(info);
 #else
-       receive_chars(info, regs, rx);          
+       receive_chars(info, rx);                
 #endif
        return IRQ_HANDLED;
 }
 
-static void do_softint(void *private)
+static void do_softint(struct work_struct *work)
 {
-       struct m68k_serial      *info = (struct m68k_serial *) private;
+       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue);
        struct tty_struct       *tty;
        
-       tty = info->tty;
+       tty = info->port.tty;
        if (!tty)
                return;
 #if 0
@@ -446,12 +416,12 @@ static void do_softint(void *private)
  *     do_serial_hangup() -> tty->hangup() -> rs_hangup()
  * 
  */
-static void do_serial_hangup(void *private)
+static void do_serial_hangup(struct work_struct *work)
 {
-       struct m68k_serial      *info = (struct m68k_serial *) private;
+       struct m68k_serial      *info = container_of(work, struct m68k_serial, tqueue_hangup);
        struct tty_struct       *tty;
        
-       tty = info->tty;
+       tty = info->port.tty;
        if (!tty)
                return;
 
@@ -473,7 +443,7 @@ static int startup(struct m68k_serial * info)
                        return -ENOMEM;
        }
 
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        /*
         * Clear the FIFO buffers and disable them
@@ -495,8 +465,8 @@ static int startup(struct m68k_serial * info)
        uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
 #endif
 
-       if (info->tty)
-               clear_bit(TTY_IO_ERROR, &info->tty->flags);
+       if (info->port.tty)
+               clear_bit(TTY_IO_ERROR, &info->port.tty->flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
        /*
@@ -506,7 +476,7 @@ static int startup(struct m68k_serial * info)
        change_speed(info);
 
        info->flags |= S_INITIALIZED;
-       restore_flags(flags);
+       local_irq_restore(flags);
        return 0;
 }
 
@@ -523,18 +493,18 @@ static void shutdown(struct m68k_serial * info)
        if (!(info->flags & S_INITIALIZED))
                return;
 
-       save_flags(flags); cli(); /* Disable interrupts */
+       local_irq_save(flags);
        
        if (info->xmit_buf) {
                free_page((unsigned long) info->xmit_buf);
                info->xmit_buf = 0;
        }
 
-       if (info->tty)
-               set_bit(TTY_IO_ERROR, &info->tty->flags);
+       if (info->port.tty)
+               set_bit(TTY_IO_ERROR, &info->port.tty->flags);
        
        info->flags &= ~S_INITIALIZED;
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 struct {
@@ -597,9 +567,9 @@ static void change_speed(struct m68k_serial *info)
        unsigned cflag;
        int     i;
 
-       if (!info->tty || !info->tty->termios)
+       if (!info->port.tty || !info->port.tty->termios)
                return;
-       cflag = info->tty->termios->c_cflag;
+       cflag = info->port.tty->termios->c_cflag;
        if (!(port = info->port))
                return;
 
@@ -655,24 +625,24 @@ static void rs_fair_output(void)
        if (info == 0) return;
        if (info->xmit_buf == 0) return;
 
-       save_flags(flags);  cli();
+       local_irq_save(flags);
        left = info->xmit_cnt;
        while (left != 0) {
                c = info->xmit_buf[info->xmit_tail];
                info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt--;
-               restore_flags(flags);
+               local_irq_restore(flags);
 
                rs_put_char(c);
 
-               save_flags(flags);  cli();
+               local_irq_save(flags);
                left = min(info->xmit_cnt, left-1);
        }
 
        /* Last character is being transmitted now (hopefully). */
        udelay(5);
 
-       restore_flags(flags);
+       local_irq_restore(flags);
        return;
 }
 
@@ -720,11 +690,11 @@ static void rs_flush_chars(struct tty_struct *tty)
 #endif
 
        /* Enable transmitter */
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
                        !info->xmit_buf) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
 
@@ -749,7 +719,7 @@ static void rs_flush_chars(struct tty_struct *tty)
        while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
        }
 #endif
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 extern void console_printn(const char * b, int count);
@@ -768,18 +738,22 @@ static int rs_write(struct tty_struct * tty,
        if (!tty || !info->xmit_buf)
                return 0;
 
-       save_flags(flags);
+       local_save_flags(flags);
        while (1) {
-               cli();          
+               local_irq_disable();            
                c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
                                   SERIAL_XMIT_SIZE - info->xmit_head));
+               local_irq_restore(flags);
+
                if (c <= 0)
                        break;
 
                memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+               local_irq_disable();
                info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
                info->xmit_cnt += c;
-               restore_flags(flags);
+               local_irq_restore(flags);
                buf += c;
                count -= c;
                total += c;
@@ -787,7 +761,7 @@ static int rs_write(struct tty_struct * tty,
 
        if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
                /* Enable transmitter */
-               cli();          
+               local_irq_disable();            
 #ifndef USE_INTS
                while(info->xmit_cnt) {
 #endif
@@ -807,9 +781,9 @@ static int rs_write(struct tty_struct * tty,
 #ifndef USE_INTS
                }
 #endif
-               restore_flags(flags);
+               local_irq_restore(flags);
        }
-       restore_flags(flags);
+
        return total;
 }
 
@@ -838,12 +812,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
 static void rs_flush_buffer(struct tty_struct *tty)
 {
        struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+       unsigned long flags;
                                
        if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
                return;
-       cli();
+       local_irq_save(flags);
        info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-       sti();
+       local_irq_restore(flags);
        tty_wakeup(tty);
 }
 
@@ -973,14 +948,15 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
        m68328_uart *uart = &uart_addr[info->line];
 #endif
        unsigned char status;
+       unsigned long flags;
 
-       cli();
+       local_irq_save(flags);
 #ifdef CONFIG_SERIAL_68328_RTS_CTS
        status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
 #else
        status = 0;
 #endif
-       sti();
+       local_irq_restore(flags);
        put_user(status,value);
        return 0;
 }
@@ -994,14 +970,13 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
         unsigned long flags;
         if (!info->port)
                 return;
-        save_flags(flags);
-        cli();
+        local_irq_save(flags);
 #ifdef USE_INTS        
        uart->utx.w |= UTX_SEND_BREAK;
        msleep_interruptible(duration);
        uart->utx.w &= ~UTX_SEND_BREAK;
 #endif         
-        restore_flags(flags);
+        local_irq_restore(flags);
 }
 
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
@@ -1037,18 +1012,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                        tty_wait_until_sent(tty, 0);
                        send_break(info, arg ? arg*(100) : 250);
                        return 0;
-               case TIOCGSOFTCAR:
-                       error = put_user(C_CLOCAL(tty) ? 1 : 0,
-                                   (unsigned long *) arg);
-                       if (error)
-                               return error;
-                       return 0;
-               case TIOCSSOFTCAR:
-                       get_user(arg, (unsigned long *) arg);
-                       tty->termios->c_cflag =
-                               ((tty->termios->c_cflag & ~CLOCAL) |
-                                (arg ? CLOCAL : 0));
-                       return 0;
                case TIOCGSERIAL:
                        if (access_ok(VERIFY_WRITE, (void *) arg,
                                                sizeof(struct serial_struct)))
@@ -1060,7 +1023,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
                                               (struct serial_struct *) arg);
                case TIOCSERGETLSR: /* Get line status register */
                        if (access_ok(VERIFY_WRITE, (void *) arg,
-                                               sizeof(unsigned int));
+                                               sizeof(unsigned int)))
                                return get_lsr_info(info, (unsigned int *) arg);
                        return -EFAULT;
                case TIOCSERGSTRUCT:
@@ -1077,13 +1040,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
        return 0;
 }
 
-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)
 {
        struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
 
-       if (tty->termios->c_cflag == old_termios->c_cflag)
-               return;
-
        change_speed(info);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1113,10 +1073,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
                return;
        
-       save_flags(flags); cli();
+       local_irq_save(flags);
        
        if (tty_hung_up_p(filp)) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
        
@@ -1138,7 +1098,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                info->count = 0;
        }
        if (info->count) {
-               restore_flags(flags);
+               local_irq_restore(flags);
                return;
        }
        info->flags |= S_CLOSING;
@@ -1160,13 +1120,12 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
 
        shutdown(info);
-       if (tty->driver->flush_buffer)
-               tty->driver->flush_buffer(tty);
+       rs_flush_buffer(tty);
                
        tty_ldisc_flush(tty);
        tty->closing = 0;
        info->event = 0;
-       info->tty = 0;
+       info->port.tty = NULL;
 #warning "This is not and has never been valid so fix it"      
 #if 0
        if (tty->ldisc.num != ldiscs[N_TTY].num) {
@@ -1186,7 +1145,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
        }
        info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
        wake_up_interruptible(&info->close_wait);
-       restore_flags(flags);
+       local_irq_restore(flags);
 }
 
 /*
@@ -1204,7 +1163,7 @@ void rs_hangup(struct tty_struct *tty)
        info->event = 0;
        info->count = 0;
        info->flags &= ~S_NORMAL_ACTIVE;
-       info->tty = 0;
+       info->port.tty = NULL;
        wake_up_interruptible(&info->open_wait);
 }
 
@@ -1262,9 +1221,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        info->count--;
        info->blocked_open++;
        while (1) {
-               cli();
+               local_irq_disable();
                m68k_rtsdtr(info, 1);
-               sti();
+               local_irq_enable();
                current->state = TASK_INTERRUPTIBLE;
                if (tty_hung_up_p(filp) ||
                    !(info->flags & S_INITIALIZED)) {
@@ -1321,7 +1280,7 @@ int rs_open(struct tty_struct *tty, struct file * filp)
 
        info->count++;
        tty->driver_data = info;
-       info->tty = tty;
+       info->port.tty = tty;
 
        /*
         * Start up serial port
@@ -1340,60 +1299,7 @@ static void show_serial_version(void)
        printk("MC68328 serial driver version 1.00\n");
 }
 
-#ifdef CONFIG_PM_LEGACY
-/* Serial Power management
- *  The console (currently fixed at line 0) is a special case for power
- *  management because the kernel is so chatty. The console will be 
- *  explicitly disabled my our power manager as the last minute, so we won't
- *  mess with it here.
- */
-static struct pm_dev *serial_pm[NR_PORTS];
-
-static int serial_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
-{
-       struct m68k_serial *info = (struct m68k_serial *)dev->data;
-
-       if(info == NULL)
-               return -1;
-
-       /* special case for line 0 - pm restores it */
-       if(info->line == 0)
-               return 0; 
-
-       switch (request) {
-       case PM_SUSPEND:
-               shutdown(info);
-               break;
-
-       case PM_RESUME:
-               startup(info);
-               break;
-       }
-       return 0;
-}
-
-void shutdown_console(void)
-{
-       struct m68k_serial *info = &m68k_soft[0];
-
-       /* HACK: wait a bit for any pending printk's to be dumped */
-       {
-               int i = 10000;
-               while(i--);
-       }
-
-       shutdown(info);
-}
-
-void startup_console(void)
-{
-       struct m68k_serial *info = &m68k_soft[0];
-       startup(info);
-}
-#endif /* CONFIG_PM_LEGACY */
-
-
-static struct tty_operations rs_ops = {
+static const struct tty_operations rs_ops = {
        .open = rs_open,
        .close = rs_close,
        .write = rs_write,
@@ -1444,14 +1350,14 @@ rs68328_init(void)
                return -ENOMEM;
        }
 
-       save_flags(flags); cli();
+       local_irq_save(flags);
 
        for(i=0;i<NR_PORTS;i++) {
 
            info = &m68k_soft[i];
            info->magic = SERIAL_MAGIC;
            info->port = (int) &uart_addr[i];
-           info->tty = 0;
+           info->port.tty = NULL;
            info->irq = uart_irqs[i];
            info->custom_divisor = 16;
            info->close_delay = 50;
@@ -1460,8 +1366,8 @@ rs68328_init(void)
            info->event = 0;
            info->count = 0;
            info->blocked_open = 0;
-           INIT_WORK(&info->tqueue, do_softint, info);
-           INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+           INIT_WORK(&info->tqueue, do_softint);
+           INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
            init_waitqueue_head(&info->open_wait);
            init_waitqueue_head(&info->close_wait);
            info->line = i;
@@ -1471,8 +1377,6 @@ rs68328_init(void)
                   info->port, info->irq);
            printk(" is a builtin MC68328 UART\n");
            
-           IRQ_ports[info->irq] = info;        /* waste of space */
-
 #ifdef CONFIG_M68VZ328
                if (i > 0 )
                        PJSEL &= 0xCF;  /* PSW enable second port output */
@@ -1480,16 +1384,11 @@ rs68328_init(void)
 
            if (request_irq(uart_irqs[i],
                            rs_interrupt,
-                           IRQ_FLG_STD,
-                           "M68328_UART", NULL))
+                           IRQF_DISABLED,
+                           "M68328_UART", info))
                 panic("Unable to attach 68328 serial interrupt\n");
-#ifdef CONFIG_PM_LEGACY
-           serial_pm[i] = pm_register(PM_SYS_DEV, PM_SYS_COM, serial_pm_callback);
-           if (serial_pm[i])
-                   serial_pm[i]->data = info;
-#endif
        }
-       restore_flags(flags);
+       local_irq_restore(flags);
        return 0;
 }
 
@@ -1506,10 +1405,10 @@ static void m68328_set_baud(void)
        USTCNT = ustcnt & ~USTCNT_TXEN;
 
 again:
-       for (i = 0; i < sizeof(baud_table) / sizeof(baud_table[0]); i++)
+       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
                if (baud_table[i] == m68328_console_baud)
                        break;
-       if (i >= sizeof(baud_table) / sizeof(baud_table[0])) {
+       if (i >= ARRAY_SIZE(baud_table)) {
                m68328_console_baud = 9600;
                goto again;
        }
@@ -1535,10 +1434,10 @@ int m68328_console_setup(struct console *cp, char *arg)
        if (arg)
                n = simple_strtoul(arg,NULL,0);
 
-       for (i = 0; i < BAUD_TABLE_SIZE; i++)
+       for (i = 0; i < ARRAY_SIZE(baud_table); i++)
                if (baud_table[i] == n)
                        break;
-       if (i < BAUD_TABLE_SIZE) {
+       if (i < ARRAY_SIZE(baud_table)) {
                m68328_console_baud = n;
                m68328_console_cbaud = 0;
                if (i > 15) {