天天看点

linux 串口驱动read,Linux串口驱动分析read

static ssize_t tty_read(struct file *file, char __user *buf, size_t count,

loff_t *ppos)

{

int i;

struct inode *inode = file->f_path.dentry->d_inode;

struct tty_struct *tty = file_tty(file);

struct tty_ldisc *ld;

if (tty_paranoia_check(tty, inode, "tty_read"))

return -EIO;

if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))

return -EIO;

ld = tty_ldisc_ref_wait(tty);

if (ld->ops->read)

i = (ld->ops->read)(tty, file, buf, count);

else

i = -EIO;

tty_ldisc_deref(ld);

if (i > 0)

inode->i_atime = current_fs_time(inode->i_sb);

return i;

}

static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,unsigned char __user *buf, size_t nr)

{

unsigned char __user *b = buf;

uncopied = copy_from_read_buf(tty, &b, &nr);

uncopied += copy_from_read_buf(tty, &b, &nr);

}

static int copy_from_read_buf(struct tty_struct *tty,unsigned char __user **b,size_t *nr)

{

if (n) {

retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n);

n -= retval;

tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n);

spin_lock_irqsave(&tty->read_lock, flags);

tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1);

tty->read_cnt -= n;

if (L_EXTPROC(tty) && tty->icanon && n == 1) {

if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty))

n--;

}

spin_unlock_irqrestore(&tty->read_lock, flags);

*b += n;

*nr -= n;

}

return retval;

}

static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)

{

struct s3c24xx_uart_port *ourport = dev_id;

struct uart_port *port = &ourport->port;

struct tty_struct *tty = port->state->port.tty;

unsigned int ufcon, ch, flag, ufstat, uerstat;

int max_count = 64;

while (max_count-- > 0) {

ufcon = rd_regl(port, S3C2410_UFCON);

ufstat = rd_regl(port, S3C2410_UFSTAT);

if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)

break;

uerstat = rd_regl(port, S3C2410_UERSTAT);

ch = rd_regb(port, S3C2410_URXH);

if (port->flags & UPF_CONS_FLOW) {

int txe = s3c24xx_serial_txempty_nofifo(port);

if (rx_enabled(port)) {

if (!txe) {

rx_enabled(port) = 0;

continue;

}

} else {

if (txe) {

ufcon |= S3C2410_UFCON_RESETRX;

wr_regl(port, S3C2410_UFCON, ufcon);

rx_enabled(port) = 1;

goto out;

}

continue;

}

}

flag = TTY_NORMAL;

port->icount.rx++;

if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {

dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",

ch, uerstat);

if (uerstat & S3C2410_UERSTAT_BREAK) {

dbg("break!\n");

port->icount.brk++;

if (uart_handle_break(port))

goto ignore_char;

}

if (uerstat & S3C2410_UERSTAT_FRAME)

port->icount.frame++;

if (uerstat & S3C2410_UERSTAT_OVERRUN)

port->icount.overrun++;

uerstat &= port->read_status_mask;

if (uerstat & S3C2410_UERSTAT_BREAK)

flag = TTY_BREAK;

else if (uerstat & S3C2410_UERSTAT_PARITY)

flag = TTY_PARITY;

else if (uerstat & (S3C2410_UERSTAT_FRAME |

S3C2410_UERSTAT_OVERRUN))

flag = TTY_FRAME;

}

if (uart_handle_sysrq_char(port, ch))

goto ignore_char;

uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN,

ch, flag);

}

tty_flip_buffer_push(tty);

}

static inline int tty_insert_flip_char(struct tty_struct *tty,unsigned char ch, char flag)

{

struct tty_buffer *tb = tty->buf.tail;

if (tb && tb->used < tb->size) {

tb->flag_buf_ptr[tb->used] = flag;

tb->char_buf_ptr[tb->used++] = ch;

return 1;

}

return tty_insert_flip_string_flags(tty, &ch, &flag, 1);

}

static void flush_to_ldisc(struct work_struct *work)

{

char_buf = head->char_buf_ptr + head->read;

flag_buf = head->flag_buf_ptr + head->read;

head->read += count;

spin_unlock_irqrestore(&tty->buf.lock, flags);

disc->ops->receive_buf(tty, char_buf,

flag_buf, count);

}

static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,char *fp, int count)

{

if (tty->real_raw) {

spin_lock_irqsave(&tty->read_lock, cpuflags);

i = min(N_TTY_BUF_SIZE - tty->read_cnt,

N_TTY_BUF_SIZE - tty->read_head);

i = min(count, i);

memcpy(tty->read_buf + tty->read_head, cp, i);

tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);

tty->read_cnt += i;

cp += i;

count -= i;

i = min(N_TTY_BUF_SIZE - tty->read_cnt,

N_TTY_BUF_SIZE - tty->read_head);

i = min(count, i);

memcpy(tty->read_buf + tty->read_head, cp, i);

tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);

tty->read_cnt += i;

spin_unlock_irqrestore(&tty->read_lock, cpuflags);

}

}