/* * Open the serial port */ static int rs_open(struct tty_struct * tty, struct file * filp) { int retval; func_enter(); if(!rs_initialized) { return -EIO; } if(MINOR(tty->device) - tty->driver.minor_start) { return -ENODEV; } rs_dprintk(TX3912_UART_DEBUG_OPEN, "Serial opening...\n"); tty->driver_data = rs_port; rs_port->gs.tty = tty; rs_port->gs.count++; /* * Start up serial port */ retval = gs_init_port(&rs_port->gs); rs_dprintk(TX3912_UART_DEBUG_OPEN, "Finished gs_init...\n"); if(retval) { rs_port->gs.count--; return retval; } rs_port->gs.flags |= GS_ACTIVE; if(rs_port->gs.count == 1) { MOD_INC_USE_COUNT; } rs_enable_rx_interrupts(rs_port); rs_enable_tx_interrupts(rs_port); retval = gs_block_til_ready(&rs_port->gs, filp); if(retval) { MOD_DEC_USE_COUNT; rs_port->gs.count--; return retval; } if((rs_port->gs.count == 1) && (rs_port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = rs_port->gs.normal_termios; else *tty->termios = rs_port->gs.callout_termios; rs_set_real_termios(rs_port); } rs_port->gs.session = current->session; rs_port->gs.pgrp = current->pgrp; func_exit(); return 0; }
/* * TX interrupt handler */ static inline void rs_tx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags, status; save_and_cli(flags); rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_tx_interrupt..."); /* Get the interrupts */ status = inl(TX3912_INT2_STATUS); if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } /* Clear interrupts */ outl(TX3912_INT2_UARTA_TX_BITS, TX3912_INT2_CLEAR); /* TX holding register empty - transmit a byte */ if(status & TX3912_INT2_UARTAEMPTYINT) { transmit_char_pio(rs_port); } /* TX Transmit Holding Register Overrun (shouldn't happen) */ if(status & TX3912_INT2_UARTATXOVERRUNINT) { printk( "rs_tx_interrupt: TX overrun\n"); } restore_flags(flags); rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); }
static int rs_init_portstructs(void) { struct rs_port *port; int i; /* Debugging */ func_enter(); rs_ports = ckmalloc(TX3912_UART_NPORTS * sizeof (struct rs_port)); if (!rs_ports) return -ENOMEM; rs_termios = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); if (!rs_termios) { kfree (rs_ports); return -ENOMEM; } rs_termios_locked = ckmalloc(TX3912_UART_NPORTS * sizeof (struct termios *)); if (!rs_termios_locked) { kfree (rs_ports); kfree (rs_termios); return -ENOMEM; } /* Adjust the values in the "driver" */ rs_driver.termios = rs_termios; rs_driver.termios_locked = rs_termios_locked; port = rs_ports; for (i=0; i < TX3912_UART_NPORTS;i++) { rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i); port->gs.callout_termios = tty_std_termios; port->gs.normal_termios = tty_std_termios; port->gs.magic = SERIAL_MAGIC; port->gs.close_delay = HZ/2; port->gs.closing_wait = 30 * HZ; port->gs.rd = &rs_real_driver; #ifdef NEW_WRITE_LOCKING port->gs.port_write_sem = MUTEX; #endif #ifdef DECLARE_WAITQUEUE init_waitqueue_head(&port->gs.open_wait); init_waitqueue_head(&port->gs.close_wait); #endif port->base = (i == 0) ? TX3912_UARTA_BASE : TX3912_UARTB_BASE; port->intshift = (i == 0) ? UARTA_SHIFT : UARTB_SHIFT; rs_dprintk (TX3912_UART_DEBUG_INIT, "base 0x%08lx intshift %d\n", port->base, port->intshift); port++; } func_exit(); return 0; }
static inline void rs_tx_interrupt(int irq, void *dev_id, struct pt_regs * regs, int intshift) { struct rs_port * port; unsigned long int2status; unsigned long flags; unsigned long ints; save_and_cli(flags); port = (struct rs_port *)dev_id; rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); /* Get the interrrupts we have enabled */ int2status = IntStatus2 & IntEnable2; if (!port || !port->gs.tty) { restore_flags(flags); return; } /* Get interrupts in easy to use form */ ints = int2status >> intshift; /* Clear any interrupts we might be about to handle */ IntClear2 = int2status & ( (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT) | INTTYPE(UART_TXOVERRUN_INT)) << intshift); /* TX holding register empty, so transmit byte (non-DMA) */ if (ints & (INTTYPE(UART_TX_INT) | INTTYPE(UART_EMPTY_INT))) { transmit_char_pio(port); } /* TX Transmit Holding Register Overrun (shouldn't happen) */ if (ints & INTTYPE(UART_TXOVERRUN_INT)) { printk ( "rs: TX overrun\n"); } /* check_modem_status(); */ restore_flags(flags); rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); }
/* * RX interrupt handler */ static inline void rs_rx_interrupt(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags, status; save_and_cli(flags); rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "rs_rx_interrupt..."); /* Get the interrupts */ status = inl(TX3912_INT2_STATUS); /* Clear any interrupts we might be about to handle */ outl(TX3912_INT2_UARTA_RX_BITS, TX3912_INT2_CLEAR); if(!rs_port || !rs_port->gs.tty) { restore_flags(flags); return; } /* RX Receiver Holding Register Overrun */ if(status & TX3912_INT2_UARTATXOVERRUNINT) { rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "overrun"); rs_port->icount.overrun++; } /* RX Frame Error */ if(status & TX3912_INT2_UARTAFRAMEERRINT) { rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "frame error"); rs_port->icount.frame++; } /* Break signal received */ if(status & TX3912_INT2_UARTABREAKINT) { rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "break"); rs_port->icount.brk++; } /* RX Parity Error */ if(status & TX3912_INT2_UARTAPARITYINT) { rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "parity error"); rs_port->icount.parity++; } /* Byte received */ if(status & TX3912_INT2_UARTARXINT) { receive_char_pio(rs_port); } restore_flags(flags); rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); }
/* * Transmit a character */ static inline void transmit_char_pio(struct rs_port *port) { /* TX while bytes available */ for (;;) { if (!(inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_EMPTY)) break; else if (port->x_char) { outb(port->x_char, TX3912_UARTA_DATA); port->icount.tx++; port->x_char = 0; } else if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped || port->gs.tty->hw_stopped) { break; } else { outb(port->gs.xmit_buf[port->gs.xmit_tail++], TX3912_UARTA_DATA); port->icount.tx++; port->gs.xmit_tail &= SERIAL_XMIT_SIZE-1; if (--port->gs.xmit_cnt <= 0) { break; } } udelay(10); } if (port->gs.xmit_cnt <= 0 || port->gs.tty->stopped || port->gs.tty->hw_stopped) { rs_disable_tx_interrupts(port); } if (port->gs.xmit_cnt <= port->gs.wakeup_chars) { if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && port->gs.tty->ldisc.write_wakeup) (port->gs.tty->ldisc.write_wakeup)(port->gs.tty); rs_dprintk(TX3912_UART_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n", port->gs.wakeup_chars); wake_up_interruptible(&port->gs.tty->write_wait); } }
/* * Initialize the serial port */ void __init tx3912_rs_init(void) { func_enter(); rs_dprintk(TX3912_UART_DEBUG_INIT, "Initializing serial...\n"); /* Allocate critical structures */ if(!(rs_tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL))) { return; } if(!(rs_port = kmalloc(sizeof(struct rs_port), GFP_KERNEL))) { kfree(rs_tty); return; } if(!(rs_termios = kmalloc(sizeof(struct termios), GFP_KERNEL))) { kfree(rs_port); kfree(rs_tty); return; } if(!(rs_termios_locked = kmalloc(sizeof(struct termios), GFP_KERNEL))) { kfree(rs_termios); kfree(rs_port); kfree(rs_tty); return; } /* Zero out the structures */ memset(rs_tty, 0, sizeof(struct tty_struct)); memset(rs_port, 0, sizeof(struct rs_port)); memset(rs_termios, 0, sizeof(struct termios)); memset(rs_termios_locked, 0, sizeof(struct termios)); memset(&rs_driver, 0, sizeof(rs_driver)); memset(&rs_callout_driver, 0, sizeof(rs_callout_driver)); /* Fill in hardware specific port structure */ rs_port->gs.callout_termios = tty_std_termios; rs_port->gs.normal_termios = tty_std_termios; rs_port->gs.magic = SERIAL_MAGIC; rs_port->gs.close_delay = HZ/2; rs_port->gs.closing_wait = 30 * HZ; rs_port->gs.rd = &rs_real_driver; #ifdef NEW_WRITE_LOCKING rs_port->gs.port_write_sem = MUTEX; #endif #ifdef DECLARE_WAITQUEUE init_waitqueue_head(&rs_port->gs.open_wait); init_waitqueue_head(&rs_port->gs.close_wait); #endif /* Fill in generic serial driver structures */ rs_driver.magic = TTY_DRIVER_MAGIC; rs_driver.driver_name = "serial"; rs_driver.name = "ttyS"; rs_driver.major = TTY_MAJOR; rs_driver.minor_start = 64; rs_driver.num = 1; rs_driver.type = TTY_DRIVER_TYPE_SERIAL; rs_driver.subtype = SERIAL_TYPE_NORMAL; rs_driver.init_termios = tty_std_termios; rs_driver.init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; rs_driver.refcount = &rs_refcount; rs_driver.table = rs_tty; rs_driver.termios = rs_termios; rs_driver.termios_locked = rs_termios_locked; rs_driver.open = rs_open; rs_driver.close = gs_close; rs_driver.write = gs_write; rs_driver.put_char = gs_put_char; rs_driver.flush_chars = gs_flush_chars; rs_driver.write_room = gs_write_room; rs_driver.chars_in_buffer = gs_chars_in_buffer; rs_driver.flush_buffer = gs_flush_buffer; rs_driver.ioctl = rs_ioctl; rs_driver.throttle = rs_throttle; rs_driver.unthrottle = rs_unthrottle; rs_driver.set_termios = gs_set_termios; rs_driver.stop = gs_stop; rs_driver.start = gs_start; rs_driver.hangup = gs_hangup; rs_callout_driver = rs_driver; rs_callout_driver.name = "cua"; rs_callout_driver.major = TTYAUX_MAJOR; rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT; /* Register serial and callout drivers */ if(tty_register_driver(&rs_driver)) { printk(KERN_ERR "Unable to register serial driver\n"); goto error; } if(tty_register_driver(&rs_callout_driver)) { tty_unregister_driver(&rs_driver); printk(KERN_ERR "Unable to register callout driver\n"); goto error; } /* Assign IRQs */ if(request_irq(2, rs_tx_interrupt, SA_SHIRQ, "uarta_tx", rs_port)) { printk(KERN_ERR "Cannot allocate IRQ for UARTA_TX.\n"); goto error; } if(request_irq(3, rs_rx_interrupt, SA_SHIRQ, "uarta_rx", rs_port)) { printk(KERN_ERR "Cannot allocate IRQ for UARTA_RX.\n"); goto error; } /* Enable the serial receive interrupt */ rs_enable_rx_interrupts(rs_port); #ifndef CONFIG_SERIAL_TX3912_CONSOLE /* Write the control registers */ outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_CTRL2); outl(0x00000000, TX3912_UARTA_DMA_CTRL1); outl(0x00000000, TX3912_UARTA_DMA_CTRL2); outl(inl(TX3912_UARTA_CTRL1) | TX3912_UART_CTRL1_ENUART, TX3912_UARTA_CTRL1); /* Loop until the UART is on */ while(~inl(TX3912_UARTA_CTRL1) & TX3912_UART_CTRL1_UARTON); #endif rs_initialized = 1; func_exit(); return; error: kfree(rs_termios_locked); kfree(rs_termios); kfree(rs_port); kfree(rs_tty); func_exit(); }
/* * ---------------------------------------------------------------------- * * Here starts the interrupt handling routines. All of the following * subroutines are declared as inline and are folded into * rs_interrupt(). They were separated out for readability's sake. * * Note: rs_interrupt() is a "fast" interrupt, which means that it * runs with interrupts turned off. People who may want to modify * rs_interrupt() should try to keep the interrupt handler as fast as * possible. After you are done making modifications, it is not a bad * idea to do: * * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c * * and look at the resulting assemble code in serial.s. * * - Ted Ts'o ([email protected]), 7-Mar-93 * ----------------------------------------------------------------------- */ static inline void receive_char_pio(struct rs_port *port) { struct tty_struct *tty = port->gs.tty; unsigned char ch; int counter = 2048; /* While there are characters, get them ... */ while (counter>0) { if (!(inl(port->base + TX3912_UART_CTRL1) & UART_RX_HOLD_FULL)) break; ch = inb(port->base + TX3912_UART_DATA); if (tty->flip.count < TTY_FLIPBUF_SIZE) { *tty->flip.char_buf_ptr++ = ch; *tty->flip.flag_buf_ptr++ = 0; tty->flip.count++; } udelay(1); /* Allow things to happen - it take a while */ counter--; } if (!counter) printk( "Ugh, looped in receive_char_pio!\n" ); tty_flip_buffer_push(tty); #if 0 /* Now handle error conditions */ if (*status & (INTTYPE(UART_RXOVERRUN_INT) | INTTYPE(UART_FRAMEERR_INT) | INTTYPE(UART_PARITYERR_INT) | INTTYPE(UART_BREAK_INT))) { /* * Now check to see if character should be * ignored, and mask off conditions which * should be ignored. */ if (*status & port->ignore_status_mask) { goto ignore_char; } *status &= port->read_status_mask; if (*status & INTTYPE(UART_BREAK_INT)) { rs_dprintk(TX3912_UART_DEBUG_INTERRUPTS, "handling break...."); *tty->flip.flag_buf_ptr = TTY_BREAK; } else if (*status & INTTYPE(UART_PARITYERR_INT)) { *tty->flip.flag_buf_ptr = TTY_PARITY; } else if (*status & INTTYPE(UART_FRAMEERR_INT)) { *tty->flip.flag_buf_ptr = TTY_FRAME; } if (*status & INTTYPE(UART_RXOVERRUN_INT)) { /* * Overrun is special, since it's * reported immediately, and doesn't * affect the current character */ if (tty->flip.count < TTY_FLIPBUF_SIZE) { tty->flip.count++; tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; *tty->flip.flag_buf_ptr = TTY_OVERRUN; } } } tty->flip.flag_buf_ptr++; tty->flip.char_buf_ptr++; tty->flip.count++; ignore_char: tty_flip_buffer_push(tty); #endif }
void __init tx3912_rs_init(void) { int rc; func_enter(); rs_dprintk (TX3912_UART_DEBUG_INIT, "Initing serial module... (rs_debug=%d)\n", rs_debug); rc = rs_init_portstructs (); rs_init_drivers (); if (request_irq(2, rs_tx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, "serial", &rs_ports[0])) { printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); rc = 0; } if (request_irq(3, rs_rx_interrupt_uarta, SA_SHIRQ | SA_INTERRUPT, "serial", &rs_ports[0])) { printk(KERN_ERR "rs: Cannot allocate irq for UARTA.\n"); rc = 0; } IntEnable6 |= INT6_UARTARXINT; rs_enable_rx_interrupts(&rs_ports[0]); #ifndef CONFIG_SERIAL_TX3912_CONSOLE { unsigned int scratch = 0; /* Setup master clock for UART */ scratch = inl(TX3912_CLK_CTRL_BASE); scratch &= ~TX3912_CLK_CTRL_SIBMCLKDIV_MASK; scratch |= ((0x2 << TX3912_CLK_CTRL_SIBMCLKDIV_SHIFT) & TX3912_CLK_CTRL_SIBMCLKDIV_MASK) | TX3912_CLK_CTRL_SIBMCLKDIR | TX3912_CLK_CTRL_ENSIBMCLK | TX3912_CLK_CTRL_CSERSEL; outl(scratch, TX3912_CLK_CTRL_BASE); /* Configure UARTA clock */ scratch = inl(TX3912_CLK_CTRL_BASE); scratch |= ((0x3 << TX3912_CLK_CTRL_CSERDIV_SHIFT) & TX3912_CLK_CTRL_CSERDIV_MASK) | TX3912_CLK_CTRL_ENCSERCLK | TX3912_CLK_CTRL_ENUARTACLK; outl(scratch, TX3912_CLK_CTRL_BASE); /* Setup UARTA for 115200,8N1 */ outl(0, TX3912_UARTA_BASE + TX3912_UART_CTRL1); outl(TX3912_UART_CTRL2_B115200, TX3912_UARTA_BASE + TX3912_UART_CTRL2); outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL1); outl(0, TX3912_UARTA_BASE + TX3912_UART_DMA_CTRL2); /* Enable UARTA */ outl(TX3912_UART_CTRL1_ENUART, TX3912_UARTA_BASE + TX3912_UART_CTRL1); while (~inl(TX3912_UARTA_BASE + TX3912_UART_CTRL1) & TX3912_UART_CTRL1_UARTON); } #endif /* Note: I didn't do anything to enable the second UART */ if (rc >= 0) rs_initialized++; func_exit(); }
/* ********************************************************************** * * Here are the routines that actually * * interface with the rest of the system * * ********************************************************************** */ static int rs_open (struct tty_struct * tty, struct file * filp) { struct rs_port *port; int retval, line; func_enter(); if (!rs_initialized) { return -EIO; } line = MINOR(tty->device) - tty->driver.minor_start; rs_dprintk (TX3912_UART_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p)\n", (int) current->pid, line, tty, current->tty); if ((line < 0) || (line >= TX3912_UART_NPORTS)) return -ENODEV; /* Pre-initialized already */ port = & rs_ports[line]; rs_dprintk (TX3912_UART_DEBUG_OPEN, "port = %p\n", port); tty->driver_data = port; port->gs.tty = tty; port->gs.count++; rs_dprintk (TX3912_UART_DEBUG_OPEN, "starting port\n"); /* * Start up serial port */ retval = gs_init_port(&port->gs); rs_dprintk (TX3912_UART_DEBUG_OPEN, "done gs_init\n"); if (retval) { port->gs.count--; return retval; } port->gs.flags |= GS_ACTIVE; rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", port->gs.count); if (port->gs.count == 1) { MOD_INC_USE_COUNT; } rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n"); /* Jim: Initialize port hardware here */ /* Enable high-priority interrupts for UARTA */ IntEnable6 |= INT6_UARTARXINT; rs_enable_rx_interrupts(&rs_ports[0]); retval = gs_block_til_ready(&port->gs, filp); rs_dprintk (TX3912_UART_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n", retval, port->gs.count); if (retval) { MOD_DEC_USE_COUNT; port->gs.count--; return retval; } /* tty->low_latency = 1; */ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = port->gs.normal_termios; else *tty->termios = port->gs.callout_termios; rs_set_real_termios (port); } port->gs.session = current->session; port->gs.pgrp = current->pgrp; func_exit(); /* Jim */ /* cli(); */ return 0; }
static inline void rs_rx_interrupt(int irq, void *dev_id, struct pt_regs * regs, int intshift) { struct rs_port * port; unsigned long int2status; unsigned long flags; unsigned long ints; save_and_cli(flags); port = (struct rs_port *)dev_id; rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "rs_interrupt (port %p, shift %d)...", port, intshift); /* Get the interrrupts we have enabled */ int2status = IntStatus2 & IntEnable2; /* Get interrupts in easy to use form */ ints = int2status >> intshift; /* Clear any interrupts we might be about to handle */ IntClear2 = int2status & ( (INTTYPE(UART_RXOVERRUN_INT) | INTTYPE(UART_FRAMEERR_INT) | INTTYPE(UART_BREAK_INT) | INTTYPE(UART_PARITYERR_INT) | INTTYPE(UART_RX_INT)) << intshift); if (!port || !port->gs.tty) { restore_flags(flags); return; } /* RX Receiver Holding Register Overrun */ if (ints & INTTYPE(UART_RXOVERRUN_INT)) { rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "overrun"); port->icount.overrun++; } /* RX Frame Error */ if (ints & INTTYPE(UART_FRAMEERR_INT)) { rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "frame error"); port->icount.frame++; } /* Break signal received */ if (ints & INTTYPE(UART_BREAK_INT)) { rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "break"); port->icount.brk++; } /* RX Parity Error */ if (ints & INTTYPE(UART_PARITYERR_INT)) { rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "parity error"); port->icount.parity++; } /* Receive byte (non-DMA) */ if (ints & INTTYPE(UART_RX_INT)) { receive_char_pio(port); } restore_flags(flags); rs_dprintk (TX3912_UART_DEBUG_INTERRUPTS, "end.\n"); }