📄 io_edgeport.c
字号:
if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) { dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits ); goto exit_send; } // lock this write edge_port->write_in_progress = TRUE; // get a pointer to the write_urb urb = edge_port->write_urb; /* make sure transfer buffer is freed */ kfree(urb->transfer_buffer); urb->transfer_buffer = NULL; /* build the data header for the buffer and port that we are about to send out */ count = fifo->count; buffer = kmalloc (count+2, GFP_ATOMIC); if (buffer == NULL) { dev_err(&edge_port->port->dev, "%s - no more kernel memory...\n", __FUNCTION__); edge_port->write_in_progress = FALSE; goto exit_send; } buffer[0] = IOSP_BUILD_DATA_HDR1 (edge_port->port->number - edge_port->port->serial->minor, count); buffer[1] = IOSP_BUILD_DATA_HDR2 (edge_port->port->number - edge_port->port->serial->minor, count); /* now copy our data */ bytesleft = fifo->size - fifo->tail; firsthalf = min (bytesleft, count); memcpy(&buffer[2], &fifo->fifo[fifo->tail], firsthalf); fifo->tail += firsthalf; fifo->count -= firsthalf; if (fifo->tail == fifo->size) { fifo->tail = 0; } secondhalf = count-firsthalf; if (secondhalf) { memcpy(&buffer[2+firsthalf], &fifo->fifo[fifo->tail], secondhalf); fifo->tail += secondhalf; fifo->count -= secondhalf; } if (count) usb_serial_debug_data(debug, &edge_port->port->dev, __FUNCTION__, count, &buffer[2]); /* fill up the urb with all of our data and submit it */ usb_fill_bulk_urb (urb, edge_serial->serial->dev, usb_sndbulkpipe(edge_serial->serial->dev, edge_serial->bulk_out_endpoint), buffer, count+2, edge_bulk_out_data_callback, edge_port); /* decrement the number of credits we have by the number we just sent */ edge_port->txCredits -= count; edge_port->icount.tx += count; urb->dev = edge_serial->serial->dev; status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { /* something went wrong */ dev_err(&edge_port->port->dev, "%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n", __FUNCTION__, status); edge_port->write_in_progress = FALSE; /* revert the credits as something bad happened. */ edge_port->txCredits += count; edge_port->icount.tx -= count; } dbg("%s wrote %d byte(s) TxCredit %d, Fifo %d", __FUNCTION__, count, edge_port->txCredits, fifo->count);exit_send: spin_unlock_irqrestore(&edge_port->ep_lock, flags);}/***************************************************************************** * edge_write_room * this function is called by the tty driver when it wants to know how many * bytes of data we can accept for a specific port. * If successful, we return the amount of room that we have for this port * (the txCredits), * Otherwise we return a negative error number. *****************************************************************************/static int edge_write_room (struct usb_serial_port *port){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); int room; unsigned long flags; dbg("%s", __FUNCTION__); if (edge_port == NULL) return -ENODEV; if (edge_port->closePending == TRUE) return -ENODEV; dbg("%s - port %d", __FUNCTION__, port->number); if (!edge_port->open) { dbg("%s - port not opened", __FUNCTION__); return -EINVAL; } // total of both buffers is still txCredit spin_lock_irqsave(&edge_port->ep_lock, flags); room = edge_port->txCredits - edge_port->txfifo.count; spin_unlock_irqrestore(&edge_port->ep_lock, flags); dbg("%s - returns %d", __FUNCTION__, room); return room;}/***************************************************************************** * edge_chars_in_buffer * this function is called by the tty driver when it wants to know how many * bytes of data we currently have outstanding in the port (data that has * been written, but hasn't made it out the port yet) * If successful, we return the number of bytes left to be written in the * system, * Otherwise we return a negative error number. *****************************************************************************/static int edge_chars_in_buffer (struct usb_serial_port *port){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); int num_chars; unsigned long flags; dbg("%s", __FUNCTION__); if (edge_port == NULL) return -ENODEV; if (edge_port->closePending == TRUE) return -ENODEV; if (!edge_port->open) { dbg("%s - port not opened", __FUNCTION__); return -EINVAL; } spin_lock_irqsave(&edge_port->ep_lock, flags); num_chars = edge_port->maxTxCredits - edge_port->txCredits + edge_port->txfifo.count; spin_unlock_irqrestore(&edge_port->ep_lock, flags); if (num_chars) { dbg("%s(port %d) - returns %d", __FUNCTION__, port->number, num_chars); } return num_chars;}/***************************************************************************** * SerialThrottle * this function is called by the tty driver when it wants to stop the data * being read from the port. *****************************************************************************/static void edge_throttle (struct usb_serial_port *port){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty; int status; dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; if (!edge_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } tty = port->tty; if (!tty) { dbg ("%s - no tty available", __FUNCTION__); return; } /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); status = edge_write (port, &stop_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;}/***************************************************************************** * edge_unthrottle * this function is called by the tty driver when it wants to resume the data * being read from the port (called after SerialThrottle is called) *****************************************************************************/static void edge_unthrottle (struct usb_serial_port *port){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty; int status; dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; if (!edge_port->open) { dbg("%s - port not opened", __FUNCTION__); return; } tty = port->tty; if (!tty) { dbg ("%s - no tty available", __FUNCTION__); return; } /* 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, &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 = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; unsigned int cflag; if (!port->tty || !port->tty->termios) { dbg ("%s - no tty or termios", __FUNCTION__); return; } cflag = tty->termios->c_cflag; /* check that they really want us to change something */ if (old_termios) { if (cflag == old_termios->c_cflag && tty->termios->c_iflag == old_termios->c_iflag) { dbg("%s - nothing to change", __FUNCTION__); return; } } dbg("%s - clfag %08x iflag %08x", __FUNCTION__, tty->termios->c_cflag, tty->termios->c_iflag); if (old_termios) { dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, old_termios->c_cflag, old_termios->c_iflag); } dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return; if (!edge_port->open) { dbg("%s - port not opened", __FUNCTION__); 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 __user *value){ unsigned int result = 0; unsigned long flags; spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->maxTxCredits == edge_port->txCredits && edge_port->txfifo.count == 0) { dbg("%s -- Empty", __FUNCTION__); result = TIOCSER_TEMT; } spin_unlock_irqrestore(&edge_port->ep_lock, flags); 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 __user *value){ unsigned int result = 0; struct tty_struct *tty = edge_port->port->tty; if (!tty) return -ENOIOCTLCMD; result = tty->read_cnt; dbg("%s(%d) = %d", __FUNCTION__, edge_port->port->number, result); if (copy_to_user(value, &result, sizeof(int))) return -EFAULT; //return 0; return -ENOIOCTLCMD;}static int edge_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int mcr; dbg("%s - port %d", __FUNCTION__, port->number); mcr = edge_port->shadowMCR; if (set & TIOCM_RTS) mcr |= MCR_RTS; if (set & TIOCM_DTR) mcr |= MCR_DTR; if (set & TIOCM_LOOP) mcr |= MCR_LOOPBACK; if (clear & TIOCM_RTS) mcr &= ~MCR_RTS; if (clear & TIOCM_DTR) mcr &= ~MCR_DTR; if (clear & TIOCM_LOOP) mcr &= ~MCR_LOOPBACK; edge_port->shadowMCR = mcr; send_cmd_write_uart_register(edge_port, MCR, edge_port->shadowMCR); return 0;}static int edge_tiocmget(struct usb_serial_port *port, struct file *file){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); unsigned int result = 0; unsigned int msr; unsigned int mcr; dbg("%s - port %d", __FUNCTION__, port->number); msr = edge_port->shadowMSR; mcr = edge_port->shadowMCR; result = ((mcr & MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ | ((mcr & MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ | ((msr & EDGEPORT_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ | ((msr & EDGEPORT_MSR_CD) ? TIOCM_CAR: 0) /* 0x040 */ | ((msr & EDGEPORT_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ | ((msr & EDGEPORT_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ dbg("%s -- %x", __FUNCTION__, result); return result;}static int get_serial_info(struct edgeport_port *edge_port, struct serial_struct __user *retinfo)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -