📄 serial167.c
字号:
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; /*!!!*/ copy_to_user(retinfo,&tmp,sizeof(*retinfo)); return 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; copy_from_user(&new_serial,new_info,sizeof(new_serial)); 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); cy_put_user(result,(unsigned long *) value); return 0;} /* 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 = cy_get_user((unsigned long *) value); 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){ copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)); 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 value){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; 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; cy_put_user(tmp,value); return 0;}static intset_default_threshold(struct cyclades_port * info, unsigned long value){ info->default_threshold = value & 0x0f; return 0;}static intget_default_threshold(struct cyclades_port * info, unsigned long *value){ cy_put_user(info->default_threshold,value); return 0;}static intset_timeout(struct cyclades_port * info, unsigned long value){ volatile unsigned char *base_addr = (u_char *)BASE_ADDR; int channel; 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]; cy_put_user(tmp,value); return 0;}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){ cy_put_user(info->default_timeout,value); return 0;}static intcy_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ int error; 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: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(struct cyclades_monitor)); if (error){ ret_val = error; break; } ret_val = get_mon_info(info, (struct cyclades_monitor *)arg); break; case CYGETTHRESH: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); if (error){ ret_val = error; break; } ret_val = get_threshold(info, (unsigned long *)arg); break; case CYSETTHRESH: ret_val = set_threshold(info, (unsigned long)arg); break; case CYGETDEFTHRESH: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); if (error){ ret_val = error; break; } ret_val = get_default_threshold(info, (unsigned long *)arg); break; case CYSETDEFTHRESH: ret_val = set_default_threshold(info, (unsigned long)arg); break; case CYGETTIMEOUT: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); if (error){ ret_val = error; break; } ret_val = get_timeout(info, (unsigned long *)arg); break; case CYSETTIMEOUT: ret_val = set_timeout(info, (unsigned long)arg); break; case CYGETDEFTIMEOUT: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned long)); if (error){ ret_val = error; break; } 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) return ret_val; 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) return ret_val; 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: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned int *)); if (error){ ret_val = error; break; } cy_put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); break; case TIOCSSOFTCAR: error = verify_area(VERIFY_READ, (void *) arg ,sizeof(unsigned long *)); if (error){ ret_val = error; break; } arg = cy_get_user((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); break; case TIOCMGET: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(unsigned int *)); if (error){ ret_val = error; break; } ret_val = get_modem_info(info, (unsigned int *) arg); break; case TIOCGSERIAL: error = verify_area(VERIFY_WRITE, (void *) arg ,sizeof(struct serial_struct)); if (error){ ret_val = error; break; } 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -