📄 jsm_tty.c
字号:
/************************************************************************ * Copyright 2003 Digi International (www.digi.com) * * Copyright (C) 2004 IBM Corporation. All rights reserved. * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 * Temple Place - Suite 330, Boston, * MA 02111-1307, USA. * * Contact Information: * Scott H Kilau <Scott_Kilau@digi.com> * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com> * ***********************************************************************/#include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/serial_reg.h>#include <linux/delay.h> /* For udelay */#include <linux/pci.h>#include "jsm.h"static void jsm_carrier(struct jsm_channel *ch);static inline int jsm_get_mstat(struct jsm_channel *ch){ unsigned char mstat; unsigned result; jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "start\n"); mstat = (ch->ch_mostat | ch->ch_mistat); result = 0; if (mstat & UART_MCR_DTR) result |= TIOCM_DTR; if (mstat & UART_MCR_RTS) result |= TIOCM_RTS; if (mstat & UART_MSR_CTS) result |= TIOCM_CTS; if (mstat & UART_MSR_DSR) result |= TIOCM_DSR; if (mstat & UART_MSR_RI) result |= TIOCM_RI; if (mstat & UART_MSR_DCD) result |= TIOCM_CD; jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n"); return result;}static unsigned int jsm_tty_tx_empty(struct uart_port *port){ return TIOCSER_TEMT;}/* * Return modem signals to ld. */static unsigned int jsm_tty_get_mctrl(struct uart_port *port){ int result; struct jsm_channel *channel = (struct jsm_channel *)port; jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); result = jsm_get_mstat(channel); if (result < 0) return -ENXIO; jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); return result;}/* * jsm_set_modem_info() * * Set modem signals, called by ld. */static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl){ struct jsm_channel *channel = (struct jsm_channel *)port; jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); if (mctrl & TIOCM_RTS) channel->ch_mostat |= UART_MCR_RTS; else channel->ch_mostat &= ~UART_MCR_RTS; if (mctrl & TIOCM_DTR) channel->ch_mostat |= UART_MCR_DTR; else channel->ch_mostat &= ~UART_MCR_DTR; channel->ch_bd->bd_ops->assert_modem_signals(channel); jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n"); udelay(10);}static void jsm_tty_start_tx(struct uart_port *port){ struct jsm_channel *channel = (struct jsm_channel *)port; jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); channel->ch_flags &= ~(CH_STOP); jsm_tty_write(port); jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");}static void jsm_tty_stop_tx(struct uart_port *port){ struct jsm_channel *channel = (struct jsm_channel *)port; jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "start\n"); channel->ch_flags |= (CH_STOP); jsm_printk(IOCTL, INFO, &channel->ch_bd->pci_dev, "finish\n");}static void jsm_tty_send_xchar(struct uart_port *port, char ch){ unsigned long lock_flags; struct jsm_channel *channel = (struct jsm_channel *)port; spin_lock_irqsave(&port->lock, lock_flags); if (ch == port->info->tty->termios->c_cc[VSTART]) channel->ch_bd->bd_ops->send_start_character(channel); if (ch == port->info->tty->termios->c_cc[VSTOP]) channel->ch_bd->bd_ops->send_stop_character(channel); spin_unlock_irqrestore(&port->lock, lock_flags);}static void jsm_tty_stop_rx(struct uart_port *port){ struct jsm_channel *channel = (struct jsm_channel *)port; channel->ch_bd->bd_ops->disable_receiver(channel);}static void jsm_tty_break(struct uart_port *port, int break_state){ unsigned long lock_flags; struct jsm_channel *channel = (struct jsm_channel *)port; spin_lock_irqsave(&port->lock, lock_flags); if (break_state == -1) channel->ch_bd->bd_ops->send_break(channel); else channel->ch_bd->bd_ops->clear_break(channel, 0); spin_unlock_irqrestore(&port->lock, lock_flags);}static int jsm_tty_open(struct uart_port *port){ struct jsm_board *brd; int rc = 0; struct jsm_channel *channel = (struct jsm_channel *)port; /* Get board pointer from our array of majors we have allocated */ brd = channel->ch_bd; /* * Allocate channel buffers for read/write/error. * Set flag, so we don't get trounced on. */ channel->ch_flags |= (CH_OPENING); /* Drop locks, as malloc with GFP_KERNEL can sleep */ if (!channel->ch_rqueue) { channel->ch_rqueue = (u8 *) kmalloc(RQUEUESIZE, GFP_KERNEL); if (!channel->ch_rqueue) { jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, "unable to allocate read queue buf"); return -ENOMEM; } memset(channel->ch_rqueue, 0, RQUEUESIZE); } if (!channel->ch_equeue) { channel->ch_equeue = (u8 *) kmalloc(EQUEUESIZE, GFP_KERNEL); if (!channel->ch_equeue) { jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, "unable to allocate error queue buf"); return -ENOMEM; } memset(channel->ch_equeue, 0, EQUEUESIZE); } if (!channel->ch_wqueue) { channel->ch_wqueue = (u8 *) kmalloc(WQUEUESIZE, GFP_KERNEL); if (!channel->ch_wqueue) { jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, "unable to allocate write queue buf"); return -ENOMEM; } memset(channel->ch_wqueue, 0, WQUEUESIZE); } channel->ch_flags &= ~(CH_OPENING); /* * Initialize if neither terminal is open. */ jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "jsm_open: initializing channel in open...\n"); /* * Flush input queues. */ channel->ch_r_head = channel->ch_r_tail = 0; channel->ch_e_head = channel->ch_e_tail = 0; channel->ch_w_head = channel->ch_w_tail = 0; brd->bd_ops->flush_uart_write(channel); brd->bd_ops->flush_uart_read(channel); channel->ch_flags = 0; channel->ch_cached_lsr = 0; channel->ch_stops_sent = 0; channel->ch_c_cflag = port->info->tty->termios->c_cflag; channel->ch_c_iflag = port->info->tty->termios->c_iflag; channel->ch_c_oflag = port->info->tty->termios->c_oflag; channel->ch_c_lflag = port->info->tty->termios->c_lflag; channel->ch_startc = port->info->tty->termios->c_cc[VSTART]; channel->ch_stopc = port->info->tty->termios->c_cc[VSTOP]; /* Tell UART to init itself */ brd->bd_ops->uart_init(channel); /* * Run param in case we changed anything */ brd->bd_ops->param(channel); jsm_carrier(channel); channel->ch_open_count++; jsm_printk(OPEN, INFO, &channel->ch_bd->pci_dev, "finish\n"); return rc;}static void jsm_tty_close(struct uart_port *port){ struct jsm_board *bd; struct termios *ts; struct jsm_channel *channel = (struct jsm_channel *)port; jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n"); bd = channel->ch_bd; ts = channel->uart_port.info->tty->termios; channel->ch_flags &= ~(CH_STOPI); channel->ch_open_count--; /* * If we have HUPCL set, lower DTR and RTS */ if (channel->ch_c_cflag & HUPCL) { jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "Close. HUPCL set, dropping DTR/RTS\n"); /* Drop RTS/DTR */ channel->ch_mostat &= ~(UART_MCR_DTR | UART_MCR_RTS); bd->bd_ops->assert_modem_signals(channel); } channel->ch_old_baud = 0; /* Turn off UART interrupts for this port */ channel->ch_bd->bd_ops->uart_off(channel); jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "finish\n");}static void jsm_tty_set_termios(struct uart_port *port, struct termios *termios, struct termios *old_termios){ unsigned long lock_flags; struct jsm_channel *channel = (struct jsm_channel *)port; spin_lock_irqsave(&port->lock, lock_flags); channel->ch_c_cflag = termios->c_cflag; channel->ch_c_iflag = termios->c_iflag; channel->ch_c_oflag = termios->c_oflag; channel->ch_c_lflag = termios->c_lflag; channel->ch_startc = termios->c_cc[VSTART]; channel->ch_stopc = termios->c_cc[VSTOP]; channel->ch_bd->bd_ops->param(channel); jsm_carrier(channel); spin_unlock_irqrestore(&port->lock, lock_flags);}static const char *jsm_tty_type(struct uart_port *port){ return "jsm";}static void jsm_tty_release_port(struct uart_port *port){}static int jsm_tty_request_port(struct uart_port *port){ return 0;}static void jsm_config_port(struct uart_port *port, int flags){ port->type = PORT_JSM;}static struct uart_ops jsm_ops = { .tx_empty = jsm_tty_tx_empty, .set_mctrl = jsm_tty_set_mctrl, .get_mctrl = jsm_tty_get_mctrl, .stop_tx = jsm_tty_stop_tx, .start_tx = jsm_tty_start_tx, .send_xchar = jsm_tty_send_xchar, .stop_rx = jsm_tty_stop_rx, .break_ctl = jsm_tty_break, .startup = jsm_tty_open, .shutdown = jsm_tty_close, .set_termios = jsm_tty_set_termios, .type = jsm_tty_type, .release_port = jsm_tty_release_port, .request_port = jsm_tty_request_port, .config_port = jsm_config_port,};/* * jsm_tty_init() * * Init the tty subsystem. Called once per board after board has been * downloaded and init'ed. */int jsm_tty_init(struct jsm_board *brd){ int i; void __iomem *vaddr; struct jsm_channel *ch; if (!brd) return -ENXIO; jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); /* * Initialize board structure elements. */ brd->nasync = brd->maxports; /* * Allocate channel memory that might not have been allocated * when the driver was first loaded. */ for (i = 0; i < brd->nasync; i++) { if (!brd->channels[i]) { /* * Okay to malloc with GFP_KERNEL, we are not at * interrupt context, and there are no locks held. */ brd->channels[i] = kmalloc(sizeof(struct jsm_channel), GFP_KERNEL); if (!brd->channels[i]) { jsm_printk(CORE, ERR, &brd->pci_dev, "%s:%d Unable to allocate memory for channel struct\n", __FILE__, __LINE__); } memset(brd->channels[i], 0, sizeof(struct jsm_channel)); } } ch = brd->channels[0]; vaddr = brd->re_map_membase; /* Set up channel variables */ for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { if (!brd->channels[i]) continue; spin_lock_init(&ch->ch_lock); if (brd->bd_uart_offset == 0x200) ch->ch_neo_uart = vaddr + (brd->bd_uart_offset * i); ch->ch_bd = brd; ch->ch_portnum = i; /* .25 second delay */ ch->ch_close_delay = 250; init_waitqueue_head(&ch->ch_flags_wait); } jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); return 0;}int jsm_uart_port_init(struct jsm_board *brd){ int i; struct jsm_channel *ch; if (!brd) return -ENXIO; jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); /* * Initialize board structure elements. */ brd->nasync = brd->maxports; /* Set up channel variables */ for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { if (!brd->channels[i]) continue; brd->channels[i]->uart_port.irq = brd->irq; brd->channels[i]->uart_port.type = PORT_JSM; brd->channels[i]->uart_port.iotype = UPIO_MEM; brd->channels[i]->uart_port.membase = brd->re_map_membase; brd->channels[i]->uart_port.fifosize = 16; brd->channels[i]->uart_port.ops = &jsm_ops; brd->channels[i]->uart_port.line = brd->channels[i]->ch_portnum + brd->boardnum * 2; if (uart_add_one_port (&jsm_uart_driver, &brd->channels[i]->uart_port)) printk(KERN_INFO "Added device failed\n"); else printk(KERN_INFO "Added device \n"); } jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); return 0;}int jsm_remove_uart_port(struct jsm_board *brd){ int i; struct jsm_channel *ch; if (!brd) return -ENXIO; jsm_printk(INIT, INFO, &brd->pci_dev, "start\n"); /* * Initialize board structure elements. */ brd->nasync = brd->maxports; /* Set up channel variables */ for (i = 0; i < brd->nasync; i++) { if (!brd->channels[i]) continue; ch = brd->channels[i]; uart_remove_one_port(&jsm_uart_driver, &brd->channels[i]->uart_port); } jsm_printk(INIT, INFO, &brd->pci_dev, "finish\n"); return 0;}void jsm_input(struct jsm_channel *ch){ struct jsm_board *bd; struct tty_struct *tp; u32 rmask; u16 head; u16 tail; int data_len; unsigned long lock_flags; int flip_len; int len = 0; int n = 0; char *buf = NULL; char *buf2 = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -