// SPDX-License-Identifier: GPL-2.0/* * Serial driver for the amiga builtin port. * * This code was created by taking serial.c version 4.30 from kernel * release 2.3.22, replacing all hardware related stuff with the * corresponding amiga hardware actions, and removing all irrelevant * code. As a consequence, it uses many of the constants and names * associated with the registers and bits of 16550 compatible UARTS - * but only to keep track of status, etc in the state variables. It * was done this was to make it easier to keep the code in line with * (non hardware specific) changes to serial.c. * * The port is registered with the tty driver as minor device 64, and * therefore other ports should only use 65 upwards. * * Richard Lucock 28/12/99 * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, * 1998, 1999 Theodore Ts'o * */ /* Set of debugging defines */ #undef SERIAL_DEBUG_INTR#undef SERIAL_DEBUG_OPEN#undef SERIAL_DEBUG_FLOW#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT /* * End of serial driver configuration section. */ #include <linux/bitops.h>#include <linux/circ_buf.h>#include <linux/console.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fcntl.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/mm.h>#include <linux/module.h>#include <linux/platform_device.h>#include <linux/ptrace.h>#include <linux/seq_file.h>#include <linux/serial.h>#include <linux/serial_reg.h>#include <linux/serial_core.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/tty_flip.h>#include <linux/tty.h>#include <linux/types.h>#include <linux/uaccess.h> #include <asm/amigahw.h>#include <asm/amigaints.h>#include <asm/irq.h>#include <asm/setup.h> struct serial_state { struct tty_port tport; struct circ_buf xmit; struct async_icount icount; unsigned long port; int baud_base; int custom_divisor; int read_status_mask; int ignore_status_mask; int timeout; int quot; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ u8 x_char; /* xon/xoff character */}; static struct tty_driver *serial_driver; /* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256 #define XMIT_FIFO_SIZE 1 static unsigned char current_ctl_bits; static void change_speed(struct tty_struct *tty, struct serial_state *info, const struct ktermios *old);static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static struct serial_state serial_state; /* some serial hardware definitions */#define SDR_OVRUN (1<<15)#define SDR_RBF (1<<14)#define SDR_TBE (1<<13)#define SDR_TSRE (1<<12) #define SERPER_PARENB (1<<15) #define AC_SETCLR (1<<15)#define AC_UARTBRK (1<<11) #define SER_DTR (1<<7)#define SER_RTS (1<<6)#define SER_DCD (1<<5)#define SER_CTS (1<<4)#define SER_DSR (1<<3) static __inline__ void rtsdtr_ctrl(int bits){ ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR));} /* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->flow.stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */static void rs_stop(struct tty_struct *tty){ struct serial_state *info = tty->driver_data; unsigned long flags; local_irq_save(flags); if (info->IER & UART_IER_THRI) { info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ amiga_custom.intena = IF_TBE; mb(); amiga_custom.intreq = IF_TBE; mb(); } local_irq_restore(flags);} static void rs_start(struct tty_struct *tty){ struct serial_state *info = tty->driver_data; unsigned long flags; local_irq_save(flags); if (info->xmit.head != info->xmit.tail && info->xmit.buf && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); } local_irq_restore(flags);} /* * ---------------------------------------------------------------------- * * Here start the interrupt handling routines. * * ----------------------------------------------------------------------- */ static void receive_chars(struct serial_state *info){ int status; int serdatr; u8 ch, flag; struct async_icount *icount; bool overrun = false; icount = &info->icount; status = UART_LSR_DR; /* We obviously have a character! */ serdatr = amiga_custom.serdatr; mb(); amiga_custom.intreq = IF_RBF; mb(); if((serdatr & 0x1ff) == 0) status |= UART_LSR_BI; if(serdatr & SDR_OVRUN) status |= UART_LSR_OE; ch = serdatr & 0xff; icount->rx++; #ifdef SERIAL_DEBUG_INTR printk("DR%02x:%02x...", ch, status);#endif flag = TTY_NORMAL; /* * We don't handle parity or frame errors - but I have left * the code in, since I'm not sure that the errors can't be * detected. */ if (status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE)) { /* * For statistics only */ if (status & UART_LSR_BI) { status &= ~(UART_LSR_FE | UART_LSR_PE); icount->brk++; } else if (status & UART_LSR_PE) icount->parity++; else if (status & UART_LSR_FE) icount->frame++; if (status & UART_LSR_OE) icount->overrun++; /* * Now check to see if character should be * ignored, and mask off conditions which * should be ignored. */ if (status & info->ignore_status_mask) return; status &= info->read_status_mask; if (status & (UART_LSR_BI)) {#ifdef SERIAL_DEBUG_INTR printk("handling break....");#endif flag = TTY_BREAK; if (info->tport.flags & ASYNC_SAK) do_SAK(info->tport.tty); } else if (status & UART_LSR_PE) flag = TTY_PARITY; else if (status & UART_LSR_FE) flag = TTY_FRAME; if (status & UART_LSR_OE) { /* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ overrun = true; } } tty_insert_flip_char(&info->tport, ch, flag); if (overrun) tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN); tty_flip_buffer_push(&info->tport);} static void transmit_chars(struct serial_state *info){ amiga_custom.intreq = IF_TBE; mb(); if (info->x_char) { amiga_custom.serdat = info->x_char | 0x100; mb(); info->icount.tx++; info->x_char = 0; return; } if (info->xmit.head == info->xmit.tail || info->tport.tty->flow.stopped || info->tport.tty->hw_stopped) { info->IER &= ~UART_IER_THRI; amiga_custom.intena = IF_TBE; mb(); return; } amiga_custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; mb(); info->xmit.tail = info->xmit.tail & (UART_XMIT_SIZE - 1); info->icount.tx++; if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < WAKEUP_CHARS) tty_wakeup(info->tport.tty); #ifdef SERIAL_DEBUG_INTR printk("THRE...");#endif if (info->xmit.head == info->xmit.tail) { amiga_custom.intena = IF_TBE; mb(); info->IER &= ~UART_IER_THRI; }} static void check_modem_status(struct serial_state *info){ struct tty_port *port = &info->tport; unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); unsigned char dstatus; struct async_icount *icount; /* Determine bits that have changed */ dstatus = status ^ current_ctl_bits; current_ctl_bits = status; if (dstatus) { icount = &info->icount; /* update input line counters */ if (dstatus & SER_DSR) icount->dsr++; if (dstatus & SER_DCD) { icount->dcd++; } if (dstatus & SER_CTS) icount->cts++; wake_up_interruptible(&port->delta_msr_wait); } if (tty_port_check_carrier(port) && (dstatus & SER_DCD)) {#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off");#endif if (!(status & SER_DCD)) wake_up_interruptible(&port->open_wait); else {#ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup...");#endif if (port->tty) tty_hangup(port->tty); } } if (tty_port_cts_enabled(port)) { if (port->tty->hw_stopped) { if (!(status & SER_CTS)) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start...");#endif port->tty->hw_stopped = false; info->IER |= UART_IER_THRI; amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); tty_wakeup(port->tty); return; } } else { if ((status & SER_CTS)) {#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop...");#endif port->tty->hw_stopped = true; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ amiga_custom.intena = IF_TBE; mb(); amiga_custom.intreq = IF_TBE; mb(); } } }} static irqreturn_t ser_vbl_int( int irq, void *data){ /* vbl is just a periodic interrupt we tie into to update modem status */ struct serial_state *info = data; /* * TBD - is it better to unregister from this interrupt or to * ignore it if MSI is clear ? */ if(info->IER & UART_IER_MSI) check_modem_status(info); return IRQ_HANDLED;} static irqreturn_t ser_rx_int(int irq, void *dev_id){ struct serial_state *info = dev_id; #ifdef SERIAL_DEBUG_INTR printk("ser_rx_int...");#endif if (!info->tport.tty) return IRQ_NONE; receive_chars(info);#ifdef SERIAL_DEBUG_INTR printk("end.\n");#endif return IRQ_HANDLED;} static irqreturn_t ser_tx_int(int irq, void *dev_id){ struct serial_state *info = dev_id; if (amiga_custom.serdatr & SDR_TBE) {#ifdef SERIAL_DEBUG_INTR printk("ser_tx_int...");#endif if (!info->tport.tty) return IRQ_NONE; transmit_chars(info);#ifdef SERIAL_DEBUG_INTR printk("end.\n");#endif } return IRQ_HANDLED;} /* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- */ /* * --------------------------------------------------------------- * Low level utility subroutines for the serial driver: routines to * figure out the appropriate timeout for an interrupt chain, routines * to initialize and startup a serial port, and routines to shutdown a * serial port. Useful stuff like that. * --------------------------------------------------------------- */ static int rs_startup(struct tty_struct *tty, struct serial_state *info){ struct tty_port *port = &info->tport; unsigned long flags; int retval=0; void *buffer; buffer = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; local_irq_save(flags); if (tty_port_initialized(port)) { kfree(buffer); goto errout; } if (info->xmit.buf) kfree(buffer); else info->xmit.buf = buffer; #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d ...", info->line);#endif /* Clear anything in the input buffer */ amiga_custom.intreq = IF_RBF; mb(); retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); if (retval) { if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); retval = 0; } goto errout; } /* enable both Rx and Tx interrupts */ amiga_custom.intena = IF_SETCLR | IF_RBF | IF_TBE; mb(); info->IER = UART_IER_MSI; /* remember current state of the DCD and CTS bits */ current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); info->MCR = 0; if (C_BAUD(tty)) info->MCR = SER_DTR | SER_RTS; rtsdtr_ctrl(info->MCR); clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit.head = info->xmit.tail = 0; /* * and set the speed of the serial port */Lines 1–500 of 1665. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Serial driver for the amiga builtin port. * * This code was created by taking serial.c version 4.30 from kernel * release 2.3.22, replacing all hardware related stuff with the * corresponding amiga hardware actions, and removing all irrelevant * code. As a consequence, it uses many of the constants and names * associated with the registers and bits of 16550 compatible UARTS - * but only to keep track of status, etc in the state variables. It * was done this was to make it easier to keep the code in line with * (non hardware specific) changes to serial.c. * * The port is registered with the tty driver as minor device 64, and * therefore other ports should only use 65 upwards. * * Richard Lucock 28/12/99 * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, * 1998, 1999 Theodore Ts'o * */ /* Set of debugging defines */ #undef SERIAL_DEBUG_INTR #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT /* * End of serial driver configuration section. */ #include <linux/bitops.h> #include <linux/circ_buf.h> #include <linux/console.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/fcntl.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mm.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/ptrace.h> #include <linux/seq_file.h> #include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/serial_core.h> #include <linux/sched.h> #include <linux/signal.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/tty_flip.h> #include <linux/tty.h> #include <linux/types.h> #include <linux/uaccess.h> #include <asm/amigahw.h> #include <asm/amigaints.h> #include <asm/irq.h> #include <asm/setup.h> struct serial_state { struct tty_port tport; struct circ_buf xmit; struct async_icount icount; unsigned long port; int baud_base; int custom_divisor; int read_status_mask; int ignore_status_mask; int timeout; int quot; int IER; /* Interrupt Enable Register */ int MCR; /* Modem control register */ u8 x_char; /* xon/xoff character */ }; static struct tty_driver *serial_driver; /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 #define XMIT_FIFO_SIZE 1 static unsigned char current_ctl_bits; static void change_speed(struct tty_struct *tty, struct serial_state *info, const struct ktermios *old); static void rs_wait_until_sent(struct tty_struct *tty, int timeout); static struct serial_state serial_state; /* some serial hardware definitions */ #define SDR_OVRUN (1<<15) #define SDR_RBF (1<<14) #define SDR_TBE (1<<13) #define SDR_TSRE (1<<12) #define SERPER_PARENB (1<<15) #define AC_SETCLR (1<<15) #define AC_UARTBRK (1<<11) #define SER_DTR (1<<7) #define SER_RTS (1<<6) #define SER_DCD (1<<5) #define SER_CTS (1<<4) #define SER_DSR (1<<3) static __inline__ void rtsdtr_ctrl(int bits) { ciab.pra = ((bits & (SER_RTS | SER_DTR)) ^ (SER_RTS | SER_DTR)) | (ciab.pra & ~(SER_RTS | SER_DTR)); } /* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->flow.stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */ static void rs_stop(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; unsigned long flags; local_irq_save(flags); if (info->IER & UART_IER_THRI) { info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ amiga_custom.intena = IF_TBE; mb(); amiga_custom.intreq = IF_TBE; mb(); } local_irq_restore(flags); } static void rs_start(struct tty_struct *tty) { struct serial_state *info = tty->driver_data; unsigned long flags; local_irq_save(flags); if (info->xmit.head != info->xmit.tail && info->xmit.buf && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); } local_irq_restore(flags); } /* * ---------------------------------------------------------------------- * * Here start the interrupt handling routines. * * ----------------------------------------------------------------------- */ static void receive_chars(struct serial_state *info) { int status; int serdatr; u8 ch, flag; struct async_icount *icount; bool overrun = false; icount = &info->icount; status = UART_LSR_DR; /* We obviously have a character! */ serdatr = amiga_custom.serdatr; mb(); amiga_custom.intreq = IF_RBF; mb(); if((serdatr & 0x1ff) == 0) status |= UART_LSR_BI; if(serdatr & SDR_OVRUN) status |= UART_LSR_OE; ch = serdatr & 0xff; icount->rx++; #ifdef SERIAL_DEBUG_INTR printk("DR%02x:%02x...", ch, status); #endif flag = TTY_NORMAL; /* * We don't handle parity or frame errors - but I have left * the code in, since I'm not sure that the errors can't be * detected. */ if (status & (UART_LSR_BI | UART_LSR_PE | UART_LSR_FE | UART_LSR_OE)) { /* * For statistics only */ if (status & UART_LSR_BI) { status &= ~(UART_LSR_FE | UART_LSR_PE); icount->brk++; } else if (status & UART_LSR_PE) icount->parity++; else if (status & UART_LSR_FE) icount->frame++; if (status & UART_LSR_OE) icount->overrun++; /* * Now check to see if character should be * ignored, and mask off conditions which * should be ignored. */ if (status & info->ignore_status_mask) return; status &= info->read_status_mask; if (status & (UART_LSR_BI)) { #ifdef SERIAL_DEBUG_INTR printk("handling break...."); #endif flag = TTY_BREAK; if (info->tport.flags & ASYNC_SAK) do_SAK(info->tport.tty); } else if (status & UART_LSR_PE) flag = TTY_PARITY; else if (status & UART_LSR_FE) flag = TTY_FRAME; if (status & UART_LSR_OE) { /* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ overrun = true; } } tty_insert_flip_char(&info->tport, ch, flag); if (overrun) tty_insert_flip_char(&info->tport, 0, TTY_OVERRUN); tty_flip_buffer_push(&info->tport); } static void transmit_chars(struct serial_state *info) { amiga_custom.intreq = IF_TBE; mb(); if (info->x_char) { amiga_custom.serdat = info->x_char | 0x100; mb(); info->icount.tx++; info->x_char = 0; return; } if (info->xmit.head == info->xmit.tail || info->tport.tty->flow.stopped || info->tport.tty->hw_stopped) { info->IER &= ~UART_IER_THRI; amiga_custom.intena = IF_TBE; mb(); return; } amiga_custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100; mb(); info->xmit.tail = info->xmit.tail & (UART_XMIT_SIZE - 1); info->icount.tx++; if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) < WAKEUP_CHARS) tty_wakeup(info->tport.tty); #ifdef SERIAL_DEBUG_INTR printk("THRE..."); #endif if (info->xmit.head == info->xmit.tail) { amiga_custom.intena = IF_TBE; mb(); info->IER &= ~UART_IER_THRI; } } static void check_modem_status(struct serial_state *info) { struct tty_port *port = &info->tport; unsigned char status = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); unsigned char dstatus; struct async_icount *icount; /* Determine bits that have changed */ dstatus = status ^ current_ctl_bits; current_ctl_bits = status; if (dstatus) { icount = &info->icount; /* update input line counters */ if (dstatus & SER_DSR) icount->dsr++; if (dstatus & SER_DCD) { icount->dcd++; } if (dstatus & SER_CTS) icount->cts++; wake_up_interruptible(&port->delta_msr_wait); } if (tty_port_check_carrier(port) && (dstatus & SER_DCD)) { #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttyS%d CD now %s...", info->line, (!(status & SER_DCD)) ? "on" : "off"); #endif if (!(status & SER_DCD)) wake_up_interruptible(&port->open_wait); else { #ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup..."); #endif if (port->tty) tty_hangup(port->tty); } } if (tty_port_cts_enabled(port)) { if (port->tty->hw_stopped) { if (!(status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx start..."); #endif port->tty->hw_stopped = false; info->IER |= UART_IER_THRI; amiga_custom.intena = IF_SETCLR | IF_TBE; mb(); /* set a pending Tx Interrupt, transmitter should restart now */ amiga_custom.intreq = IF_SETCLR | IF_TBE; mb(); tty_wakeup(port->tty); return; } } else { if ((status & SER_CTS)) { #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) printk("CTS tx stop..."); #endif port->tty->hw_stopped = true; info->IER &= ~UART_IER_THRI; /* disable Tx interrupt and remove any pending interrupts */ amiga_custom.intena = IF_TBE; mb(); amiga_custom.intreq = IF_TBE; mb(); } } } } static irqreturn_t ser_vbl_int( int irq, void *data) { /* vbl is just a periodic interrupt we tie into to update modem status */ struct serial_state *info = data; /* * TBD - is it better to unregister from this interrupt or to * ignore it if MSI is clear ? */ if(info->IER & UART_IER_MSI) check_modem_status(info); return IRQ_HANDLED; } static irqreturn_t ser_rx_int(int irq, void *dev_id) { struct serial_state *info = dev_id; #ifdef SERIAL_DEBUG_INTR printk("ser_rx_int..."); #endif if (!info->tport.tty) return IRQ_NONE; receive_chars(info); #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif return IRQ_HANDLED; } static irqreturn_t ser_tx_int(int irq, void *dev_id) { struct serial_state *info = dev_id; if (amiga_custom.serdatr & SDR_TBE) { #ifdef SERIAL_DEBUG_INTR printk("ser_tx_int..."); #endif if (!info->tport.tty) return IRQ_NONE; transmit_chars(info); #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif } return IRQ_HANDLED; } /* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- */ /* * --------------------------------------------------------------- * Low level utility subroutines for the serial driver: routines to * figure out the appropriate timeout for an interrupt chain, routines * to initialize and startup a serial port, and routines to shutdown a * serial port. Useful stuff like that. * --------------------------------------------------------------- */ static int rs_startup(struct tty_struct *tty, struct serial_state *info) { struct tty_port *port = &info->tport; unsigned long flags; int retval=0; void *buffer; buffer = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!buffer) return -ENOMEM; local_irq_save(flags); if (tty_port_initialized(port)) { kfree(buffer); goto errout; } if (info->xmit.buf) kfree(buffer); else info->xmit.buf = buffer; #ifdef SERIAL_DEBUG_OPEN printk("starting up ttys%d ...", info->line); #endif /* Clear anything in the input buffer */ amiga_custom.intreq = IF_RBF; mb(); retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info); if (retval) { if (capable(CAP_SYS_ADMIN)) { set_bit(TTY_IO_ERROR, &tty->flags); retval = 0; } goto errout; } /* enable both Rx and Tx interrupts */ amiga_custom.intena = IF_SETCLR | IF_RBF | IF_TBE; mb(); info->IER = UART_IER_MSI; /* remember current state of the DCD and CTS bits */ current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); info->MCR = 0; if (C_BAUD(tty)) info->MCR = SER_DTR | SER_RTS; rtsdtr_ctrl(info->MCR); clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit.head = info->xmit.tail = 0; /* * and set the speed of the serial port */