📄 io_edgeport.c
字号:
{ 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){ DEFINE_WAIT(wait); struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct async_icount cnow; struct async_icount cprev; struct serial_icounter_struct icount; dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { // return number of bytes available case TIOCINQ: dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); return get_number_bytes_avail(edge_port, (unsigned int __user *) arg); break; case TIOCSERGETLSR: dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); return get_lsr_info(edge_port, (unsigned int __user *) arg); return 0; case TIOCGSERIAL: dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); return get_serial_info(edge_port, (struct serial_struct __user *) arg); case TIOCSSERIAL: dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); break; case TIOCMIWAIT: dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); cprev = edge_port->icount; while (1) { prepare_to_wait(&edge_port->delta_msr_wait, &wait, TASK_INTERRUPTIBLE); schedule(); finish_wait(&edge_port->delta_msr_wait, &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; memset(&icount, 0, sizeof(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("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, port->number, icount.rx, icount.tx ); if (copy_to_user((void __user *)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 = usb_get_serial_port_data(port); int status; /* flush and chase */ edge_port->chaseResponsePending = TRUE; dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__); 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("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0); } else { dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__); status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0); } if (status) { dbg("%s - error sending break set/clear command.", __FUNCTION__); } return;}/***************************************************************************** * process_rcvd_data * this function handles the data received on the bulk in pipe. *****************************************************************************/static void 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; dbg("%s", __FUNCTION__); lastBufferLength = bufferLength + 1; while (bufferLength > 0) { /* failsafe incase we get a message that we don't understand */ if (lastBufferLength == bufferLength) { dbg("%s - stuck in loop, exiting it.", __FUNCTION__); 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("%s - Hdr1=%02X Hdr2=%02X", __FUNCTION__, 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("%s - Data for Port %u Len %u", __FUNCTION__, edge_serial->rxPort, edge_serial->rxBytesRemaining); //ASSERT( DevExt->RxPort < DevExt->NumPorts ); //ASSERT( DevExt->RxBytesRemaining < IOSP_MAX_DATA_LENGTH ); if (bufferLength == 0 ) { edge_serial->rxState = EXPECT_DATA; break; } // Else, drop through } case EXPECT_DATA: // Expect data if (bufferLength < edge_serial->rxBytesRemaining) { rxLen = bufferLength; edge_serial->rxState = EXPECT_DATA; // Expect data to start next buffer } else { // BufLen >= RxBytesRemaining rxLen = edge_serial->rxBytesRemaining; edge_serial->rxState = EXPECT_HDR1; // Start another header next time } bufferLength -= rxLen; edge_serial->rxBytesRemaining -= rxLen; /* spit this data back into the tty driver if this port is open */ if (rxLen) { port = edge_serial->serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port->open) { tty = edge_port->port->tty; if (tty) { dbg("%s - Sending %d bytes to TTY for port %d", __FUNCTION__, rxLen, edge_serial->rxPort); edge_tty_recv(&edge_serial->serial->dev->dev, tty, buffer, rxLen); } edge_port->icount.rx += rxLen; } buffer += rxLen; } break; case EXPECT_HDR3: // Expect 3rd byte of status header edge_serial->rxHeader3 = *buffer; ++buffer; --bufferLength; // We have all the header bytes, process the status now process_rcvd_status (edge_serial, edge_serial->rxStatusParam, edge_serial->rxHeader3); edge_serial->rxState = EXPECT_HDR1; break; } }}/***************************************************************************** * process_rcvd_status * this function handles the any status messages received on the bulk in pipe. *****************************************************************************/static void process_rcvd_status (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3){ struct usb_serial_port *port; struct edgeport_port *edge_port; __u8 code = edge_serial->rxStatusCode; /* switch the port pointer to the one being currently talked about */ port = edge_serial->serial->port[edge_serial->rxPort]; edge_port = usb_get_serial_port_data(port); if (edge_port == NULL) { dev_err(&edge_serial->serial->dev->dev, "%s - edge_port == NULL for port %d\n", __FUNCTION__, edge_serial->rxPort); return; } dbg("%s - port %d", __FUNCTION__, edge_serial->rxPort); if (code == IOSP_EXT_STATUS) { switch (byte2) { case IOSP_EXT_STATUS_CHASE_RSP: // we want to do EXT status regardless of port open/closed dbg("%s - Port %u EXT CHASE_RSP Data = %02x", __FUNCTION__, edge_serial->rxPort, byte3 ); // Currently, the only EXT_STATUS is Chase, so process here instead of one more call // to one more subroutine. If/when more EXT_STATUS, there'll be more work to do. // Also, we currently clear flag and close the port regardless of content of above's Byte3. // We could choose to do something else when Byte3 says Timeout on Chase from Edgeport, // like wait longer in block_until_chase_response, but for now we don't. edge_port->chaseResponsePending = FALSE; wake_up (&edge_port->wait_chase); return; case IOSP_EXT_STATUS_RX_CHECK_RSP: dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __FUNCTION__, edge_serial->rxPort, byte3 ); //Port->RxCheckRsp = TRUE; return; } } if (code == IOSP_STATUS_OPEN_RSP) { edge_port->txCredits = GET_TX_BUFFER_SIZE(byte3); edge_port->maxTxCredits = edge_port->txCredits; dbg("%s - Port %u Open Response Inital MSR = %02x TxBufferSize = %d", __FUNCTION__, edge_serial->rxPort, byte2, edge_port->txCredits); handle_new_msr (edge_port, byte2); /* send the current line settings to the port so we are in sync with any further termios calls */ if (edge_port->port->tty) change_port_settings (edge_port, edge_port->port->tty->termios); /* we have completed the open */ edge_port->openPending = FALSE; edge_port->open = TRUE; wake_up(&edge_port->wait_open); return; } // If port is closed, silently discard all rcvd status. We can // have cases where buffered status is received AFTER the close // port command is sent to the Edgeport. if ((!edge_port->open ) || (edge_port->closePending)) { return; } switch (code) { // Not currently sent by Edgeport case IOSP_STATUS_LSR: dbg("%s - Port %u LSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2); handle_new_lsr (edge_port, FALSE, byte2, 0); break; case IOSP_STATUS_LSR_DATA: dbg("%s - Port %u LSR Status = %02x, Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3); // byte2 is LSR Register // byte3 is broken data byte handle_new_lsr (edge_port, TRUE, byte2, byte3); break; // // case IOSP_EXT_4_STATUS: // dbg("%s - Port %u LSR Status = %02x Data = %02x", __FUNCTION__, edge_serial->rxPort, byte2, byte3); // break; // case IOSP_STATUS_MSR: dbg("%s - Port %u MSR Status = %02x", __FUNCTION__, edge_serial->rxPort, byte2); // Process this new modem status and generate appropriate // events, etc, based on the new status. This routine // also saves the MSR in Port->ShadowMsr. handle_new_msr(edge_port, byte2); break; default: dbg("%s - Unrecognized IOSP status code %u\n", __FUNCTION__, code); break; } return;}/***************************************************************************** * edge_tty_recv * this function passes data on to the tty flip buffer *****************************************************************************/static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned char *data, int length){ int cnt; do { if (tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); if (tty->flip.count >= TTY_FLIPBUF_SIZE) { dev_err(dev, "%s - dropping data, %d bytes lost\n", __FUNCTION__, length); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -