📄 serial_44b0.c
字号:
info->IER = 0;
serial_outp(info, UART_IER, 0x00); // disable all intrs
*/
disable_uart_rx_interrupt(info->line);
disable_uart_tx_interrupt(info->line);
if(info->line==0||info->line==1)
(void)uart_in(info, UART_RX); // read data port to reset things
/*else */
/*(void)uart_in(info, EX_UART_RX); // read data port to reset things*/
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~ASYNC_INITIALIZED;
restore_flags(flags);
}
#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
static int baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300,
600, 1200, 1800, 2400, 4800, 9600, 19200,
38400, 57600, 115200, 230400, 460800, 0 };
#endif
/*
* 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,
struct termios *old_termios)
{
int quot = 0, baud_base, baud;
// unsigned cflag, cval, fcr = 0;
unsigned cflag, cval;
int bits;
unsigned long flags;
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
if (!CONFIGURED_SERIAL_PORT(info))
return;
// byte size and parity
switch (cflag & CSIZE) {
case CS5: cval = 0x00; bits = 7; break;
case CS6: cval = 0x01; bits = 8; break;
case CS7: cval = 0x02; bits = 9; break;
case CS8: cval = 0x03; bits = 10; break;
// Never happens, but GCC is too dumb to figure it out
default: cval = 0x00; bits = 7; break;
}
if (cflag & CSTOPB) {
cval |= 0x04;
bits++;
}
if (cflag & PARENB) {
bits++;
}
if (cflag & PARODD)
cval |= UART_LCR_OPAR;
else if (cflag & PARENB)
cval |= UART_LCR_EPAR;
else
cval |= UART_LCR_NPAR;
#ifdef CONFIG_SERIAL_SAMSUNG_IRDA
if (info->line == 1){
cval |= UART_LCR_IRDA;
}
#endif
// Determine divisor based on baud rate
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600; // B0 transition handled in rs_set_termios
baud_base = info->state->baud_base;
quot = 1; //tricky
// If the quotient is zero refuse the change
if (!quot && old_termios) {
info->tty->termios->c_cflag &= ~CBAUD;
info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600;
}
// As a last resort, if the quotient is zero, default to 9600 bps
if (!quot)
quot = baud_base / 9600;
//
// Work around a bug in the Oxford Semiconductor 952 rev B
// chip which causes it to seriously miscalculate baud rates
// when DLL is 0.
//
info->quot = quot;
info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
info->timeout += HZ/50; // Add .02 seconds of slop
//
// Set up parity check flag
//
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
if (I_INPCK(info->tty))
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= UART_LSR_BI;
//
// Characters to ignore
//
info->ignore_status_mask = 0;
if (I_IGNPAR(info->tty))
info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
if (I_IGNBRK(info->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))
info->ignore_status_mask |= UART_LSR_OE;
}
save_flags(flags); cli();
info->LCR = cval; // Save LCR
if(info->line==0||info->line==1)
{
serial_outp(info, UART_BDR, baudrate_div(baud));
serial_outp(info, UART_LCR, cval);
}
/*else */
/*{ */
/*serial_outp(info, EX_UART_LCR, 0x80); //set line ctrol */
/*serial_outp(info, EX_UART_BDR, 115200%baud); */
/*serial_outp(info, EX_UART_BDR+1, 115200/baud); */
/*serial_outp(info, EX_UART_LCR, cval); //re set line ctrol*/
/*} */
restore_flags(flags);
}
static void rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_put_char"))
return;
if (!tty || !info->xmit.buf)
return;
save_flags(flags); cli();
if (CIRC_SPACE(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE) == 0) {
restore_flags(flags);
return;
}
#ifdef UARTPOLLING
wait_for_xmitr(info);
/* Send the character out. */
if(info->line==0||info->line==1)
uart_out(info, UART_TX, ch);
/*else */
/*uart_out(info, EX_UART_TX, ch);*/
#else
info->xmit.buf[info->xmit.head] = ch;
info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
#endif
restore_flags(flags);
}
static void rs_flush_chars(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
return;
if (info->xmit.head == info->xmit.tail
|| tty->stopped
|| tty->hw_stopped
|| !info->xmit.buf)
return;
save_flags(flags); cli();
enable_uart_tx_interrupt(info->line);
restore_flags(flags);
}
static int rs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
int c, ret = 0;
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_write"))
return 0;
if (!tty || !info->xmit.buf || !tmp_buf)
return 0;
save_flags(flags);
if (from_user) {
down(&tmp_buf_sem);
while (1) {
int c1;
c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
if (count < c)
c = count;
if (c <= 0)
break;
c -= copy_from_user(tmp_buf, buf, c);
if (!c) {
if (!ret)
ret = -EFAULT;
break;
}
cli();
c1 = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
if (c1 < c)
c = c1;
memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1));
restore_flags(flags);
buf += c;
count -= c;
ret += c;
}
up(&tmp_buf_sem);
} else {
cli();
while (1) {
c = CIRC_SPACE_TO_END(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
if (count < c)
c = count;
if (c <= 0) {
break;
}
memcpy(info->xmit.buf + info->xmit.head, buf, c);
info->xmit.head = ((info->xmit.head + c) & (SERIAL_XMIT_SIZE-1));
buf += c;
count -= c;
ret += c;
}
restore_flags(flags);
}
if (info->xmit.head != info->xmit.tail && !tty->stopped && !tty->hw_stopped)
{
#ifdef UARTPOLLING
cli();
count = ret;
do {
wait_for_xmitr(info);
/* Send the character out. */
if(info->line==0||info->line==1)
uart_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
/*else */
/*uart_out(info, EX_UART_TX, info->xmit.buf[info->xmit.tail]);*/
info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
info->state->icount.tx++;
if (info->xmit.head == info->xmit.tail)
break;
} while (--count > 0);
restore_flags(flags);
#else
enable_uart_tx_interrupt(info->line);
#endif
}
return ret;
}
static int rs_write_room(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
if (serial_paranoia_check(info, tty->device, "rs_write_room"))
return 0;
return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
static int rs_chars_in_buffer(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
return 0;
return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
}
static void rs_flush_buffer(struct tty_struct *tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
return;
save_flags(flags); cli();
info->xmit.head = info->xmit.tail = 0;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
#ifdef SERIAL_HAVE_POLL_WAIT
wake_up_interruptible(&tty->poll_wait);
#endif
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
}
/*
* 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 async_struct *info = (struct async_struct *)tty->driver_data;
if (serial_paranoia_check(info, tty->device, "rs_send_char"))
return;
info->x_char = ch;
if (ch) {
// Make sure transmit interrupts are on
enable_uart_tx_interrupt(info->line);
}
}
/*
* ------------------------------------------------------------
* 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)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
printk("throttle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->device, "rs_throttle"))
return;
if (I_IXOFF(tty))
rs_send_xchar(tty, STOP_CHAR(tty));
/*
if (tty->termios->c_cflag & CRTSCTS)
info->MCR &= ~UART_MCR_RTS;
*/
save_flags(flags); cli();
restore_flags(flags);
}
static void rs_unthrottle(struct tty_struct * tty)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
printk("unthrottle %s: %d....\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
return;
if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else
rs_send_xchar(tty, START_CHAR(tty));
}
save_flags(flags); cli();
restore_flags(flags);
}
/*
* ------------------------------------------------------------
* rs_ioctl() and friends
* ------------------------------------------------------------
*/
static int get_serial_info(struct async_struct * info,
struct serial_struct * retinfo)
{
struct serial_struct tmp;
struct serial_state *state = info->state;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = state->type;
tmp.line = state->line;
tmp.port = state->port;
if (HIGH_BITS_OFFSET)
tmp.port_high = state->port >> HIGH_BITS_OFFSET;
else
tmp.port_high = 0;
tmp.irq = state->irq;
tmp.flags = state->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.custom_divisor = state->custom_divisor;
tmp.hub6 = state->hub6;
tmp.io_type = state->io_type;
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
}
static int set_serial_info(struct async_struct * info,
struct serial_struct * new_info)
{
struct serial_struct new_serial;
struct serial_state old_state, *state;
unsigned int i,change_irq,change_port;
int retval = 0;
unsigned long new_port;
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
state = info->state;
old_state = *state;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -