📄 serial_tx3912.c
字号:
{ 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 void rs_close (void *ptr){ func_enter (); /* Anything to do here? */ MOD_DEC_USE_COUNT; func_exit ();}/* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug elsewhere. Thinking about it some more. (try it sometime) Try running minicom on a serial port that is driven by a modularized driver. Have the modem hangup. Then remove the driver module. Then exit minicom. I expect an "oops". -- REW */static void rs_hungup (void *ptr){ func_enter (); MOD_DEC_USE_COUNT; func_exit ();}static int rs_ioctl (struct tty_struct * tty, struct file * filp, unsigned int cmd, unsigned long arg){ int rc; struct rs_port *port = tty->driver_data; int ival; rc = 0; switch (cmd) { case TIOCGSOFTCAR: rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned int *) arg); break; case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(int))) == 0) { get_user(ival, (unsigned int *) arg); tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); } break; case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) rc = gs_getserial(&port->gs, (struct serial_struct *) arg); break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0) rc = gs_setserial(&port->gs, (struct serial_struct *) arg); break; default: rc = -ENOIOCTLCMD; break; } /* func_exit(); */ return rc;}/* * This function is used to send a high-priority XON/XOFF character to * the device */static void rs_send_xchar(struct tty_struct * tty, char ch){ struct rs_port *port = (struct rs_port *)tty->driver_data; func_enter (); port->x_char = ch; if (ch) { /* Make sure transmit interrupts are on */ rs_enable_tx_interrupts(tty); } func_exit();}/* * ------------------------------------------------------------ * rs_throttle() * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void rs_throttle(struct tty_struct * tty){#ifdef TX3912_UART_DEBUG_THROTTLE char buf[64]; printk("throttle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty));#endif func_enter (); if (I_IXOFF(tty)) rs_send_xchar(tty, STOP_CHAR(tty)); func_exit ();}static void rs_unthrottle(struct tty_struct * tty){ struct rs_port *port = (struct rs_port *)tty->driver_data;#ifdef TX3912_UART_DEBUG_THROTTLE char buf[64]; printk("unthrottle %s: %d....\n", tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty));#endif func_enter(); if (I_IXOFF(tty)) { if (port->x_char) port->x_char = 0; else rs_send_xchar(tty, START_CHAR(tty)); } func_exit();}/* ********************************************************************** * * Here are the initialization routines. * * ********************************************************************** */void * ckmalloc (int size){ void *p; p = kmalloc(size, GFP_KERNEL); if (p) memset(p, 0, size); return p;}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 int rs_init_drivers(void){ int error; func_enter(); memset(&rs_driver, 0, sizeof(rs_driver)); 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 = TX3912_UART_NPORTS; 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_table; 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; if ((error = tty_register_driver(&rs_driver))) { printk(KERN_ERR "Couldn't register serial driver, error = %d\n", error); return 1; } if ((error = tty_register_driver(&rs_callout_driver))) { tty_unregister_driver(&rs_driver); printk(KERN_ERR "Couldn't register callout driver, error = %d\n", error); return 1; } func_exit(); return 0;}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();}/* * Begin serial console routines */#ifdef CONFIG_SERIAL_TX3912_CONSOLEvoid serial_outc(unsigned char c){ int i; unsigned long int2; #define BUSY_WAIT 10000 /* * Turn UARTA interrupts off */ int2 = IntEnable2; IntEnable2 &= ~(INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY); /* * The UART_TX_EMPTY bit in UartA_Ctrl1 seems * not to be very reliable :-( * * Wait for the Tx register to become empty */ for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; UartA_Data = c; for (i = 0; !(IntStatus2 & INT2_UARTATXINT) && (i < BUSY_WAIT); i++); IntClear2 = INT2_UARTATXINT | INT2_UARTATXOVERRUN | INT2_UARTAEMPTY; IntEnable2 = int2;}static int serial_console_wait_key(struct console *co){ unsigned int int2, res; int2 = IntEnable2; IntEnable2 = 0; while (!(UartA_Ctrl1 & UART_RX_HOLD_FULL)); res = UartA_Data; udelay(10); IntEnable2 = int2; return res;}static void serial_console_write(struct console *co, const char *s, unsigned count){ unsigned int i; for (i = 0; i < count; i++) { if (*s == '\n') serial_outc('\r'); serial_outc(*s++); }}static kdev_t serial_console_device(struct console *c){ return MKDEV(TTY_MAJOR, 64 + c->index);}static __init int serial_console_setup(struct console *co, char *options){ 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); return 0;}static struct console sercons = { name: "ttyS", write: serial_console_write, device: serial_console_device, wait_key: serial_console_wait_key, setup: serial_console_setup, flags: CON_PRINTBUFFER, index: -1};void __init tx3912_console_init(void){ register_console(&sercons);}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -