📄 8253xtty.c
字号:
else { LOWER(port,dtr); } break; default: restore_flags(flags); return -EINVAL; } restore_flags(flags); return 0;}/* * This routine sends a break character out the serial port. */static void sab8253x_break(struct tty_struct *tty, int break_state){ struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long flags; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_break")) { return; } if (!port->regs) { return; } save_flags(flags); cli(); if (break_state == -1) { SET_REG_BIT(port,dafo,SAB82532_DAFO_XBRK); } else { CLEAR_REG_BIT(port,dafo,SAB82532_DAFO_XBRK); } restore_flags(flags);}static int sab8253x_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ int error; unsigned int wordindex; unsigned short *wordptr; struct sab_port *port = (struct sab_port *)tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ SAB_BOARD *bptr; unsigned long flags; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_ioctl")) { return -ENODEV; } if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) { return -EIO; } } switch (cmd) { case ATIS_IOCSPARAMS: copy_from_user(&port->ccontrol, (struct channelcontrol*)arg , sizeof(struct channelcontrol)); break; case ATIS_IOCGPARAMS: copy_to_user((struct channelcontrol*) arg, &port->ccontrol, sizeof(struct channelcontrol)); break; case ATIS_IOCSSPEED: copy_from_user(&port->custspeed, (unsigned long*)arg , sizeof(unsigned long)); break; case ATIS_IOCGSPEED: copy_to_user((unsigned long*) arg, &port->custspeed, sizeof(unsigned long)); break; case ATIS_IOCSSEP9050: bptr = port->board; if(bptr->b_type == BD_WANMCS) { return -EINVAL; } copy_from_user((unsigned char*) bptr->b_eprom, (unsigned char*) arg , sizeof(struct sep9050)); wordptr = (unsigned short*) bptr->b_eprom; plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, NM93_WENCMD, NM93_WENADDR, 0); for(wordindex = 0; wordindex < EPROM9050_SIZE; ++wordindex) { plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, NM93_WRITECMD, wordindex, wordptr[wordindex]); } plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, NM93_WDSCMD, NM93_WDSADDR, 0); break; case ATIS_IOCGSEP9050: bptr = port->board; if(bptr->b_type == BD_WANMCS) { return -EINVAL; } if (!plx9050_eprom_read(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl, (unsigned short*) bptr->b_eprom, (unsigned char) 0, EPROM9050_SIZE)) { printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n"); return -EIO; } copy_to_user((unsigned char*) arg, (unsigned char*) bptr->b_eprom, sizeof(struct sep9050)); break; case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); case TIOCSSOFTCAR: error = get_user(arg, (unsigned int *) arg); if (error) { return error; } tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: return sab8253x_get_modem_info(port, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return sab8253x_set_modem_info(port, cmd, (unsigned int *) arg); case TIOCGSERIAL: return sab8253x_get_serial_info(port, (struct serial_struct *) arg); case TIOCSSERIAL: return sab8253x_set_serial_info(port, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ return sab8253x_get_lsr_info(port, (unsigned int *) arg); case TIOCSERGSTRUCT: if (copy_to_user((struct sab_port *) arg, port, sizeof(struct sab_port))) return -EFAULT; return 0; /* * 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: save_flags(flags); cli(); /* note the counters on entry */ cprev = port->icount; restore_flags(flags); while (1) { interruptible_sleep_on(&port->delta_msr_wait); /* waits for a modem signal change */ /* see if a signal did it */ if (signal_pending(current)) { return -ERESTARTSYS; } save_flags(flags); cli(); cnow = port->icount; /* atomic copy */ restore_flags(flags); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { return -EIO; /* no change => error */ } 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)) ) { { return 0; } } cprev = cnow; } /* NOTREACHED */ break; /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ case TIOCGICOUNT: save_flags(flags); cli(); cnow = port->icount; restore_flags(flags); p_cuser = (struct serial_icounter_struct *) arg; error = put_user(cnow.cts, &p_cuser->cts); if (error) { return error; } error = put_user(cnow.dsr, &p_cuser->dsr); if (error) { return error; } error = put_user(cnow.rng, &p_cuser->rng); if (error) { return error; } error = put_user(cnow.dcd, &p_cuser->dcd); if (error) { return error; } return 0; case ATIS_IOCSSIGMODE: if(port->chip->c_cim) { if(port->chip->c_cim->ci_type == CIM_SP502) { copy_from_user(&port->sigmode, (unsigned int*)arg , sizeof(unsigned int)); return 0; } } return -EINVAL; case ATIS_IOCGSIGMODE: if(port->chip->c_cim) { if(port->chip->c_cim->ci_type == CIM_SP502) { copy_to_user((unsigned int*) arg, &port->sigmode, sizeof(unsigned int)); return 0; } } return -EINVAL; default: return -ENOIOCTLCMD; } return 0;}static void sab8253x_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct sab_port *port = (struct sab_port *)tty->driver_data; if((tty->termios->c_cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { return; } if(!port) { return; } sab8253x_change_speed(port); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { LOWER(port,rts); LOWER(port,dtr); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { RAISE(port, dtr); if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) { RAISE(port, rts); } } /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; sab8253x_start(tty); }}/* * ------------------------------------------------------------ * sab8253x_close() * * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void sab8253x_close(struct tty_struct *tty, struct file * filp){ struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long flags; MOD_DEC_USE_COUNT; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_close")) { return; } if(port->open_type == OPEN_SYNC_NET) { /* port->tty field should already be NULL */ /* port count was not incremented */ return; } --(port->count); /* have a valid port */ if (tty_hung_up_p(filp)) { if(port->count == 0) /* shutdown took place in hangup context */ { port->open_type = OPEN_NOT; } else if(port->count < 0) { printk(KERN_ALERT "XX20: port->count went negative.\n"); port->count = 0; port->open_type = OPEN_NOT; } return; } if (port->count < 0) { printk(KERN_ALERT "sab8253x_close: bad serial port count for ttys%d: %d\n", port->line, port->count); port->count = 0; } if (port->count) { return; } port->flags |= FLAG8253X_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (port->flags & FLAG8253X_NORMAL_ACTIVE) { port->normal_termios = *tty->termios; } if (port->flags & FLAG8253X_CALLOUT_ACTIVE) { port->callout_termios = *tty->termios; } /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; if (port->closing_wait != SAB8253X_CLOSING_WAIT_NONE) { tty_wait_until_sent(tty, port->closing_wait); /* wait for drain */ } /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and turn off * the receiver. */ save_flags(flags); cli(); port->interrupt_mask0 |= SAB82532_IMR0_TCD; WRITEB(port,imr0,port->interrupt_mask0); CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); /* ??????? */ restore_flags(flags); if (port->flags & FLAG8253X_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ sab8253x_wait_until_sent(tty, port->timeout); } sab8253x_shutdown(port); /* no more ints on port */ Sab8253xCleanUpTransceiveN(port); /* should be okay */ if (tty->driver.flush_buffer) { tty->driver.flush_buffer(tty); } if (tty->ldisc.flush_buffer) { tty->ldisc.flush_buffer(tty); } tty->closing = 0; port->event = 0; port->tty = 0; if (port->blocked_open) { if (port->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); /* deal with open blocks */ } if((port->flags & (FLAG8253X_CALLOUT_ACTIVE | FLAG8253X_NETWORK)) == (FLAG8253X_CALLOUT_ACTIVE | FLAG8253X_NETWORK) && port->dev) { port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| FLAG8253X_CLOSING); /* leave network set */ netif_carrier_off(port->dev); port->open_type = OPEN_SYNC_NET; sab8253x_startupN(port); } else { port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| FLAG8253X_CLOSING); wake_up_interruptible(&port->close_wait); port->open_type = OPEN_NOT; }}/* * sab8253x_hangup() --- called by tty_hangup() when a hangup is signaled. */static void sab8253x_hangup(struct tty_struct *tty){ struct sab_port *port = (struct sab_port *)tty->driver_data; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_hangup")) { return; } #ifdef XCONFIG_SERIAL_CONSOLE if (port->is_console) { return; }#endif sab8253x_flush_buffer(tty); if(port) { sab8253x_shutdown(port); Sab8253xCleanUpTransceiveN(port); /* this logic is a bit contorted Are we cleaning up the lists because we are waking up a blocked open? There is possibly an order problem here perhaps the open count should have increased in the int handler so that it could decrease here*/ port->event = 0; port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE); port->tty = 0; wake_up_interruptible(&port->open_wait); /* deal with blocking open */ }}/* * ------------------------------------------------------------ * sab8253x_open() and friends * ------------------------------------------------------------ *//* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */static int sab8253x_open(struct tty_struct *tty, struct file * filp){ struct sab_port *port; int retval, line; int counter; unsigned long flags; MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; for(counter = 0, port = AuraPortRoot; (counter < line) && (port != NULL); ++counter) { port = port->next; } if (!port) { printk(KERN_ALERT "sab8253x_open: can't find structure for line %d\n", line); return -ENODEV; } save_flags(flags); /* Need to protect the port->tty field */ cli(); if(port->tty == NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -