📄 jpt_driver.c
字号:
}#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))static int nuart_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; int c, total = 0; unsigned long flags; if (!tty || !info->xmit_buf || !nuvar_tmp_buf) return (0); if (from_user) { down(&nuvar_tmp_buf_sem); while (1) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; c -= copy_from_user(nuvar_tmp_buf, buf, c); if (!c) { if (!total) total = -EFAULT; break; } spin_lock_irqsave(&info->lock, flags); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, nuvar_tmp_buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); info->xmit_cnt += c; spin_unlock_irqrestore(&info->lock, flags); buf += c; count -= c; total += c; } up(&nuvar_tmp_buf_sem); } else { spin_lock_irqsave(&info->lock, flags); while (1) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); info->xmit_cnt += c; buf += c; count -= c; total += c; } spin_unlock_irqrestore(&info->lock, flags); } return (total);}#elsestatic int nuart_write(struct tty_struct *tty, const unsigned char *buf, int count){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; int c, total = 0; unsigned long flags; if (!tty || !info->xmit_buf || !nuvar_tmp_buf) return (0); spin_lock_irqsave(&info->lock, flags); while (1) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) { break; } memcpy(info->xmit_buf + info->xmit_head, buf, c); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); info->xmit_cnt += c; buf += c; count -= c; total += c; } spin_unlock_irqrestore(&info->lock, flags); return (total);}#endifstatic void nuart_put_char(struct tty_struct *tty, unsigned char ch){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; unsigned long flags; if (!tty || !info->xmit_buf) return; spin_lock_irqsave(&info->lock, flags); if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { spin_unlock_irqrestore(&info->lock, flags); return; } info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; spin_unlock_irqrestore(&info->lock, flags);}static void nuart_flush_chars(struct tty_struct *tty){ return;}static int nuart_write_room(struct tty_struct *tty){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; int ret; ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; return (ret);}static int nuart_chars_in_buffer(struct tty_struct *tty){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; return (info->xmit_cnt);}static void nuart_flush_buffer(struct tty_struct *tty){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; unsigned long flags; spin_lock_irqsave(&info->lock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; spin_unlock_irqrestore(&info->lock, flags); wake_up_interruptible(&tty->write_wait); if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup) (tty);}static void nuart_send_break(struct nuart_struct *info, int duration){ unsigned long flags; if (!info->base) return; set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&info->lock, flags); nuart_break(info->base, &info->reg, 1); spin_unlock_irqrestore(&info->lock, flags); schedule_timeout(duration); spin_lock_irqsave(&info->lock, flags); nuart_break(info->base, &info->reg, 0); spin_unlock_irqrestore(&info->lock, flags);}static int nuart_tiocmget(struct tty_struct * tty, struct file * file){ struct nuart_struct * info = (struct nuart_struct *)tty->driver_data; unsigned long flags, status; if(PORTNO(tty) == NUART_PORTS) return (-ENOIOCTLCMD); if(tty->flags & (1 << TTY_IO_ERROR)) return (-EIO); spin_lock_irqsave(&info->lock, flags); status = nuart_get_stat(info->base); spin_unlock_irqrestore(&info->lock, flags); if((status & (NUART_RI | NUART_DSR | NUART_DCD | NUART_CTS)) != (info->reg.mpr & (NUART_RI | NUART_DSR | NUART_DCD | NUART_CTS))) nuart_check_modem_status(info, status); info->reg.mpr = status; return ((status & NUART_DCD) ? TIOCM_CAR : 0) | ((status & NUART_RI) ? TIOCM_RNG : 0) | ((status & NUART_DSR) ? TIOCM_DSR : 0) | ((status & NUART_CTS) ? TIOCM_CTS : 0) | ((info->reg.pcr & NUART_DTRC_HIGH) ? TIOCM_DTR : 0) | ((info->reg.pcr & NUART_RTSC_HIGH) ? TIOCM_RTS : 0);}static int nuart_tiocmset(struct tty_struct *tty, struct file * file, unsigned int set, unsigned int clear){ struct nuart_struct * info = (struct nuart_struct *)tty->driver_data; unsigned long flags; int dtr = 0, rts = 0; if(PORTNO(tty) == NUART_PORTS) return (-ENOIOCTLCMD); if(tty->flags & (1 << TTY_IO_ERROR)) return (-EIO); if(set & TIOCM_RTS) rts = 1; if(set & TIOCM_DTR) dtr = 1; if(clear & TIOCM_RTS) rts = 0; if(clear & TIOCM_DTR) dtr = 0; spin_lock_irqsave(&info->lock, flags); nuart_dtr(info->base, &info->reg, dtr); nuart_rts(info->base, &info->reg, rts); spin_unlock_irqrestore(&info->lock, flags); return (0);}static int nuart_get_serial_info(struct nuart_struct *info, struct serial_struct *retinfo){ struct serial_struct tmp; if (!retinfo) return (-EFAULT); memset(&tmp, 0, sizeof(tmp)); tmp.line = info->port; tmp.port = info->base; tmp.flags = info->flags; tmp.baud_base = info->baud_base; tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.hub6 = 0; return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;}static int nuart_set_serial_info(struct nuart_struct *info, struct serial_struct *new_info){ struct serial_struct new_serial; unsigned int flags; int retval = 0; if (!new_info || !info->base) return (-EFAULT); if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; if ((new_serial.port != info->base) || (new_serial.baud_base != info->baud_base)) return (-EPERM); flags = info->flags & ASYNC_SPD_MASK; if (!capable(CAP_SYS_ADMIN)) { if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) return (-EPERM); info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); } else { /* * OK, past this point, all the error checking has been done.
* At this point, we start making changes.....
*/ info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->close_delay = new_serial.close_delay * HZ / 100; info->closing_wait = new_serial.closing_wait * HZ / 100; } if (info->flags & ASYNC_INITIALIZED) { if (flags != (info->flags & ASYNC_SPD_MASK)) { nuart_change_speed(info, 0); } } else retval = nuart_startup(info); return (retval);}static int nuart_get_lsr_info(struct nuart_struct *info, unsigned int *value){ unsigned int result; unsigned long flags; spin_lock_irqsave(&info->lock, flags); info->reg.mpr = nuart_get_stat(info->base); spin_unlock_irqrestore(&info->lock, flags); result = ((info->reg.mpr & NUART_TBUSY) ? 0 : TIOCSER_TEMT); return put_user(result, value);}static int nuart_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ unsigned long flags; struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; int retval, ret; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ unsigned long templ; DECLARE_WAITQUEUE(wait, current); if (PORTNO(tty) == NUART_PORTS) return 0; if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return (-EIO); } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return (retval); tty_wait_until_sent(tty, 0); if (!arg) nuart_send_break(info, HZ / 4); /* 1/4 second */ return (0); case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return (retval); tty_wait_until_sent(tty, 0); nuart_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); return (0); case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); case TIOCSSOFTCAR: if(get_user(templ, (unsigned long *) arg)) return -EFAULT; arg = templ; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return (0);// case TIOCMGET:// return (nuart_get_modem_info(info, (unsigned int *) arg));// case TIOCMBIS:// case TIOCMBIC:// case TIOCMSET:// return (nuart_set_modem_info(info, cmd, (unsigned int *) arg)); case TIOCGSERIAL: return (nuart_get_serial_info(info, (struct serial_struct *) arg)); case TIOCSSERIAL: return (nuart_set_serial_info(info, (struct serial_struct *) arg)); case TIOCSERGETLSR: /* Get line status register */ return (nuart_get_lsr_info(info, (unsigned int *) arg)); /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: spin_lock_irqsave(&info->lock, flags); cprev = info->icount; spin_unlock_irqrestore(&info->lock, flags); add_wait_queue(&info->delta_msr_wait, &wait); while(1) { spin_lock_irqsave(&info->lock, flags); cnow = info->icount; spin_unlock_irqrestore(&info->lock, flags); set_current_state(TASK_INTERRUPTIBLE); if(cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { ret = -EIO; break; } if(((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { ret = 0; break; } schedule(); if(signal_pending(current)) { ret = -ERESTARTSYS; break; } cprev = cnow; } current->state=TASK_RUNNING; remove_wait_queue(&info->delta_msr_wait, &wait); return ret; /* NOT REACHED */ break; case TIOCGICOUNT: spin_lock_irqsave(&info->lock, flags); cnow = info->icount; spin_unlock_irqrestore(&info->lock, flags); p_cuser = (struct serial_icounter_struct *)arg; if(put_user(cnow.cts, &p_cuser->cts)) return -EFAULT; if(put_user(cnow.dsr, &p_cuser->dsr)) return -EFAULT; if(put_user(cnow.rng, &p_cuser->rng)) return -EFAULT; return put_user(cnow.dcd, &p_cuser->dcd); default: return (-ENOIOCTLCMD); } return (0);}static void nuart_throttle(struct tty_struct *tty){}static void nuart_unthrottle(struct tty_struct *tty){}static void nuart_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; if ((tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { nuart_change_speed(info, old_termios); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; nuart_start(tty); } }/* Handle sw stopped */ if ((old_termios->c_iflag & IXON) && !(tty->termios->c_iflag & IXON)) { tty->stopped = 0; nuart_start(tty); }}static void nuart_stop(struct tty_struct *tty){ struct nuart_struct * info = (struct nuart_struct *)tty->driver_data; if(info->xmit_cnt && info->xmit_buf) info->lflag &= ~NUART_LFLAG_THRI;}static void nuart_start(struct tty_struct *tty){ struct nuart_struct * info = (struct nuart_struct *)tty->driver_data; if(info->xmit_cnt && info->xmit_buf) info->lflag |= NUART_LFLAG_THRI;}void nuart_hangup(struct tty_struct *tty){ struct nuart_struct *info = (struct nuart_struct *) tty->driver_data; nuart_flush_buffer(tty); nuart_shutdown(info); info->count = 0; info->event = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait);}static void nuart_do_softint(void *private_){ struct nuart_struct *info = (struct nuart_struct *)private_; struct tty_struct *tty; tty = info->tty; if(tty) { if(test_and_clear_bit(NUART_EVENT_TXLOW, &info->event)) { if((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); } if(test_and_clear_bit(NUART_EVENT_HANGUP, &info->event)) tty_hangup(tty); }}module_init(nuart_module_init);module_exit(nuart_module_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -