diff options
Diffstat (limited to 'drivers/tty/amiserial.c')
| -rw-r--r-- | drivers/tty/amiserial.c | 730 | 
1 files changed, 222 insertions, 508 deletions
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index b84c83456dc..afadcd43d14 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -45,7 +45,7 @@  #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)  #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, (info->flags), serial_driver->refcount,info->count,tty->count,s) + tty->name, (info->tport.flags), serial_driver->refcount,info->count,tty->count,s)  #else  #define DBG_CNT(s)  #endif @@ -58,7 +58,6 @@  #include <linux/types.h>  #include <linux/serial.h> -#include <linux/serialP.h>  #include <linux/serial_reg.h>  static char *serial_version = "4.30"; @@ -70,6 +69,7 @@ static char *serial_version = "4.30";  #include <linux/interrupt.h>  #include <linux/tty.h>  #include <linux/tty_flip.h> +#include <linux/circ_buf.h>  #include <linux/console.h>  #include <linux/major.h>  #include <linux/string.h> @@ -92,6 +92,24 @@ static char *serial_version = "4.30";  #include <asm/amigahw.h>  #include <asm/amigaints.h> +struct serial_state { +	struct tty_port		tport; +	struct circ_buf		xmit; +	struct async_icount	icount; + +	unsigned long		port; +	int			baud_base; +	int			xmit_fifo_size; +	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 */ +	int			x_char;	/* xon/xoff character */ +}; +  #define custom amiga_custom  static char *serial_name = "Amiga-builtin serial driver"; @@ -100,11 +118,10 @@ static struct tty_driver *serial_driver;  /* number of characters left in xmit buffer before we ask for more */  #define WAKEUP_CHARS 256 -static struct async_struct *IRQ_ports; -  static unsigned char current_ctl_bits; -static void change_speed(struct async_struct *info, struct ktermios *old); +static void change_speed(struct tty_struct *tty, struct serial_state *info, +		struct ktermios *old);  static void rs_wait_until_sent(struct tty_struct *tty, int timeout); @@ -117,7 +134,7 @@ static struct serial_state rs_table[1];  #define serial_isroot()	(capable(CAP_SYS_ADMIN)) -static inline int serial_paranoia_check(struct async_struct *info, +static inline int serial_paranoia_check(struct serial_state *info,  					char *name, const char *routine)  {  #ifdef SERIAL_PARANOIA_CHECK @@ -170,7 +187,7 @@ static __inline__ void rtsdtr_ctrl(int bits)   */  static void rs_stop(struct tty_struct *tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_stop")) @@ -190,7 +207,7 @@ static void rs_stop(struct tty_struct *tty)  static void rs_start(struct tty_struct *tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_start")) @@ -231,27 +248,16 @@ static void rs_start(struct tty_struct *tty)   * -----------------------------------------------------------------------   */ -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static void rs_sched_event(struct async_struct *info, -			   int event) -{ -	info->event |= 1 << event; -	tasklet_schedule(&info->tlet); -} - -static void receive_chars(struct async_struct *info) +static void receive_chars(struct serial_state *info)  {          int status;  	int serdatr; -	struct tty_struct *tty = info->tty; +	struct tty_struct *tty = info->tport.tty;  	unsigned char ch, flag;  	struct	async_icount *icount;  	int oe = 0; -	icount = &info->state->icount; +	icount = &info->icount;  	status = UART_LSR_DR; /* We obviously have a character! */  	serdatr = custom.serdatr; @@ -308,7 +314,7 @@ static void receive_chars(struct async_struct *info)  	    printk("handling break....");  #endif  	    flag = TTY_BREAK; -	    if (info->flags & ASYNC_SAK) +	    if (info->tport.flags & ASYNC_SAK)  	      do_SAK(tty);  	  } else if (status & UART_LSR_PE)  	    flag = TTY_PARITY; @@ -331,20 +337,20 @@ out:  	return;  } -static void transmit_chars(struct async_struct *info) +static void transmit_chars(struct serial_state *info)  {  	custom.intreq = IF_TBE;  	mb();  	if (info->x_char) {  	        custom.serdat = info->x_char | 0x100;  		mb(); -		info->state->icount.tx++; +		info->icount.tx++;  		info->x_char = 0;  		return;  	}  	if (info->xmit.head == info->xmit.tail -	    || info->tty->stopped -	    || info->tty->hw_stopped) { +	    || info->tport.tty->stopped +	    || info->tport.tty->hw_stopped) {  		info->IER &= ~UART_IER_THRI;  	        custom.intena = IF_TBE;  		mb(); @@ -354,12 +360,12 @@ static void transmit_chars(struct async_struct *info)  	custom.serdat = info->xmit.buf[info->xmit.tail++] | 0x100;  	mb();  	info->xmit.tail = info->xmit.tail & (SERIAL_XMIT_SIZE-1); -	info->state->icount.tx++; +	info->icount.tx++;  	if (CIRC_CNT(info->xmit.head,  		     info->xmit.tail,  		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS) -		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); +		tty_wakeup(info->tport.tty);  #ifdef SERIAL_DEBUG_INTR  	printk("THRE..."); @@ -371,8 +377,9 @@ static void transmit_chars(struct async_struct *info)  	}  } -static void check_modem_status(struct async_struct *info) +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; @@ -382,52 +389,52 @@ static void check_modem_status(struct async_struct *info)  	current_ctl_bits = status;  	if (dstatus) { -		icount = &info->state->icount; +		icount = &info->icount;  		/* update input line counters */  		if (dstatus & SER_DSR)  			icount->dsr++;  		if (dstatus & SER_DCD) {  			icount->dcd++;  #ifdef CONFIG_HARD_PPS -			if ((info->flags & ASYNC_HARDPPS_CD) && +			if ((port->flags & ASYNC_HARDPPS_CD) &&  			    !(status & SER_DCD))  				hardpps();  #endif  		}  		if (dstatus & SER_CTS)  			icount->cts++; -		wake_up_interruptible(&info->delta_msr_wait); +		wake_up_interruptible(&port->delta_msr_wait);  	} -	if ((info->flags & ASYNC_CHECK_CD) && (dstatus & SER_DCD)) { +	if ((port->flags & ASYNC_CHECK_CD) && (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(&info->open_wait); +			wake_up_interruptible(&port->open_wait);  		else {  #ifdef SERIAL_DEBUG_OPEN  			printk("doing serial hangup...");  #endif -			if (info->tty) -				tty_hangup(info->tty); +			if (port->tty) +				tty_hangup(port->tty);  		}  	} -	if (info->flags & ASYNC_CTS_FLOW) { -		if (info->tty->hw_stopped) { +	if (port->flags & ASYNC_CTS_FLOW) { +		if (port->tty->hw_stopped) {  			if (!(status & SER_CTS)) {  #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))  				printk("CTS tx start...");  #endif -				info->tty->hw_stopped = 0; +				port->tty->hw_stopped = 0;  				info->IER |= UART_IER_THRI;  				custom.intena = IF_SETCLR | IF_TBE;  				mb();  				/* set a pending Tx Interrupt, transmitter should restart now */  				custom.intreq = IF_SETCLR | IF_TBE;  				mb(); -				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); +				tty_wakeup(port->tty);  				return;  			}  		} else { @@ -435,7 +442,7 @@ static void check_modem_status(struct async_struct *info)  #if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))  				printk("CTS tx stop...");  #endif -				info->tty->hw_stopped = 1; +				port->tty->hw_stopped = 1;  				info->IER &= ~UART_IER_THRI;  				/* disable Tx interrupt and remove any pending interrupts */  				custom.intena = IF_TBE; @@ -450,7 +457,7 @@ static void check_modem_status(struct async_struct *info)  static irqreturn_t ser_vbl_int( int irq, void *data)  {          /* vbl is just a periodic interrupt we tie into to update modem status */ -	struct async_struct * info = IRQ_ports; +	struct serial_state *info = data;  	/*  	 * TBD - is it better to unregister from this interrupt or to  	 * ignore it if MSI is clear ? @@ -462,18 +469,16 @@ static irqreturn_t ser_vbl_int( int irq, void *data)  static irqreturn_t ser_rx_int(int irq, void *dev_id)  { -	struct async_struct * info; +	struct serial_state *info = dev_id;  #ifdef SERIAL_DEBUG_INTR  	printk("ser_rx_int...");  #endif -	info = IRQ_ports; -	if (!info || !info->tty) +	if (!info->tport.tty)  		return IRQ_NONE;  	receive_chars(info); -	info->last_active = jiffies;  #ifdef SERIAL_DEBUG_INTR  	printk("end.\n");  #endif @@ -482,19 +487,17 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id)  static irqreturn_t ser_tx_int(int irq, void *dev_id)  { -	struct async_struct * info; +	struct serial_state *info = dev_id;  	if (custom.serdatr & SDR_TBE) {  #ifdef SERIAL_DEBUG_INTR  	  printk("ser_tx_int...");  #endif -	  info = IRQ_ports; -	  if (!info || !info->tty) +	  if (!info->tport.tty)  		return IRQ_NONE;  	  transmit_chars(info); -	  info->last_active = jiffies;  #ifdef SERIAL_DEBUG_INTR  	  printk("end.\n");  #endif @@ -509,29 +512,6 @@ static irqreturn_t ser_tx_int(int irq, void *dev_id)   */  /* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ - -static void do_softint(unsigned long private_) -{ -	struct async_struct	*info = (struct async_struct *) private_; -	struct tty_struct	*tty; - -	tty = info->tty; -	if (!tty) -		return; - -	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) -		tty_wakeup(tty); -} - -/*   * ---------------------------------------------------------------   * Low level utility subroutines for the serial driver:  routines to   * figure out the appropriate timeout for an interrupt chain, routines @@ -540,8 +520,9 @@ static void do_softint(unsigned long private_)   * ---------------------------------------------------------------   */ -static int startup(struct async_struct * info) +static int startup(struct tty_struct *tty, struct serial_state *info)  { +	struct tty_port *port = &info->tport;  	unsigned long flags;  	int	retval=0;  	unsigned long page; @@ -552,7 +533,7 @@ static int startup(struct async_struct * info)  	local_irq_save(flags); -	if (info->flags & ASYNC_INITIALIZED) { +	if (port->flags & ASYNC_INITIALIZED) {  		free_page(page);  		goto errout;  	} @@ -574,9 +555,7 @@ static int startup(struct async_struct * info)  	retval = request_irq(IRQ_AMIGA_VERTB, ser_vbl_int, 0, "serial status", info);  	if (retval) {  	  if (serial_isroot()) { -	    if (info->tty) -	      set_bit(TTY_IO_ERROR, -		      &info->tty->flags); +	      set_bit(TTY_IO_ERROR, &tty->flags);  	    retval = 0;  	  }  	  goto errout; @@ -590,37 +569,32 @@ static int startup(struct async_struct * info)  	/* remember current state of the DCD and CTS bits */  	current_ctl_bits = ciab.pra & (SER_DCD | SER_CTS | SER_DSR); -	IRQ_ports = info; -  	info->MCR = 0; -	if (info->tty->termios->c_cflag & CBAUD) +	if (C_BAUD(tty))  	  info->MCR = SER_DTR | SER_RTS;  	rtsdtr_ctrl(info->MCR); -	if (info->tty) -		clear_bit(TTY_IO_ERROR, &info->tty->flags); +	clear_bit(TTY_IO_ERROR, &tty->flags);  	info->xmit.head = info->xmit.tail = 0;  	/*  	 * Set up the tty->alt_speed kludge  	 */ -	if (info->tty) { -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) -			info->tty->alt_speed = 57600; -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) -			info->tty->alt_speed = 115200; -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) -			info->tty->alt_speed = 230400; -		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) -			info->tty->alt_speed = 460800; -	} +	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) +		tty->alt_speed = 57600; +	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) +		tty->alt_speed = 115200; +	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) +		tty->alt_speed = 230400; +	if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) +		tty->alt_speed = 460800;  	/*  	 * and set the speed of the serial port  	 */ -	change_speed(info, NULL); +	change_speed(tty, info, NULL); -	info->flags |= ASYNC_INITIALIZED; +	port->flags |= ASYNC_INITIALIZED;  	local_irq_restore(flags);  	return 0; @@ -633,15 +607,15 @@ errout:   * This routine will shutdown a serial port; interrupts are disabled, and   * DTR is dropped if the hangup on close termio flag is on.   */ -static void shutdown(struct async_struct * info) +static void shutdown(struct tty_struct *tty, struct serial_state *info)  {  	unsigned long	flags;  	struct serial_state *state; -	if (!(info->flags & ASYNC_INITIALIZED)) +	if (!(info->tport.flags & ASYNC_INITIALIZED))  		return; -	state = info->state; +	state = info;  #ifdef SERIAL_DEBUG_OPEN  	printk("Shutting down serial port %d ....\n", info->line); @@ -653,9 +627,7 @@ static void shutdown(struct async_struct * info)  	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq  	 * here so the queue might never be waken up  	 */ -	wake_up_interruptible(&info->delta_msr_wait); - -	IRQ_ports = NULL; +	wake_up_interruptible(&info->tport.delta_msr_wait);  	/*  	 * Free the IRQ, if necessary @@ -675,14 +647,13 @@ static void shutdown(struct async_struct * info)  	custom.adkcon = AC_UARTBRK;  	mb(); -	if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) +	if (tty->termios->c_cflag & HUPCL)  		info->MCR &= ~(SER_DTR|SER_RTS);  	rtsdtr_ctrl(info->MCR); -	if (info->tty) -		set_bit(TTY_IO_ERROR, &info->tty->flags); +	set_bit(TTY_IO_ERROR, &tty->flags); -	info->flags &= ~ASYNC_INITIALIZED; +	info->tport.flags &= ~ASYNC_INITIALIZED;  	local_irq_restore(flags);  } @@ -691,17 +662,16 @@ static void shutdown(struct async_struct * info)   * This routine is called to set the UART divisor registers to match   * the specified baud rate for a serial port.   */ -static void change_speed(struct async_struct *info, +static void change_speed(struct tty_struct *tty, struct serial_state *info,  			 struct ktermios *old_termios)  { +	struct tty_port *port = &info->tport;  	int	quot = 0, baud_base, baud;  	unsigned cflag, cval = 0;  	int	bits;  	unsigned long	flags; -	if (!info->tty || !info->tty->termios) -		return; -	cflag = info->tty->termios->c_cflag; +	cflag = tty->termios->c_cflag;  	/* Byte size is always 8 bits plus parity bit if requested */ @@ -722,13 +692,12 @@ static void change_speed(struct async_struct *info,  #endif  	/* Determine divisor based on baud rate */ -	baud = tty_get_baud_rate(info->tty); +	baud = tty_get_baud_rate(tty);  	if (!baud)  		baud = 9600;	/* B0 transition handled in rs_set_termios */ -	baud_base = info->state->baud_base; -	if (baud == 38400 && -	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) -		quot = info->state->custom_divisor; +	baud_base = info->baud_base; +	if (baud == 38400 && (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) +		quot = info->custom_divisor;  	else {  		if (baud == 134)  			/* Special case since 134 is really 134.5 */ @@ -739,14 +708,14 @@ static void change_speed(struct async_struct *info,  	/* If the quotient is zero refuse the change */  	if (!quot && old_termios) {  		/* FIXME: Will need updating for new tty in the end */ -		info->tty->termios->c_cflag &= ~CBAUD; -		info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); -		baud = tty_get_baud_rate(info->tty); +		tty->termios->c_cflag &= ~CBAUD; +		tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); +		baud = tty_get_baud_rate(tty);  		if (!baud)  			baud = 9600;  		if (baud == 38400 && -		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) -			quot = info->state->custom_divisor; +		    (port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) +			quot = info->custom_divisor;  		else {  			if (baud == 134)  				/* Special case since 134 is really 134.5 */ @@ -764,17 +733,17 @@ static void change_speed(struct async_struct *info,  	/* CTS flow control flag and modem status interrupts */  	info->IER &= ~UART_IER_MSI; -	if (info->flags & ASYNC_HARDPPS_CD) +	if (port->flags & ASYNC_HARDPPS_CD)  		info->IER |= UART_IER_MSI;  	if (cflag & CRTSCTS) { -		info->flags |= ASYNC_CTS_FLOW; +		port->flags |= ASYNC_CTS_FLOW;  		info->IER |= UART_IER_MSI;  	} else -		info->flags &= ~ASYNC_CTS_FLOW; +		port->flags &= ~ASYNC_CTS_FLOW;  	if (cflag & CLOCAL) -		info->flags &= ~ASYNC_CHECK_CD; +		port->flags &= ~ASYNC_CHECK_CD;  	else { -		info->flags |= ASYNC_CHECK_CD; +		port->flags |= ASYNC_CHECK_CD;  		info->IER |= UART_IER_MSI;  	}  	/* TBD: @@ -786,24 +755,24 @@ static void change_speed(struct async_struct *info,  	 */  	info->read_status_mask = UART_LSR_OE | UART_LSR_DR; -	if (I_INPCK(info->tty)) +	if (I_INPCK(tty))  		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; -	if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) +	if (I_BRKINT(tty) || I_PARMRK(tty))  		info->read_status_mask |= UART_LSR_BI;  	/*  	 * Characters to ignore  	 */  	info->ignore_status_mask = 0; -	if (I_IGNPAR(info->tty)) +	if (I_IGNPAR(tty))  		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; -	if (I_IGNBRK(info->tty)) { +	if (I_IGNBRK(tty)) {  		info->ignore_status_mask |= UART_LSR_BI;  		/*  		 * If we're ignore parity and break indicators, ignore   		 * overruns too.  (For real raw support).  		 */ -		if (I_IGNPAR(info->tty)) +		if (I_IGNPAR(tty))  			info->ignore_status_mask |= UART_LSR_OE;  	}  	/* @@ -828,13 +797,12 @@ static void change_speed(struct async_struct *info,  	mb();  	} -	info->LCR = cval;				/* Save LCR */  	local_irq_restore(flags);  }  static int rs_put_char(struct tty_struct *tty, unsigned char ch)  { -	struct async_struct *info; +	struct serial_state *info;  	unsigned long flags;  	info = tty->driver_data; @@ -861,7 +829,7 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch)  static void rs_flush_chars(struct tty_struct *tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) @@ -886,11 +854,9 @@ static void rs_flush_chars(struct tty_struct *tty)  static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count)  {  	int	c, ret = 0; -	struct async_struct *info; +	struct serial_state *info = tty->driver_data;  	unsigned long flags; -	info = tty->driver_data; -  	if (serial_paranoia_check(info, tty->name, "rs_write"))  		return 0; @@ -934,7 +900,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count  static int rs_write_room(struct tty_struct *tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	if (serial_paranoia_check(info, tty->name, "rs_write_room"))  		return 0; @@ -943,7 +909,7 @@ static int rs_write_room(struct tty_struct *tty)  static int rs_chars_in_buffer(struct tty_struct *tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))  		return 0; @@ -952,7 +918,7 @@ static int rs_chars_in_buffer(struct tty_struct *tty)  static void rs_flush_buffer(struct tty_struct *tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) @@ -969,7 +935,7 @@ static void rs_flush_buffer(struct tty_struct *tty)   */  static void rs_send_xchar(struct tty_struct *tty, char ch)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;          unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_send_char")) @@ -1004,7 +970,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)   */  static void rs_throttle(struct tty_struct * tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  #ifdef SERIAL_DEBUG_THROTTLE  	char	buf[64]; @@ -1029,7 +995,7 @@ static void rs_throttle(struct tty_struct * tty)  static void rs_unthrottle(struct tty_struct * tty)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  #ifdef SERIAL_DEBUG_THROTTLE  	char	buf[64]; @@ -1060,25 +1026,22 @@ static void rs_unthrottle(struct tty_struct * tty)   * ------------------------------------------------------------   */ -static int get_serial_info(struct async_struct * info, +static int get_serial_info(struct tty_struct *tty, struct serial_state *state,  			   struct serial_struct __user * retinfo)  {  	struct serial_struct tmp; -	struct serial_state *state = info->state;  	if (!retinfo)  		return -EFAULT;  	memset(&tmp, 0, sizeof(tmp));  	tty_lock(); -	tmp.type = state->type; -	tmp.line = state->line; +	tmp.line = tty->index;  	tmp.port = state->port; -	tmp.irq = state->irq; -	tmp.flags = state->flags; +	tmp.flags = state->tport.flags;  	tmp.xmit_fifo_size = state->xmit_fifo_size;  	tmp.baud_base = state->baud_base; -	tmp.close_delay = state->close_delay; -	tmp.closing_wait = state->closing_wait; +	tmp.close_delay = state->tport.close_delay; +	tmp.closing_wait = state->tport.closing_wait;  	tmp.custom_divisor = state->custom_divisor;  	tty_unlock();  	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) @@ -1086,38 +1049,34 @@ static int get_serial_info(struct async_struct * info,  	return 0;  } -static int set_serial_info(struct async_struct * info, +static int set_serial_info(struct tty_struct *tty, struct serial_state *state,  			   struct serial_struct __user * new_info)  { +	struct tty_port *port = &state->tport;  	struct serial_struct new_serial; - 	struct serial_state old_state, *state; -	unsigned int		change_irq,change_port; +	bool change_spd;  	int 			retval = 0;  	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))  		return -EFAULT;  	tty_lock(); -	state = info->state; -	old_state = *state; -   -	change_irq = new_serial.irq != state->irq; -	change_port = (new_serial.port != state->port); -	if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) { -	  tty_unlock(); -	  return -EINVAL; +	change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) || +		new_serial.custom_divisor != state->custom_divisor; +	if (new_serial.irq || new_serial.port != state->port || +			new_serial.xmit_fifo_size != state->xmit_fifo_size) { +		tty_unlock(); +		return -EINVAL;  	}  	if (!serial_isroot()) {  		if ((new_serial.baud_base != state->baud_base) || -		    (new_serial.close_delay != state->close_delay) || +		    (new_serial.close_delay != port->close_delay) ||  		    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||  		    ((new_serial.flags & ~ASYNC_USR_MASK) != -		     (state->flags & ~ASYNC_USR_MASK))) +		     (port->flags & ~ASYNC_USR_MASK)))  			return -EPERM; -		state->flags = ((state->flags & ~ASYNC_USR_MASK) | -			       (new_serial.flags & ASYNC_USR_MASK)); -		info->flags = ((info->flags & ~ASYNC_USR_MASK) | +		port->flags = ((port->flags & ~ASYNC_USR_MASK) |  			       (new_serial.flags & ASYNC_USR_MASK));  		state->custom_divisor = new_serial.custom_divisor;  		goto check_and_exit; @@ -1134,32 +1093,28 @@ static int set_serial_info(struct async_struct * info,  	 */  	state->baud_base = new_serial.baud_base; -	state->flags = ((state->flags & ~ASYNC_FLAGS) | +	port->flags = ((port->flags & ~ASYNC_FLAGS) |  			(new_serial.flags & ASYNC_FLAGS)); -	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | -		       (info->flags & ASYNC_INTERNAL_FLAGS));  	state->custom_divisor = new_serial.custom_divisor; -	state->close_delay = new_serial.close_delay * HZ/100; -	state->closing_wait = new_serial.closing_wait * HZ/100; -	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +	port->close_delay = new_serial.close_delay * HZ/100; +	port->closing_wait = new_serial.closing_wait * HZ/100; +	tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0;  check_and_exit: -	if (info->flags & ASYNC_INITIALIZED) { -		if (((old_state.flags & ASYNC_SPD_MASK) != -		     (state->flags & ASYNC_SPD_MASK)) || -		    (old_state.custom_divisor != state->custom_divisor)) { -			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) -				info->tty->alt_speed = 57600; -			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) -				info->tty->alt_speed = 115200; -			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) -				info->tty->alt_speed = 230400; -			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) -				info->tty->alt_speed = 460800; -			change_speed(info, NULL); +	if (port->flags & ASYNC_INITIALIZED) { +		if (change_spd) { +			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) +				tty->alt_speed = 57600; +			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) +				tty->alt_speed = 115200; +			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) +				tty->alt_speed = 230400; +			if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) +				tty->alt_speed = 460800; +			change_speed(tty, state, NULL);  		}  	} else -		retval = startup(info); +		retval = startup(tty, state);  	tty_unlock();  	return retval;  } @@ -1175,7 +1130,7 @@ check_and_exit:   * 	    transmit holding register is empty.  This functionality   * 	    allows an RS485 driver to be written in user space.    */ -static int get_lsr_info(struct async_struct * info, unsigned int __user *value) +static int get_lsr_info(struct serial_state *info, unsigned int __user *value)  {  	unsigned char status;  	unsigned int result; @@ -1194,7 +1149,7 @@ static int get_lsr_info(struct async_struct * info, unsigned int __user *value)  static int rs_tiocmget(struct tty_struct *tty)  { -	struct async_struct * info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned char control, status;  	unsigned long flags; @@ -1217,7 +1172,7 @@ static int rs_tiocmget(struct tty_struct *tty)  static int rs_tiocmset(struct tty_struct *tty, unsigned int set,  						unsigned int clear)  { -	struct async_struct * info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_ioctl")) @@ -1244,7 +1199,7 @@ static int rs_tiocmset(struct tty_struct *tty, unsigned int set,   */  static int rs_break(struct tty_struct *tty, int break_state)  { -	struct async_struct * info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	if (serial_paranoia_check(info, tty->name, "rs_break")) @@ -1269,12 +1224,12 @@ static int rs_break(struct tty_struct *tty, int break_state)  static int rs_get_icount(struct tty_struct *tty,  				struct serial_icounter_struct *icount)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	struct async_icount cnow;  	unsigned long flags;  	local_irq_save(flags); -	cnow = info->state->icount; +	cnow = info->icount;  	local_irq_restore(flags);  	icount->cts = cnow.cts;  	icount->dsr = cnow.dsr; @@ -1294,7 +1249,7 @@ static int rs_get_icount(struct tty_struct *tty,  static int rs_ioctl(struct tty_struct *tty,  		    unsigned int cmd, unsigned long arg)  { -	struct async_struct * info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	struct async_icount cprev, cnow;	/* kernel counter temps */  	void __user *argp = (void __user *)arg;  	unsigned long flags; @@ -1311,9 +1266,9 @@ static int rs_ioctl(struct tty_struct *tty,  	switch (cmd) {  		case TIOCGSERIAL: -			return get_serial_info(info, argp); +			return get_serial_info(tty, info, argp);  		case TIOCSSERIAL: -			return set_serial_info(info, argp); +			return set_serial_info(tty, info, argp);  		case TIOCSERCONFIG:  			return 0; @@ -1322,7 +1277,7 @@ static int rs_ioctl(struct tty_struct *tty,  		case TIOCSERGSTRUCT:  			if (copy_to_user(argp, -					 info, sizeof(struct async_struct))) +					 info, sizeof(struct serial_state)))  				return -EFAULT;  			return 0; @@ -1335,15 +1290,15 @@ static int rs_ioctl(struct tty_struct *tty,  		case TIOCMIWAIT:  			local_irq_save(flags);  			/* note the counters on entry */ -			cprev = info->state->icount; +			cprev = info->icount;  			local_irq_restore(flags);  			while (1) { -				interruptible_sleep_on(&info->delta_msr_wait); +				interruptible_sleep_on(&info->tport.delta_msr_wait);  				/* see if a signal did it */  				if (signal_pending(current))  					return -ERESTARTSYS;  				local_irq_save(flags); -				cnow = info->state->icount; /* atomic copy */ +				cnow = info->icount; /* atomic copy */  				local_irq_restore(flags);  				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&   				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) @@ -1372,11 +1327,11 @@ static int rs_ioctl(struct tty_struct *tty,  static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)  { -	struct async_struct *info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long flags;  	unsigned int cflag = tty->termios->c_cflag; -	change_speed(info, old_termios); +	change_speed(tty, info, old_termios);  	/* Handle transition to B0 status */  	if ((old_termios->c_cflag & CBAUD) && @@ -1432,64 +1387,23 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)   */  static void rs_close(struct tty_struct *tty, struct file * filp)  { -	struct async_struct * info = tty->driver_data; -	struct serial_state *state; -	unsigned long flags; +	struct serial_state *state = tty->driver_data; +	struct tty_port *port = &state->tport; -	if (!info || serial_paranoia_check(info, tty->name, "rs_close")) +	if (serial_paranoia_check(state, tty->name, "rs_close"))  		return; -	state = info->state; - -	local_irq_save(flags); - -	if (tty_hung_up_p(filp)) { -		DBG_CNT("before DEC-hung"); -		local_irq_restore(flags); +	if (tty_port_close_start(port, tty, filp) == 0)  		return; -	} -#ifdef SERIAL_DEBUG_OPEN -	printk("rs_close ttys%d, count = %d\n", info->line, state->count); -#endif -	if ((tty->count == 1) && (state->count != 1)) { -		/* -		 * Uh, oh.  tty->count is 1, which means that the tty -		 * structure will be freed.  state->count should always -		 * be one in these conditions.  If it's greater than -		 * one, we've got real problems, since it means the -		 * serial port won't be shutdown. -		 */ -		printk("rs_close: bad serial port count; tty->count is 1, " -		       "state->count is %d\n", state->count); -		state->count = 1; -	} -	if (--state->count < 0) { -		printk("rs_close: bad serial port count for ttys%d: %d\n", -		       info->line, state->count); -		state->count = 0; -	} -	if (state->count) { -		DBG_CNT("before DEC-2"); -		local_irq_restore(flags); -		return; -	} -	info->flags |= ASYNC_CLOSING; -	/* -	 * Now we wait for the transmit buffer to clear; and we notify  -	 * the line discipline to only process XON/XOFF characters. -	 */ -	tty->closing = 1; -	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) -		tty_wait_until_sent(tty, info->closing_wait);  	/*  	 * At this point we stop accepting input.  To do this, we  	 * disable the receive line status interrupts, and tell the  	 * interrupt driver to stop checking the data ready bit in the  	 * line status register.  	 */ -	info->read_status_mask &= ~UART_LSR_DR; -	if (info->flags & ASYNC_INITIALIZED) { +	state->read_status_mask &= ~UART_LSR_DR; +	if (port->flags & ASYNC_INITIALIZED) {  	        /* disable receive interrupts */  	        custom.intena = IF_RBF;  		mb(); @@ -1502,24 +1416,15 @@ static void rs_close(struct tty_struct *tty, struct file * filp)  		 * has completely drained; this is especially  		 * important if there is a transmit FIFO!  		 */ -		rs_wait_until_sent(tty, info->timeout); +		rs_wait_until_sent(tty, state->timeout);  	} -	shutdown(info); +	shutdown(tty, state);  	rs_flush_buffer(tty);  	tty_ldisc_flush(tty); -	tty->closing = 0; -	info->event = 0; -	info->tty = NULL; -	if (info->blocked_open) { -		if (info->close_delay) { -			msleep_interruptible(jiffies_to_msecs(info->close_delay)); -		} -		wake_up_interruptible(&info->open_wait); -	} -	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); -	wake_up_interruptible(&info->close_wait); -	local_irq_restore(flags); +	port->tty = NULL; + +	tty_port_close_end(port, tty);  }  /* @@ -1527,7 +1432,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)   */  static void rs_wait_until_sent(struct tty_struct *tty, int timeout)  { -	struct async_struct * info = tty->driver_data; +	struct serial_state *info = tty->driver_data;  	unsigned long orig_jiffies, char_time;  	int lsr; @@ -1590,173 +1495,17 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)   */  static void rs_hangup(struct tty_struct *tty)  { -	struct async_struct * info = tty->driver_data; -	struct serial_state *state = info->state; +	struct serial_state *info = tty->driver_data;  	if (serial_paranoia_check(info, tty->name, "rs_hangup"))  		return; -	state = info->state; -  	rs_flush_buffer(tty); -	shutdown(info); -	info->event = 0; -	state->count = 0; -	info->flags &= ~ASYNC_NORMAL_ACTIVE; -	info->tty = NULL; -	wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, -			   struct async_struct *info) -{ -#ifdef DECLARE_WAITQUEUE -	DECLARE_WAITQUEUE(wait, current); -#else -	struct wait_queue wait = { current, NULL }; -#endif -	struct serial_state *state = info->state; -	int		retval; -	int		do_clocal = 0, extra_count = 0; -	unsigned long	flags; - -	/* -	 * If the device is in the middle of being closed, then block -	 * until it's done, and then try again. -	 */ -	if (tty_hung_up_p(filp) || -	    (info->flags & ASYNC_CLOSING)) { -		if (info->flags & ASYNC_CLOSING) -			interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART -		return ((info->flags & ASYNC_HUP_NOTIFY) ? -			-EAGAIN : -ERESTARTSYS); -#else -		return -EAGAIN; -#endif -	} - -	/* -	 * If non-blocking mode is set, or the port is not enabled, -	 * then make the check up front and then exit. -	 */ -	if ((filp->f_flags & O_NONBLOCK) || -	    (tty->flags & (1 << TTY_IO_ERROR))) { -		info->flags |= ASYNC_NORMAL_ACTIVE; -		return 0; -	} - -	if (tty->termios->c_cflag & CLOCAL) -		do_clocal = 1; - -	/* -	 * Block waiting for the carrier detect and the line to become -	 * free (i.e., not in use by the callout).  While we are in -	 * this loop, state->count is dropped by one, so that -	 * rs_close() knows when to free things.  We restore it upon -	 * exit, either normal or abnormal. -	 */ -	retval = 0; -	add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN -	printk("block_til_ready before block: ttys%d, count = %d\n", -	       state->line, state->count); -#endif -	local_irq_save(flags); -	if (!tty_hung_up_p(filp)) { -		extra_count = 1; -		state->count--; -	} -	local_irq_restore(flags); -	info->blocked_open++; -	while (1) { -		local_irq_save(flags); -		if (tty->termios->c_cflag & CBAUD) -		        rtsdtr_ctrl(SER_DTR|SER_RTS); -		local_irq_restore(flags); -		set_current_state(TASK_INTERRUPTIBLE); -		if (tty_hung_up_p(filp) || -		    !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART -			if (info->flags & ASYNC_HUP_NOTIFY) -				retval = -EAGAIN; -			else -				retval = -ERESTARTSYS; -#else -			retval = -EAGAIN; -#endif -			break; -		} -		if (!(info->flags & ASYNC_CLOSING) && -		    (do_clocal || (!(ciab.pra & SER_DCD)) )) -			break; -		if (signal_pending(current)) { -			retval = -ERESTARTSYS; -			break; -		} -#ifdef SERIAL_DEBUG_OPEN -		printk("block_til_ready blocking: ttys%d, count = %d\n", -		       info->line, state->count); -#endif -		tty_unlock(); -		schedule(); -		tty_lock(); -	} -	__set_current_state(TASK_RUNNING); -	remove_wait_queue(&info->open_wait, &wait); -	if (extra_count) -		state->count++; -	info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN -	printk("block_til_ready after blocking: ttys%d, count = %d\n", -	       info->line, state->count); -#endif -	if (retval) -		return retval; -	info->flags |= ASYNC_NORMAL_ACTIVE; -	return 0; -} - -static int get_async_struct(int line, struct async_struct **ret_info) -{ -	struct async_struct *info; -	struct serial_state *sstate; - -	sstate = rs_table + line; -	sstate->count++; -	if (sstate->info) { -		*ret_info = sstate->info; -		return 0; -	} -	info = kzalloc(sizeof(struct async_struct), GFP_KERNEL); -	if (!info) { -		sstate->count--; -		return -ENOMEM; -	} -#ifdef DECLARE_WAITQUEUE -	init_waitqueue_head(&info->open_wait); -	init_waitqueue_head(&info->close_wait); -	init_waitqueue_head(&info->delta_msr_wait); -#endif -	info->magic = SERIAL_MAGIC; -	info->port = sstate->port; -	info->flags = sstate->flags; -	info->xmit_fifo_size = sstate->xmit_fifo_size; -	info->line = line; -	tasklet_init(&info->tlet, do_softint, (unsigned long)info); -	info->state = sstate; -	if (sstate->info) { -		kfree(info); -		*ret_info = sstate->info; -		return 0; -	} -	*ret_info = sstate->info = info; -	return 0; +	shutdown(tty, info); +	info->tport.count = 0; +	info->tport.flags &= ~ASYNC_NORMAL_ACTIVE; +	info->tport.tty = NULL; +	wake_up_interruptible(&info->tport.open_wait);  }  /* @@ -1767,91 +1516,42 @@ static int get_async_struct(int line, struct async_struct **ret_info)   */  static int rs_open(struct tty_struct *tty, struct file * filp)  { -	struct async_struct	*info; -	int 			retval, line; +	struct serial_state *info = rs_table + tty->index; +	struct tty_port *port = &info->tport; +	int retval; -	line = tty->index; -	if ((line < 0) || (line >= NR_PORTS)) { -		return -ENODEV; -	} -	retval = get_async_struct(line, &info); -	if (retval) { -		return retval; -	} +	port->count++; +	port->tty = tty;  	tty->driver_data = info; -	info->tty = tty; +	tty->port = port;  	if (serial_paranoia_check(info, tty->name, "rs_open"))  		return -ENODEV; -#ifdef SERIAL_DEBUG_OPEN -	printk("rs_open %s, count = %d\n", tty->name, info->state->count); -#endif -	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; +	tty->low_latency = (port->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -	/* -	 * If the port is the middle of closing, bail out now -	 */ -	if (tty_hung_up_p(filp) || -	    (info->flags & ASYNC_CLOSING)) { -		if (info->flags & ASYNC_CLOSING) -			interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART -		return ((info->flags & ASYNC_HUP_NOTIFY) ? -			-EAGAIN : -ERESTARTSYS); -#else -		return -EAGAIN; -#endif -	} - -	/* -	 * Start up serial port -	 */ -	retval = startup(info); -	if (retval) { -		return retval; -	} - -	retval = block_til_ready(tty, filp, info); +	retval = startup(tty, info);  	if (retval) { -#ifdef SERIAL_DEBUG_OPEN -		printk("rs_open returning after block_til_ready with %d\n", -		       retval); -#endif  		return retval;  	} -#ifdef SERIAL_DEBUG_OPEN -	printk("rs_open %s successful...", tty->name); -#endif -	return 0; +	return tty_port_block_til_ready(port, tty, filp);  }  /*   * /proc fs routines....   */ -static inline void line_info(struct seq_file *m, struct serial_state *state) +static inline void line_info(struct seq_file *m, int line, +		struct serial_state *state)  { -	struct async_struct *info = state->info, scr_info;  	char	stat_buf[30], control, status;  	unsigned long flags; -	seq_printf(m, "%d: uart:amiga_builtin",state->line); +	seq_printf(m, "%d: uart:amiga_builtin", line); -	/* -	 * Figure out the current RS-232 lines -	 */ -	if (!info) { -		info = &scr_info;	/* This is just for serial_{in,out} */ - -		info->magic = SERIAL_MAGIC; -		info->flags = state->flags; -		info->quot = 0; -		info->tty = NULL; -	}  	local_irq_save(flags);  	status = ciab.pra; -	control = info ? info->MCR : status; +	control = (state->tport.flags & ASYNC_INITIALIZED) ? state->MCR : status;  	local_irq_restore(flags);  	stat_buf[0] = 0; @@ -1867,9 +1567,8 @@ static inline void line_info(struct seq_file *m, struct serial_state *state)  	if(!(status & SER_DCD))  		strcat(stat_buf, "|CD"); -	if (info->quot) { -		seq_printf(m, " baud:%d", state->baud_base / info->quot); -	} +	if (state->quot) +		seq_printf(m, " baud:%d", state->baud_base / state->quot);  	seq_printf(m, " tx:%d rx:%d", state->icount.tx, state->icount.rx); @@ -1894,7 +1593,7 @@ static inline void line_info(struct seq_file *m, struct serial_state *state)  static int rs_proc_show(struct seq_file *m, void *v)  {  	seq_printf(m, "serinfo:1.0 driver:%s\n", serial_version); -	line_info(m, &rs_table[0]); +	line_info(m, 0, &rs_table[0]);  	return 0;  } @@ -1955,6 +1654,32 @@ static const struct tty_operations serial_ops = {  	.proc_fops = &rs_proc_fops,  }; +static int amiga_carrier_raised(struct tty_port *port) +{ +	return !(ciab.pra & SER_DCD); +} + +static void amiga_dtr_rts(struct tty_port *port, int raise) +{ +	struct serial_state *info = container_of(port, struct serial_state, +			tport); +	unsigned long flags; + +	if (raise) +		info->MCR |= SER_DTR|SER_RTS; +	else +		info->MCR &= ~(SER_DTR|SER_RTS); + +	local_irq_save(flags); +	rtsdtr_ctrl(info->MCR); +	local_irq_restore(flags); +} + +static const struct tty_port_operations amiga_port_ops = { +	.carrier_raised = amiga_carrier_raised, +	.dtr_rts = amiga_dtr_rts, +}; +  /*   * The serial driver boot-time initialization code!   */ @@ -1964,17 +1689,14 @@ static int __init amiga_serial_probe(struct platform_device *pdev)  	struct serial_state * state;  	int error; -	serial_driver = alloc_tty_driver(1); +	serial_driver = alloc_tty_driver(NR_PORTS);  	if (!serial_driver)  		return -ENOMEM; -	IRQ_ports = NULL; -  	show_serial_version();  	/* Initialize the tty_driver structure */ -	serial_driver->owner = THIS_MODULE;  	serial_driver->driver_name = "amiserial";  	serial_driver->name = "ttyS";  	serial_driver->major = TTY_MAJOR; @@ -1992,20 +1714,17 @@ static int __init amiga_serial_probe(struct platform_device *pdev)  		goto fail_put_tty_driver;  	state = rs_table; -	state->magic = SSTATE_MAGIC;  	state->port = (int)&custom.serdatr; /* Just to give it a value */ -	state->line = 0;  	state->custom_divisor = 0; -	state->close_delay = 5*HZ/10; -	state->closing_wait = 30*HZ;  	state->icount.cts = state->icount.dsr =   	  state->icount.rng = state->icount.dcd = 0;  	state->icount.rx = state->icount.tx = 0;  	state->icount.frame = state->icount.parity = 0;  	state->icount.overrun = state->icount.brk = 0; +	tty_port_init(&state->tport); +	state->tport.ops = &amiga_port_ops; -	printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", -		       state->line); +	printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");  	/* Hardware set up */ @@ -2058,20 +1777,15 @@ static int __exit amiga_serial_remove(struct platform_device *pdev)  {  	int error;  	struct serial_state *state = platform_get_drvdata(pdev); -	struct async_struct *info = state->info;  	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */ -	tasklet_kill(&info->tlet);  	if ((error = tty_unregister_driver(serial_driver)))  		printk("SERIAL: failed to unregister serial driver (%d)\n",  		       error);  	put_tty_driver(serial_driver); -	rs_table[0].info = NULL; -	kfree(info); - -	free_irq(IRQ_AMIGA_TBE, rs_table); -	free_irq(IRQ_AMIGA_RBF, rs_table); +	free_irq(IRQ_AMIGA_TBE, state); +	free_irq(IRQ_AMIGA_RBF, state);  	platform_set_drvdata(pdev, NULL);  |