* 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
{ "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;
static struct console *console;
static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
extern struct console *console_drivers; /* from kernel/printk.c */
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;
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);
}
/*
* 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;
* 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;
}
}
#endif
-static void do_softint(void *private_)
+static void do_softint(struct work_struct *private_)
{
printk(KERN_ERR "simserial: do_softint called\n");
}
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;
* 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);
}
-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;
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
*/
#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;
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);
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);
info->event = 0;
state->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->tty = 0;
+ info->tty = NULL;
wake_up_interruptible(&info->open_wait);
}
*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);
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);
{
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;
/*
* 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;
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,
static int __init
simrs_init (void)
{
- int i;
+ int i, rc;
struct serial_state *state;
if (!ia64_platform_is("hpsim"))
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);