/* -*- linux-c -*- */ /* $Id: 8253xsyn.c,v 1.17 2002/02/10 22:17:25 martillo Exp $ * 8253xsyn.c: SYNC TTY Driver for the SIEMENS SAB8253X DUSCC. * * Implementation, modifications and extensions * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ /* Standard in kernel modules */ #define DEFINE_VARIABLE #include /* Specifically, a module */ #include #include #include #include #include #include #include #include #include "8253xctl.h" #include "8253x.h" #include #include #ifdef MODULE #undef XCONFIG_SERIAL_CONSOLE #endif static void sab8253x_flush_to_ldiscS(void *private_) /* need a separate version for sync there are no flags associated with received sync TTY data*/ { struct tty_struct *tty = (struct tty_struct *) private_; unsigned char *cp; int count; struct sab_port *port; struct sk_buff *skb; if(tty) { port = (struct sab_port *)tty->driver_data; } else { return; } if(port == NULL) { return; } if (test_bit(TTY_DONT_FLIP, &tty->flags)) { queue_task(&tty->flip.tqueue, &tq_timer); return; } /* note that a hangup may have occurred -- perhaps should check for that */ port->DoingInterrupt = 1; while(port->sab8253xc_rcvbuflist && (skb_queue_len(port->sab8253xc_rcvbuflist) > 0)) { skb = skb_dequeue(port->sab8253xc_rcvbuflist); count = skb->data_len; cp = skb->data; (*tty->ldisc.receive_buf)(tty, cp, 0, count); dev_kfree_skb_any(skb); } port->DoingInterrupt = 0; } void sab8253x_flush_charsS(struct tty_struct *tty) { struct sab_port *port = (struct sab_port *)tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_flush_chars")) { return; } if ((Sab8253xCountTransmit(port) <= 0) || tty->stopped || tty->hw_stopped) { /* can't flush */ return; } sab8253x_start_txS(port); } /* * ------------------------------------------------------------ * sab8253x_stopS() and sab8253x_startS() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. * ------------------------------------------------------------ */ void sab8253x_stopS(struct tty_struct *tty) { struct sab_port *port = (struct sab_port *)tty->driver_data; /* can't do anything here */ if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_stop")) { return; } /* interrupt handles it all*/ /* turning off XPR is not an option in sync mode */ } void sab8253x_startS(struct tty_struct *tty) { struct sab_port *port = (struct sab_port *)tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_start")) { return; } sab8253x_start_txS(port); } static void sab8253x_receive_charsS(struct sab_port *port, union sab8253x_irq_status *stat) { struct tty_struct *tty = port->tty; unsigned char buf[32]; int free_fifo = 0; int reset_fifo = 0; int msg_done = 0; int msg_bad = 0; int count = 0; int total_size = 0; int rstatus = 0; struct sk_buff *skb; /* Read number of BYTES (Character + Status) available. */ if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) ) { ++msg_bad; ++free_fifo; ++reset_fifo; } else { if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) { count = port->recv_fifo_size; ++free_fifo; } if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) { count = READB(port, rbcl); count &= (port->recv_fifo_size - 1); ++msg_done; ++free_fifo; total_size = READB(port, rbch); if(total_size & SAB82532_RBCH_OV) /* need to revisit for 4096 byte frames */ { msg_bad++; } rstatus = READB(port, rsta); if((rstatus & SAB82532_RSTA_VFR) == 0) { msg_bad++; } if(rstatus & SAB82532_RSTA_RDO) { msg_bad++; } if((rstatus & SAB82532_RSTA_CRC) == 0) { msg_bad++; } if(rstatus & SAB82532_RSTA_RAB) { msg_bad++; } } } /* Read the FIFO. */ (*port->readfifo)(port, buf, count); /* Issue Receive Message Complete command. */ if (free_fifo) { sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_RMC); } if(reset_fifo) { sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_RHR); } if(msg_bad) { port->msgbufindex = 0; return; } memcpy(&port->msgbuf[port->msgbufindex], buf, count); port->msgbufindex += count; #ifdef CONSOLE_SUPPORT if (port->is_console) { wake_up(&keypress_wait); } #endif if(msg_done) { if(port->msgbufindex <= 3) /* min is 1 char + 2 CRC + status byte */ { port->msgbufindex = 0; return; } total_size = port->msgbufindex - 3; /* strip off the crc16 and the status byte */ port->msgbufindex = 0; /* ignore the receive buffer waiting -- we know the correct size here */ if (!tty) { return; } if(skb = dev_alloc_skb(total_size), skb) { memcpy(skb->data, &port->msgbuf[0], total_size); skb->tail = (skb->data + total_size); skb->data_len = total_size; skb->len = total_size; skb_queue_tail(port->sab8253xc_rcvbuflist, skb); } queue_task(&tty->flip.tqueue, &tq_timer); /* clear out flip buffer as fast as possible * maybe should not be done unconditionally hear * but should be within the above consequence * clause */ } } static void sab8253x_check_statusS(struct sab_port *port, union sab8253x_irq_status *stat) { struct tty_struct *tty = port->tty; int modem_change = 0; mctlsig_t *sig; if (!tty) { return; } /* check_modem:*/ /* Checking DCD */ sig = &port->dcd; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dcd); port->icount.dcd++; modem_change++; } /* Checking CTS */ sig = &port->cts; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,cts); port->icount.cts++; modem_change++; } /* Checking DSR */ sig = &port->dsr; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dsr); port->icount.dsr++; modem_change++; } if (modem_change) { wake_up_interruptible(&port->delta_msr_wait); } sig = &port->dcd; if ((port->flags & FLAG8253X_CHECK_CD) && (stat->images[sig->irq] & sig->irqmask)) { if (sig->val) { wake_up_interruptible(&port->open_wait); } else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && (port->flags & FLAG8253X_CALLOUT_NOHUP))) { #if 0 /* requires more investigation */ MOD_INC_USE_COUNT; if (schedule_task(&port->tqueue_hangup) == 0) { MOD_DEC_USE_COUNT; } #endif } } sig = &port->cts; if (port->flags & FLAG8253X_CTS_FLOW) { /* not setting this yet */ if (port->tty->hw_stopped) { if (sig->val) { port->tty->hw_stopped = 0; sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); sab8253x_start_txS(port); } } else { if(!(getccr2configS(port) & SAB82532_CCR2_TOE)) { if (!(sig->val)) { port->tty->hw_stopped = 1; } } } } } /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ static void sab8253x_change_speedS(struct sab_port *port) { unsigned long flags,baud; tcflag_t cflag; u8 ccr2=0,ccr4=0,ebrg=0; int i, bits; #ifdef DEBUGGING printk("Change speed! "); #endif if (!port->tty || !port->tty->termios) { #ifdef DEBUGGING printk("NOT!\n"); #endif return; } #ifdef DEBUGGING printk(" for real.\n"); #endif cflag = port->tty->termios->c_cflag; /* Byte size and parity */ switch (cflag & CSIZE) { case CS5: bits = 7; break; case CS6: bits = 8; break; case CS7: bits = 9; break; default: case CS8: bits = 10; break; } if (cflag & CSTOPB) { bits++; } if (cflag & PARENB) { bits++; } /* Determine EBRG values based on the "encoded"baud rate */ i = cflag & CBAUD; switch(i) { case B0: baud=0; break; case B50: baud=100; break; case B75: baud=150; break; case B110: baud=220; break; case B134: baud=269; break; case B150: baud=300; break; case B200: baud=400; break; case B300: baud=600; break; case B600: baud=1200; break; case B1200: baud=2400; break; case B1800: baud=3600; break; case B2400: baud=4800; break; case B4800: baud=9600; break; case B9600: baud=19200; break; case B19200: baud=38400; break; case B38400: if(port->custspeed) { baud=port->custspeed<<1; } else { baud=76800; } break; case B57600: baud=115200; break; #ifdef SKIPTHIS case B76800: baud=153600; break; case B153600: baud=307200; break; #endif case B230400: baud=460800; break; case B460800: baud=921600; break; case B115200: default: baud=230400; break; } if(!sab8253x_baud(port,baud,&ebrg,&ccr2,&ccr4,&(port->baud))) { printk("Aurora Warning. baudrate %ld could not be set! Using 115200",baud); baud=230400; sab8253x_baud(port,baud,&ebrg,&ccr2,&ccr4,&(port->baud)); } if (port->baud) port->timeout = (port->xmit_fifo_size * HZ * bits) / port->baud; else port->timeout = 0; port->timeout += HZ / 50; /* Add .02 seconds of slop */ /* CTS flow control flags */ if (cflag & CRTSCTS) port->flags |= FLAG8253X_CTS_FLOW; else port->flags &= ~(FLAG8253X_CTS_FLOW); if (cflag & CLOCAL) port->flags &= ~(FLAG8253X_CHECK_CD); else port->flags |= FLAG8253X_CHECK_CD; if (port->tty) port->tty->hw_stopped = 0; /* * Set up parity check flag * XXX: not implemented, yet. */ #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) /* * Characters to ignore * XXX: not implemented, yet. */ /* * !!! ignore all characters if CREAD is not set * XXX: not implemented, yet. */ if ((cflag & CREAD) == 0) port->ignore_status_mask |= SAB82532_ISR0_RPF; save_flags(flags); cli(); sab8253x_cec_wait(port); WRITEB(port, bgr, ebrg); WRITEB(port, ccr2, READB(port, ccr2) & ~(0xc0)); /* clear out current baud rage */ WRITEB(port, ccr2, READB(port, ccr2) | ccr2); WRITEB(port, ccr4, (READB(port,ccr4) & ~SAB82532_CCR4_EBRG) | ccr4); if (port->flags & FLAG8253X_CTS_FLOW) { WRITEB(port, mode, READB(port,mode) & ~(SAB82532_MODE_RTS)); port->interrupt_mask1 &= ~(SAB82532_IMR1_CSC); WRITEB(port, imr1, port->interrupt_mask1); } else { WRITEB(port, mode, READB(port,mode) | SAB82532_MODE_RTS); port->interrupt_mask1 |= SAB82532_IMR1_CSC; WRITEB(port, imr1, port->interrupt_mask1); } WRITEB(port, mode, READB(port, mode) | SAB82532_MODE_RAC); restore_flags(flags); } void sab8253x_set_termiosS(struct tty_struct *tty, struct termios *old_termios) { struct sab_port *port = (struct sab_port *)tty->driver_data; if((tty->termios->c_cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { return; } if(!port) { return; } sab8253x_change_speedS(port); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { LOWER(port,rts); LOWER(port,dtr); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { RAISE(port,dtr); if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) { RAISE(port,rts); } } /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; sab8253x_startS(tty); } } static int sab8253x_startupS(struct sab_port *port) { unsigned long flags; int retval = 0; save_flags(flags); cli(); port->msgbufindex = 0; port->xmit_buf = NULL; port->buffergreedy = 0; if (port->flags & FLAG8253X_INITIALIZED) { goto errout; } if (!port->regs) { if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); } retval = -ENODEV; goto errout; } /* * Initialize the Hardware */ sab8253x_init_lineS(port); #if 0 /* maybe should be conditional */ if (port->tty->termios->c_cflag & CBAUD) { #endif /* Activate RTS */ RAISE(port,rts); /* Activate DTR */ RAISE(port,dtr); #if 0 } #endif /* * Initialize the modem signals values */ port->dcd.val=ISON(port,dcd); port->cts.val=ISON(port,cts); port->dsr.val=ISON(port,dsr); /* * Finally, enable interrupts */ port->interrupt_mask0 = SAB82532_IMR0_RFS | SAB82532_IMR0_PCE | SAB82532_IMR0_PLLA | SAB82532_IMR0_RSC | SAB82532_IMR0_CDSC; /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? SAB82532_IMR0_CDSC : 0); */ WRITEB(port,imr0,port->interrupt_mask0); port->interrupt_mask1 = SAB82532_IMR1_EOP | SAB82532_IMR1_XMR | SAB82532_IMR1_TIN | SAB82532_IMR1_XPR; WRITEB(port, imr1, port->interrupt_mask1); port->all_sent = 1; if (port->tty) { clear_bit(TTY_IO_ERROR, &port->tty->flags); } port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; /* * and set the speed of the serial port */ sab8253x_change_speedS(port); port->flags |= FLAG8253X_INITIALIZED; port->receive_chars = sab8253x_receive_charsS; port->transmit_chars = sab8253x_transmit_charsS; port->check_status = sab8253x_check_statusS; port->receive_test = (SAB82532_ISR0_RME | SAB82532_ISR0_RFO | SAB82532_ISR0_RPF); port->transmit_test = (SAB82532_ISR1_ALLS | SAB82532_ISR1_RDO | SAB82532_ISR1_XPR | SAB82532_ISR1_XDU | SAB82532_ISR1_CSC); port->check_status_test = (SAB82532_ISR1_CSC); /*((port->ccontrol.ccr2 & SAB82532_CCR2_TOE) ? 0 : SAB82532_ISR0_CDSC));*/ restore_flags(flags); return 0; errout: restore_flags(flags); return retval; } static void sab8253x_shutdownS(struct sab_port *port) { unsigned long flags; if (!(port->flags & FLAG8253X_INITIALIZED)) { return; } save_flags(flags); cli(); /* Disable interrupts */ /* * 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(&port->delta_msr_wait); if (port->xmit_buf) { port->xmit_buf = 0; } #ifdef XCONFIG_SERIAL_CONSOLE if (port->is_console) { port->interrupt_mask0 = SAB82532_IMR0_PERR | SAB82532_IMR0_FERR | /*SAB82532_IMR0_TIME |*/ SAB82532_IMR0_PLLA | SAB82532_IMR0_CDSC; WRITEB(port,imr0,port->interrupt_mask0); port->interrupt_mask1 = SAB82532_IMR1_BRKT | SAB82532_IMR1_ALLS | SAB82532_IMR1_XOFF | SAB82532_IMR1_TIN | SAB82532_IMR1_CSC | SAB82532_IMR1_XON | SAB82532_IMR1_XPR; WRITEB(port,imr1,port->interrupt_mask1); if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); } port->flags &= ~FLAG8253X_INITIALIZED; restore_flags(flags); return; } #endif /* Disable Interrupts */ port->interrupt_mask0 = 0xff; WRITEB(port, imr0, port->interrupt_mask0); port->interrupt_mask1 = 0xff; WRITEB(port, imr1, port->interrupt_mask1); if (!port->tty || (port->tty->termios->c_cflag & HUPCL)) { LOWER(port,rts); LOWER(port,dtr); } /* Disable Receiver */ CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); /* Power Down */ CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU); if (port->tty) { set_bit(TTY_IO_ERROR, &port->tty->flags); } port->flags &= ~FLAG8253X_INITIALIZED; restore_flags(flags); } int sab8253x_writeS(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) { struct sab_port *port = (struct sab_port *)tty->driver_data; struct sk_buff *skb; int truelength = 0; int do_queue = 1; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_write")) { return 0; } if(count == 0) { return 0; } if(port->active2.transmit == NULL) { return 0; } if((port->active2.transmit->Count & OWNER) == OWN_SAB) { sab8253x_start_txS(port); /* no descriptor slot */ return 0; } #ifndef FREEININTERRUPT skb = port->active2.transmit->HostVaddr; /* current slot value */ if(port->buffergreedy == 0) /* are we avoiding buffer free's */ { /* no */ if((skb != NULL) || /* not OWN_SAB from above */ (port->active2.transmit->crcindex != 0)) { register RING_DESCRIPTOR *freeme; freeme = port->active2.transmit; do { if((freeme->crcindex == 0) && (freeme->HostVaddr == NULL)) { break; } if(freeme->HostVaddr) { skb_unlink((struct sk_buff*)freeme->HostVaddr); dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); freeme->HostVaddr = NULL; } freeme->sendcrc = 0; freeme->crcindex = 0; freeme = (RING_DESCRIPTOR*) freeme->VNext; } while((freeme->Count & OWNER) != OWN_SAB); } skb = NULL; /* buffer was freed */ } if(skb != NULL) /* potentially useful */ { truelength = (skb->end - skb->head); if(truelength >= count) { skb->data = skb->head; /* this buffer is already queued */ skb->tail = skb->head; do_queue = 0; } else { skb_unlink(skb); dev_kfree_skb_any(skb); skb = NULL; port->active2.transmit->HostVaddr = NULL; } } /* in all cases the following is allowed */ port->active2.transmit->sendcrc = 0; port->active2.transmit->crcindex = 0; #endif if(skb == NULL) { if(port->DoingInterrupt) { skb = alloc_skb(count, GFP_ATOMIC); } else { skb = alloc_skb(count, GFP_KERNEL); } } if(skb == NULL) { printk(KERN_ALERT "sab8253xs: no skbuffs available.\n"); return 0; } if(from_user) { copy_from_user(skb->data, buf, count); } else { memcpy(skb->data, buf, count); } skb->tail = (skb->data + count); skb->data_len = count; skb->len = count; if(do_queue) { skb_queue_head(port->sab8253xbuflist, skb); } port->active2.transmit->HostVaddr = skb; port->active2.transmit->sendcrc = 0; port->active2.transmit->crcindex = 0; port->active2.transmit->Count = (OWN_SAB|count); port->active2.transmit = port->active2.transmit->VNext; sab8253x_start_txS(port); return count; } void sab8253x_throttleS(struct tty_struct * tty) { struct sab_port *port = (struct sab_port *)tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_throttleS")) { return; } if (!tty) { return; } if (I_IXOFF(tty)) { sab8253x_send_xcharS(tty, STOP_CHAR(tty)); } } void sab8253x_unthrottleS(struct tty_struct * tty) { struct sab_port *port = (struct sab_port *)tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_unthrottle")) { return; } if (!tty) { return; } if (I_IXOFF(tty)) { sab8253x_send_xcharS(tty, START_CHAR(tty)); } } void sab8253x_send_xcharS(struct tty_struct *tty, char ch) { struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long flags; int stopped; int hw_stopped; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_send_xcharS")) { return; } if (!tty) { return; } if(port->sabnext2.transmit == NULL) { return; } save_flags(flags); cli(); if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) /* may overwrite a character * -- but putting subsequent * XONs or XOFFs later in the * stream could cause problems * with the XON and XOFF protocol */ { port->sabnext2.transmit->sendcrc = 1; port->sabnext2.transmit->crcindex = 3; port->sabnext2.transmit->crc = (ch << 24); /* LITTLE ENDIAN */ restore_flags(flags); } else { restore_flags(flags); sab8253x_writeS(tty, 0, &ch, 1); } stopped = tty->stopped; hw_stopped = tty->hw_stopped; tty->stopped = 0; tty->hw_stopped = 0; sab8253x_start_txS(port); tty->stopped = stopped; tty->hw_stopped = hw_stopped; } void sab8253x_breakS(struct tty_struct *tty, int break_state) { struct sab_port *port = (struct sab_port *) tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_breakS")) { return; } /* can't break in sync mode */ } void sab8253x_closeS(struct tty_struct *tty, struct file * filp) { struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long flags; MOD_DEC_USE_COUNT; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_closeS")) { return; } if(port->open_type == OPEN_SYNC_NET) { /* port->tty field should already be NULL */ return; } save_flags(flags); cli(); --(port->count); if (tty_hung_up_p(filp)) { if(port->count == 0) /* I think the reason for the weirdness relates to freeing of structures in the tty driver */ { port->open_type = OPEN_NOT; } else if(port->count < 0) { printk(KERN_ALERT "XX20: port->count went negative.\n"); port->count = 0; port->open_type = OPEN_NOT; } restore_flags(flags); return; } #if 0 if ((tty->count == 1) && (port->count != 0)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. port->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("sab8253x_close: bad serial port count; tty->count is 1," " port->count is %d\n", port->count); port->count = 0; } #endif if (port->count < 0) { printk(KERN_ALERT "sab8253x_close: bad serial port count for ttys%d: %d\n", port->line, port->count); port->count = 0; } if (port->count) { restore_flags(flags); return; } port->flags |= FLAG8253X_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (port->flags & FLAG8253X_NORMAL_ACTIVE) { port->normal_termios = *tty->termios; } if (port->flags & FLAG8253X_CALLOUT_ACTIVE) { port->callout_termios = *tty->termios; } /* * 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 (port->closing_wait != SAB8253X_CLOSING_WAIT_NONE) { tty_wait_until_sent(tty, port->closing_wait); } /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and turn off * the receiver. */ #if 0 port->interrupt_mask0 |= SAB82532_IMR0_TCD; /* not needed for sync */ #endif WRITEB(port,imr0,port->interrupt_mask0); CLEAR_REG_BIT(port, mode, SAB82532_MODE_RAC); /* turn off receiver */ if (port->flags & FLAG8253X_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ sab8253x_wait_until_sent(tty, port->timeout); } sab8253x_shutdownS(port); Sab8253xCleanUpTransceiveN(port); if (tty->driver.flush_buffer) { tty->driver.flush_buffer(tty); } if (tty->ldisc.flush_buffer) { tty->ldisc.flush_buffer(tty); } tty->closing = 0; port->event = 0; port->tty = 0; if (port->blocked_open) { if (port->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); } port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| FLAG8253X_CLOSING); wake_up_interruptible(&port->close_wait); port->open_type = OPEN_NOT; restore_flags(flags); } void sab8253x_hangupS(struct tty_struct *tty) { struct sab_port * port = (struct sab_port *)tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_hangupS")) { return; } #ifdef XCONFIG_SERIAL_CONSOLE if (port->is_console) { return; } #endif sab8253x_flush_buffer(tty); if(port) { sab8253x_shutdownS(port); Sab8253xCleanUpTransceiveN(port); port->event = 0; port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE); port->tty = 0; wake_up_interruptible(&port->open_wait); } } int sab8253x_openS(struct tty_struct *tty, struct file * filp) { struct sab_port *port; int retval, line; int counter; unsigned long flags; MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; for(counter = 0, port = AuraPortRoot; (counter < line) && (port != NULL); ++counter) { port = port->next; } if (!port) { printk(KERN_ALERT "sab8253x_openS: can't find structure for line %d\n", line); return -ENODEV; } save_flags(flags); /* Need to protect port->tty element */ cli(); if(port->tty == 0) { port->tty = tty; tty->flip.tqueue.routine = sab8253x_flush_to_ldiscS; } tty->driver_data = port; if(port->function != FUNCTION_NR) { ++(port->count); restore_flags(flags); return -ENODEV; /* only allowed if there are no restrictions on the port */ } if(port->open_type == OPEN_SYNC_NET) { port->tty = NULL; /* Don't bother with open counting here but make sure the tty field is NULL*/ restore_flags(flags); return -EBUSY; } restore_flags(flags); if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_openS")) { ++(port->count); return -ENODEV; } #ifdef DEBUG_OPEN printk("sab8253x_open %s%d, count = %d\n", tty->driver.name, port->line, port->count); #endif /* * If the port is in the middle of closing, bail out now. */ if (tty_hung_up_p(filp) || (port->flags & FLAG8253X_CLOSING)) { if (port->flags & FLAG8253X_CLOSING) { interruptible_sleep_on(&port->close_wait); } #ifdef SERIAL_DO_RESTART ++(port->count); return ((port->flags & FLAG8253X_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); #else ++(port->count); return -EAGAIN; #endif } if(port->flags & FLAG8253X_NORMAL_ACTIVE) { if(port->open_type == OPEN_ASYNC) { ++(port->count); return -EBUSY; /* can't reopen in sync mode */ } } if(port->open_type > OPEN_SYNC) /* can reopen a SYNC_TTY */ { return -EBUSY; } if(Sab8253xSetUpLists(port)) { ++(port->count); return -ENODEV; } if(Sab8253xInitDescriptors2(port, sab8253xs_listsize, sab8253xs_rbufsize)) { ++(port->count); return -ENODEV; } retval = sab8253x_startupS(port); if (retval) { ++(port->count); return retval; /* does not check channel mode */ } retval = sab8253x_block_til_ready(tty, filp, port); /* checks channel mode */ ++(port->count); if (retval) { return retval; } port->tty = tty; /* may change here once through the block */ /* because now the port belongs to an new tty */ tty->flip.tqueue.routine = sab8253x_flush_to_ldiscS; if(Sab8253xSetUpLists(port)) { return -ENODEV; } if(Sab8253xInitDescriptors2(port, sab8253xs_listsize, sab8253xs_rbufsize)) { Sab8253xCleanUpTransceiveN(port); /* the network functions should be okay -- only difference */ /* is the crc32 that is appended */ return -ENODEV; } /* * Start up serial port */ retval = sab8253x_startupS(port); /* in case cu was running the first time * the function was called*/ if (retval) { return retval; /* does not check channel mode */ } if ((port->count == 1) && (port->flags & FLAG8253X_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) { *tty->termios = port->normal_termios; } else { *tty->termios = port->callout_termios; } sab8253x_change_speedS(port); } #ifdef XCONFIG_SERIAL_CONSOLE if (sab8253x_console.cflag && sab8253x_console.index == line) { tty->termios->c_cflag = sab8253x_console.cflag; sab8253x_console.cflag = 0; change_speed(port); } #endif port->session = current->session; port->pgrp = current->pgrp; port->open_type = OPEN_SYNC; return 0; }