📄 io_edgeport.c
字号:
__u32 lastCount; int timeout = HZ/10; int wait = 30; while (1) { // Save Last count lastCount = fifo->count; // Is the Edgeport Buffer empty? if (lastCount == 0) { dbg("%s - TX Buffer Empty", __FUNCTION__); return; } // Block the thread for a while interruptible_sleep_on_timeout (&edge_port->wait_chase, timeout); dbg("%s wait", __FUNCTION__); if (lastCount == fifo->count) { // No activity.. count down. wait--; if (wait == 0) { dbg("%s - TIMEOUT", __FUNCTION__); return; } } else { // Reset timout value back to seconds wait = 30; } }}/***************************************************************************** * edge_close * this function is called by the tty driver when a port is closed *****************************************************************************/static void edge_close (struct usb_serial_port *port, struct file * filp){ struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; int status; dbg("%s - port %d", __FUNCTION__, port->number); edge_serial = usb_get_serial_data(port->serial); edge_port = usb_get_serial_port_data(port); if ((edge_serial == NULL) || (edge_port == NULL)) return; // block until tx is empty block_until_tx_empty(edge_port); edge_port->closePending = TRUE; /* 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; } /* close the port */ dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__); send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0); //port->close = TRUE; edge_port->closePending = FALSE; edge_port->open = FALSE; edge_port->openPending = FALSE; if (edge_port->write_urb) { usb_kill_urb(edge_port->write_urb); } if (edge_port->write_urb) { /* if this urb had a transfer buffer already (old transfer) free it */ if (edge_port->write_urb->transfer_buffer != NULL) { kfree(edge_port->write_urb->transfer_buffer); } usb_free_urb (edge_port->write_urb); edge_port->write_urb = NULL; } if (edge_port->txfifo.fifo) { kfree(edge_port->txfifo.fifo); edge_port->txfifo.fifo = NULL; } dbg("%s exited", __FUNCTION__);} /***************************************************************************** * SerialWrite * this function is called by the tty driver when data should be written to * the port. * If successful, we return the number of bytes written, otherwise we return * a negative error number. *****************************************************************************/static int edge_write (struct usb_serial_port *port, const unsigned char *data, int count){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct TxFifo *fifo; int copySize; int bytesleft; int firsthalf; int secondhalf; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return -ENODEV; // get a pointer to the Tx fifo fifo = &edge_port->txfifo; spin_lock_irqsave(&edge_port->ep_lock, flags); // calculate number of bytes to put in fifo copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count)); dbg("%s(%d) of %d byte(s) Fifo room %d -- will copy %d bytes", __FUNCTION__, port->number, count, edge_port->txCredits - fifo->count, copySize); /* catch writes of 0 bytes which the tty driver likes to give us, and when txCredits is empty */ if (copySize == 0) { dbg("%s - copySize = Zero", __FUNCTION__); goto finish_write; } // queue the data // since we can never overflow the buffer we do not have to check for full condition // the copy is done is two parts -- first fill to the end of the buffer // then copy the reset from the start of the buffer bytesleft = fifo->size - fifo->head; firsthalf = min (bytesleft, copySize); dbg("%s - copy %d bytes of %d into fifo ", __FUNCTION__, firsthalf, bytesleft); /* now copy our data */ memcpy(&fifo->fifo[fifo->head], data, firsthalf); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, firsthalf, &fifo->fifo[fifo->head]); // update the index and size fifo->head += firsthalf; fifo->count += firsthalf; // wrap the index if (fifo->head == fifo->size) { fifo->head = 0; } secondhalf = copySize-firsthalf; if (secondhalf) { dbg("%s - copy rest of data %d", __FUNCTION__, secondhalf); memcpy(&fifo->fifo[fifo->head], &data[firsthalf], secondhalf); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, secondhalf, &fifo->fifo[fifo->head]); // update the index and size fifo->count += secondhalf; fifo->head += secondhalf; // No need to check for wrap since we can not get to end of fifo in this part }finish_write: spin_unlock_irqrestore(&edge_port->ep_lock, flags); send_more_port_data((struct edgeport_serial *)usb_get_serial_data(port->serial), edge_port); dbg("%s wrote %d byte(s) TxCredits %d, Fifo %d", __FUNCTION__, copySize, edge_port->txCredits, fifo->count); return copySize; }/************************************************************************ * * send_more_port_data() * * This routine attempts to write additional UART transmit data * to a port over the USB bulk pipe. It is called (1) when new * data has been written to a port's TxBuffer from higher layers * (2) when the peripheral sends us additional TxCredits indicating * that it can accept more Tx data for a given port; and (3) when * a bulk write completes successfully and we want to see if we * can transmit more. * ************************************************************************/static void send_more_port_data(struct edgeport_serial *edge_serial, struct edgeport_port *edge_port){ struct TxFifo *fifo = &edge_port->txfifo; struct urb *urb; unsigned char *buffer; int status; int count; int bytesleft; int firsthalf; int secondhalf; unsigned long flags; dbg("%s(%d)", __FUNCTION__, edge_port->port->number); spin_lock_irqsave(&edge_port->ep_lock, flags); if (edge_port->write_in_progress || !edge_port->open || (fifo->count == 0)) { dbg("%s(%d) EXIT - fifo %d, PendingWrite = %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->write_in_progress); goto exit_send; } // since the amount of data in the fifo will always fit into the // edgeport buffer we do not need to check the write length // Do we have enough credits for this port to make it worthwhile // to bother queueing a write. If it's too small, say a few bytes, // it's better to wait for more credits so we can do a larger // write. 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; /* if this urb had a transfer buffer already (old transfer) free it */ if (urb->transfer_buffer != NULL) { 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__);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -