📄 serial167.c
字号:
struct serial_struct tmp;/* CP('g'); */ if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = info->type; tmp.line = info->line; tmp.port = info->line; tmp.irq = 0; tmp.flags = info->flags; tmp.baud_base = 0; /*!!!*/ tmp.close_delay = info->close_delay; tmp.custom_divisor = 0; /*!!!*/ tmp.hub6 = 0; /*!!!*/ return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;} /* get_serial_info */static intset_serial_info(struct cyclades_port * info, struct serial_struct * new_info){ struct serial_struct new_serial; struct cyclades_port old_info;/* CP('s'); */ if (!new_info) return -EFAULT; if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; old_info = *info; if (!suser()) { if ((new_serial.close_delay != info->close_delay) || ((new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->flags & ASYNC_FLAGS & ~ASYNC_USR_MASK))) return -EPERM; info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); goto check_and_exit; } /* * 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;check_and_exit: if (info->flags & ASYNC_INITIALIZED){ config_setup(info); return 0; }else{ return startup(info); }} /* set_serial_info */static intget_modem_info(struct cyclades_port * info, unsigned int *value){ int channel; volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; unsigned char status; unsigned int result; channel = info->line; save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel; status = base_addr[CyMSVR1] | base_addr[CyMSVR2]; restore_flags(flags); result = ((status & CyRTS) ? TIOCM_RTS : 0) | ((status & CyDTR) ? TIOCM_DTR : 0) | ((status & CyDCD) ? TIOCM_CAR : 0) | ((status & CyDSR) ? TIOCM_DSR : 0) | ((status & CyCTS) ? TIOCM_CTS : 0); return put_user(result,(unsigned int *) value);} /* get_modem_info */static intset_modem_info(struct cyclades_port * info, unsigned int cmd, unsigned int *value){ int channel; volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long flags; unsigned int arg; if (get_user(arg, (unsigned long *) value)) return -EFAULT; channel = info->line; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS){ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; restore_flags(flags); } if (arg & TIOCM_DTR){ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel;/* CP('S');CP('2'); */ base_addr[CyMSVR2] = CyDTR;#ifdef SERIAL_DEBUG_DTR printk("cyc: %d: raising DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif restore_flags(flags); } break; case TIOCMBIC: if (arg & TIOCM_RTS){ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = 0; restore_flags(flags); } if (arg & TIOCM_DTR){ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel;/* CP('C');CP('2'); */ base_addr[CyMSVR2] = 0;#ifdef SERIAL_DEBUG_DTR printk("cyc: %d: dropping DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif restore_flags(flags); } break; case TIOCMSET: if (arg & TIOCM_RTS){ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = CyRTS; restore_flags(flags); }else{ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel; base_addr[CyMSVR1] = 0; restore_flags(flags); } if (arg & TIOCM_DTR){ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel;/* CP('S');CP('3'); */ base_addr[CyMSVR2] = CyDTR;#ifdef SERIAL_DEBUG_DTR printk("cyc: %d: raising DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif restore_flags(flags); }else{ save_flags(flags); cli(); base_addr[CyCAR] = (u_char)channel;/* CP('C');CP('3'); */ base_addr[CyMSVR2] = 0;#ifdef SERIAL_DEBUG_DTR printk("cyc: %d: dropping DTR\n", __LINE__); printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]);#endif restore_flags(flags); } break; default: return -EINVAL; } return 0;} /* set_modem_info */static voidsend_break( struct cyclades_port * info, int duration){ /* Let the transmit ISR take care of this (since it requires stuffing characters into the output stream). */ info->x_break = duration; if (!info->xmit_cnt ) { start_xmit(info); }} /* send_break */static intget_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon){ if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) return -EFAULT; info->mon.int_count = 0; info->mon.char_count = 0; info->mon.char_max = 0; info->mon.char_last = 0; return 0;}static intset_threshold(struct cyclades_port * info, unsigned long *arg){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; unsigned long value; int channel; if (get_user(value, arg)) return -EFAULT; channel = info->line; info->cor4 &= ~CyREC_FIFO; info->cor4 |= value & CyREC_FIFO; base_addr[CyCOR4] = info->cor4; return 0;}static intget_threshold(struct cyclades_port * info, unsigned long *value){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; unsigned long tmp; channel = info->line; tmp = base_addr[CyCOR4] & CyREC_FIFO; return put_user(tmp,value);}static intset_default_threshold(struct cyclades_port * info, unsigned long *arg){ unsigned long value; if (get_user(value, arg)) return -EFAULT; info->default_threshold = value & 0x0f; return 0;}static intget_default_threshold(struct cyclades_port * info, unsigned long *value){ return put_user(info->default_threshold,value);}static intset_timeout(struct cyclades_port * info, unsigned long *arg){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; unsigned long value; if (get_user(value, arg)) return -EFAULT; channel = info->line; base_addr[CyRTPRL] = value & 0xff; base_addr[CyRTPRH] = (value >> 8) & 0xff; return 0;}static intget_timeout(struct cyclades_port * info, unsigned long *value){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; unsigned long tmp; channel = info->line; tmp = base_addr[CyRTPRL]; return put_user(tmp,value);}static intset_default_timeout(struct cyclades_port * info, unsigned long value){ info->default_timeout = value & 0xff; return 0;}static intget_default_timeout(struct cyclades_port * info, unsigned long *value){ return put_user(info->default_timeout,value);}static intcy_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ unsigned long val; struct cyclades_port * info = (struct cyclades_port *)tty->driver_data; int ret_val = 0;#ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl ttyS%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */#endif switch (cmd) { case CYGETMON: ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); break; case CYGETTHRESH: ret_val = get_threshold(info, (unsigned long *)arg); break; case CYSETTHRESH: ret_val = set_threshold(info, (unsigned long *)arg); break; case CYGETDEFTHRESH: ret_val = get_default_threshold(info, (unsigned long *)arg); break; case CYSETDEFTHRESH: ret_val = set_default_threshold(info, (unsigned long *)arg); break; case CYGETTIMEOUT: ret_val = get_timeout(info, (unsigned long *)arg); break; case CYSETTIMEOUT: ret_val = set_timeout(info, (unsigned long *)arg); break; case CYGETDEFTIMEOUT: ret_val = get_default_timeout(info, (unsigned long *)arg); break; case CYSETDEFTIMEOUT: ret_val = set_default_timeout(info, (unsigned long)arg); break; case TCSBRK: /* SVID version: non-zero arg --> no break */ ret_val = tty_check_change(tty); if (ret_val) break; tty_wait_until_sent(tty,0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ break; case TCSBRKP: /* support for POSIX tcsendbreak() */ ret_val = tty_check_change(tty); if (ret_val) break; tty_wait_until_sent(tty,0); send_break(info, arg ? arg*(HZ/10) : HZ/4); break; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: ret_val = set_modem_info(info, cmd, (unsigned int *) arg); break;/* The following commands are incompletely implemented!!! */ case TIOCGSOFTCAR: ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); break; case TIOCSSOFTCAR: ret_val = get_user(val, (unsigned long *) arg); if (ret_val) break; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); break; case TIOCMGET: ret_val = get_modem_info(info, (unsigned int *) arg); break; case TIOCGSERIAL: ret_val = get_serial_info(info, (struct serial_struct *) arg); break; case TIOCSSERIAL: ret_val = set_serial_info(info, (struct serial_struct *) arg); break; default: ret_val = -ENOIOCTLCMD; }#ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl done\n");#endif return ret_val;} /* cy_ioctl */static voidcy_set_termios(struct tty_struct *tty, struct termios * old_termios){ struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;#ifdef SERIAL_DEBUG_OTHER printk("cy_set_termios ttyS%d\n", info->line);#endif if (tty->termios->c_cflag == old_termios->c_cflag) return; config_setup(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->stopped = 0; cy_start(tty); }#ifdef tytso_patch_94Nov25_1726 if (!(old_termios->c_cflag & CLOCAL) && (tty->termios->c_cflag & CLOCAL)) wake_up_interruptible(&info->open_wait);#endif return;} /* cy_set_termios */static voidcy_close(struct tty_struct * tty, struct file * filp){ struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;/* CP('C'); */#ifdef SERIAL_DEBUG_OTHER printk("cy_close ttyS%d\n", info->line);#endif if (!info || serial_paranoia_check(info, tty->device, "cy_close")){ return; }#ifdef SERIAL_DEBUG_OPEN printk("cy_close ttyS%d, count = %d\n", info->line, info->count);#endif if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("cy_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; }#ifdef SERIAL_DEBUG_COUNT printk("cyc: %d: decrementing count to %d\n", __LINE__, info->count - 1);#endif if (--info->count < 0) { printk("cy_close: bad serial port count for ttys%d: %d\n", info->line, info->count);#ifdef SERIAL_DEBUG_COUNT printk("cyc: %d: setting count to 0\n", __LINE__);#endif info->count = 0; } if (info->count) return; info->flags |= ASYNC_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; if (info->flags & ASYNC_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; if (info->flags & ASYNC_INITIALIZED) tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ shutdown(info); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -