📄 io_edgeport.c
字号:
} tty = port->tty; /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); status = edge_write (port, 0, &start_char, 1); if (status <= 0) { return; } } /* if we are implementing RTS/CTS, toggle that line */ if (tty->termios->c_cflag & CRTSCTS) { edge_port->shadowMCR |= MCR_RTS; status = send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); if (status != 0) { return; } } return;}/***************************************************************************** * SerialSetTermios * this function is called by the tty driver when it wants to change the termios structure *****************************************************************************/static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios){ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); struct tty_struct *tty = port->tty; unsigned int cflag = tty->termios->c_cflag; dbg(__FUNCTION__" - clfag %08x %08x iflag %08x %08x", tty->termios->c_cflag, old_termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag), RELEVANT_IFLAG(old_termios->c_iflag) ); /* check that they really want us to change something */ if (old_termios) { if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) { dbg(__FUNCTION__" - nothing to change"); return; } } dbg(__FUNCTION__" - port %d", port->number); if (edge_port == NULL) return; if (!edge_port->open) { dbg (__FUNCTION__" - port not opened"); return; } /* change the port settings to the new ones specified */ change_port_settings (edge_port, old_termios); return;}/***************************************************************************** * get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * is emptied. On bus types like RS485, the transmitter must * release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. *****************************************************************************/static int get_lsr_info(struct edgeport_port *edge_port, unsigned int *value){ unsigned int result = 0; if (edge_port->maxTxCredits == edge_port->txCredits && edge_port->txfifo.count == 0) { dbg(__FUNCTION__" -- Empty"); result = TIOCSER_TEMT; } if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0;}static int get_number_bytes_avail(struct edgeport_port *edge_port, unsigned int *value){ unsigned int result = 0; struct tty_struct *tty = edge_port->port->tty; result = tty->read_cnt; dbg(__FUNCTION__"(%d) = %d", edge_port->port->number, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; //return 0; return -ENOIOCTLCMD;}static int set_modem_info(struct edgeport_port *edge_port, unsigned int cmd, unsigned int *value){ unsigned int mcr = edge_port->shadowMCR; unsigned int arg; if (copy_from_user(&arg, value, sizeof(int))) return -EFAULT; switch (cmd) { case TIOCMBIS: if (arg & TIOCM_RTS) mcr |= MCR_RTS; if (arg & TIOCM_DTR) mcr |= MCR_RTS; if (arg & TIOCM_LOOP) mcr |= MCR_LOOPBACK; break; case TIOCMBIC: if (arg & TIOCM_RTS) mcr &= ~MCR_RTS; if (arg & TIOCM_DTR) mcr &= ~MCR_RTS; if (arg & TIOCM_LOOP) mcr &= ~MCR_LOOPBACK; break; case TIOCMSET: /* turn off the RTS and DTR and LOOPBACK * and then only turn on what was asked to */ mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK); mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0); mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0); mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0); break; } edge_port->shadowMCR = mcr; send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); return 0;}static int get_modem_info(struct edgeport_port *edge_port, unsigned int *value){ unsigned int result = 0; unsigned int msr = edge_port->shadowMSR; unsigned int mcr = edge_port->shadowMCR; result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ | ((msr & MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ | ((msr & MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ | ((msr & MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ | ((msr & MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ dbg(__FUNCTION__" -- %x", result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; return 0;}static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct * retinfo){ struct serial_struct tmp; if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; tmp.line = edge_port->port->serial->minor; tmp.port = edge_port->port->number; tmp.irq = 0; tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->maxTxCredits; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; tmp.closing_wait = 30*HZ;// tmp.custom_divisor = state->custom_divisor;// tmp.hub6 = state->hub6;// tmp.io_type = state->io_type; if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0;}/***************************************************************************** * SerialIoctl * this function handles any ioctl calls to the driver *****************************************************************************/static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg){ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); struct async_icount cnow; struct async_icount cprev; struct serial_icounter_struct icount; dbg(__FUNCTION__" - port %d, cmd = 0x%x", port->number, cmd); switch (cmd) { // return number of bytes available case TIOCINQ: dbg(__FUNCTION__" (%d) TIOCINQ", port->number); return get_number_bytes_avail(edge_port, (unsigned int *) arg); break; case TIOCSERGETLSR: dbg(__FUNCTION__" (%d) TIOCSERGETLSR", port->number); return get_lsr_info(edge_port, (unsigned int *) arg); return 0; case TIOCMBIS: case TIOCMBIC: case TIOCMSET: dbg(__FUNCTION__" (%d) TIOCMSET/TIOCMBIC/TIOCMSET", port->number); return set_modem_info(edge_port, cmd, (unsigned int *) arg); case TIOCMGET: dbg(__FUNCTION__" (%d) TIOCMGET", port->number); return get_modem_info(edge_port, (unsigned int *) arg); case TIOCGSERIAL: dbg(__FUNCTION__" (%d) TIOCGSERIAL", port->number); return get_serial_info(edge_port, (struct serial_struct *) arg); case TIOCSSERIAL: dbg(__FUNCTION__" (%d) TIOCSSERIAL", port->number); break; case TIOCMIWAIT: dbg(__FUNCTION__" (%d) TIOCMIWAIT", port->number); cprev = edge_port->icount; while (1) { interruptible_sleep_on(&edge_port->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; cnow = edge_port->icount; 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; case TIOCGICOUNT: cnow = edge_port->icount; icount.cts = cnow.cts; icount.dsr = cnow.dsr; icount.rng = cnow.rng; icount.dcd = cnow.dcd; icount.rx = cnow.rx; icount.tx = cnow.tx; icount.frame = cnow.frame; icount.overrun = cnow.overrun; icount.parity = cnow.parity; icount.brk = cnow.brk; icount.buf_overrun = cnow.buf_overrun; dbg(__FUNCTION__" (%d) TIOCGICOUNT RX=%d, TX=%d", port->number, icount.rx, icount.tx ); if (copy_to_user((void *)arg, &icount, sizeof(icount))) return -EFAULT; return 0; } return -ENOIOCTLCMD;}/***************************************************************************** * SerialBreak * this function sends a break to the port *****************************************************************************/static void edge_break (struct usb_serial_port *port, int break_state){ struct edgeport_port *edge_port = (struct edgeport_port *)(port->private); int status; /* flush and chase */ edge_port->chaseResponsePending = TRUE; dbg(__FUNCTION__" - Sending IOSP_CMD_CHASE_PORT"); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0); if (status == 0) { // block until chase finished block_until_chase_response(edge_port); } else { edge_port->chaseResponsePending = FALSE; } if (break_state == -1) { dbg(__FUNCTION__" - Sending IOSP_CMD_SET_BREAK"); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); } else { dbg(__FUNCTION__" - Sending IOSP_CMD_CLEAR_BREAK"); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); } if (status) { dbg(__FUNCTION__" - error sending break set/clear command."); } return;}/***************************************************************************** * process_rcvd_data * this function handles the data received on the bulk in pipe. *****************************************************************************/static int process_rcvd_data (struct edgeport_serial *edge_serial, unsigned char * buffer, __u16 bufferLength){ struct usb_serial_port *port; struct edgeport_port *edge_port; struct tty_struct *tty; __u16 lastBufferLength; __u16 rxLen; int i; dbg(__FUNCTION__); lastBufferLength = bufferLength + 1; while (bufferLength > 0) { /* failsafe incase we get a message that we don't understand */ if (lastBufferLength == bufferLength) { dbg(__FUNCTION__" - stuck in loop, exiting it."); break; } lastBufferLength = bufferLength; switch (edge_serial->rxState) { case EXPECT_HDR1: edge_serial->rxHeader1 = *buffer; ++buffer; --bufferLength; if (bufferLength == 0) { edge_serial->rxState = EXPECT_HDR2; break; } /* otherwise, drop on through */ case EXPECT_HDR2: edge_serial->rxHeader2 = *buffer; ++buffer; --bufferLength; dbg(__FUNCTION__" - Hdr1=%02X Hdr2=%02X", edge_serial->rxHeader1, edge_serial->rxHeader2); // Process depending on whether this header is // data or status if (IS_CMD_STAT_HDR(edge_serial->rxHeader1)) { // Decode this status header and goto EXPECT_HDR1 (if we // can process the status with only 2 bytes), or goto // EXPECT_HDR3 to get the third byte. edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1); edge_serial->rxStatusCode = IOSP_GET_STATUS_CODE(edge_serial->rxHeader1); if (!IOSP_STATUS_IS_2BYTE(edge_serial->rxStatusCode)) { // This status needs additional bytes. Save what we have // and then wait for more data. edge_serial->rxStatusParam = edge_serial->rxHeader2; edge_serial->rxState = EXPECT_HDR3; break; } // We have all the header bytes, process the status now process_rcvd_status (edge_serial, edge_serial->rxHeader2, 0); edge_serial->rxState = EXPECT_HDR1; break; } else { edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1); edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, edge_serial->rxHeader2); dbg(__FUNCTION__" - Data for Port %u Len
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -