📄 io_edgeport.c
字号:
static void edge_bulk_out_cmd_callback (struct urb *urb){ struct edgeport_port *edge_port = (struct edgeport_port *)urb->context; struct tty_struct *tty; int status = urb->status; dbg("%s", __FUNCTION__); atomic_dec(&CmdUrbs); dbg("%s - FREE URB %p (outstanding %d)", __FUNCTION__, urb, atomic_read(&CmdUrbs)); /* clean up the transfer buffer */ kfree(urb->transfer_buffer); /* Free the command urb */ usb_free_urb (urb); if (status) { dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, status); return; } /* Get pointer to tty */ tty = edge_port->port->tty; /* tell the tty driver that something has changed */ if (tty && edge_port->open) tty_wakeup(tty); /* we have completed the command */ edge_port->commandPending = false; wake_up(&edge_port->wait_command);}/***************************************************************************** * Driver tty interface functions *****************************************************************************//***************************************************************************** * SerialOpen * this function is called by the tty driver when a port is opened * If successful, we return 0 * Otherwise we return a negative error number. *****************************************************************************/static int edge_open (struct usb_serial_port *port, struct file * filp){ struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct usb_serial *serial; struct edgeport_serial *edge_serial; int response; dbg("%s - port %d", __FUNCTION__, port->number); if (edge_port == NULL) return -ENODEV; if (port->tty) port->tty->low_latency = low_latency; /* see if we've set up our endpoint info yet (can't set it up in edge_startup as the structures were not set up at that time.) */ serial = port->serial; edge_serial = usb_get_serial_data(serial); if (edge_serial == NULL) { return -ENODEV; } if (edge_serial->interrupt_in_buffer == NULL) { struct usb_serial_port *port0 = serial->port[0]; /* not set up yet, so do it now */ edge_serial->interrupt_in_buffer = port0->interrupt_in_buffer; edge_serial->interrupt_in_endpoint = port0->interrupt_in_endpointAddress; edge_serial->interrupt_read_urb = port0->interrupt_in_urb; edge_serial->bulk_in_buffer = port0->bulk_in_buffer; edge_serial->bulk_in_endpoint = port0->bulk_in_endpointAddress; edge_serial->read_urb = port0->read_urb; edge_serial->bulk_out_endpoint = port0->bulk_out_endpointAddress; /* set up our interrupt urb */ usb_fill_int_urb(edge_serial->interrupt_read_urb, serial->dev, usb_rcvintpipe(serial->dev, port0->interrupt_in_endpointAddress), port0->interrupt_in_buffer, edge_serial->interrupt_read_urb->transfer_buffer_length, edge_interrupt_callback, edge_serial, edge_serial->interrupt_read_urb->interval); /* set up our bulk in urb */ usb_fill_bulk_urb(edge_serial->read_urb, serial->dev, usb_rcvbulkpipe(serial->dev, port0->bulk_in_endpointAddress), port0->bulk_in_buffer, edge_serial->read_urb->transfer_buffer_length, edge_bulk_in_callback, edge_serial); edge_serial->read_in_progress = false; /* start interrupt read for this edgeport * this interrupt will continue as long as the edgeport is connected */ response = usb_submit_urb (edge_serial->interrupt_read_urb, GFP_KERNEL); if (response) { dev_err(&port->dev, "%s - Error %d submitting control urb\n", __FUNCTION__, response); } } /* initialize our wait queues */ init_waitqueue_head(&edge_port->wait_open); init_waitqueue_head(&edge_port->wait_chase); init_waitqueue_head(&edge_port->delta_msr_wait); init_waitqueue_head(&edge_port->wait_command); /* initialize our icount structure */ memset (&(edge_port->icount), 0x00, sizeof(edge_port->icount)); /* initialize our port settings */ edge_port->txCredits = 0; /* Can't send any data yet */ edge_port->shadowMCR = MCR_MASTER_IE; /* Must always set this bit to enable ints! */ edge_port->chaseResponsePending = false; /* send a open port command */ edge_port->openPending = true; edge_port->open = false; response = send_iosp_ext_cmd (edge_port, IOSP_CMD_OPEN_PORT, 0); if (response < 0) { dev_err(&port->dev, "%s - error sending open port command\n", __FUNCTION__); edge_port->openPending = false; return -ENODEV; } /* now wait for the port to be completely opened */ wait_event_timeout(edge_port->wait_open, !edge_port->openPending, OPEN_TIMEOUT); if (!edge_port->open) { /* open timed out */ dbg("%s - open timedout", __FUNCTION__); edge_port->openPending = false; return -ENODEV; } /* create the txfifo */ edge_port->txfifo.head = 0; edge_port->txfifo.tail = 0; edge_port->txfifo.count = 0; edge_port->txfifo.size = edge_port->maxTxCredits; edge_port->txfifo.fifo = kmalloc (edge_port->maxTxCredits, GFP_KERNEL); if (!edge_port->txfifo.fifo) { dbg("%s - no memory", __FUNCTION__); edge_close (port, filp); return -ENOMEM; } /* Allocate a URB for the write */ edge_port->write_urb = usb_alloc_urb (0, GFP_KERNEL); edge_port->write_in_progress = false; if (!edge_port->write_urb) { dbg("%s - no memory", __FUNCTION__); edge_close (port, filp); return -ENOMEM; } dbg("%s(%d) - Initialize TX fifo to %d bytes", __FUNCTION__, port->number, edge_port->maxTxCredits); dbg("%s exited", __FUNCTION__); return 0;}/************************************************************************ * * block_until_chase_response * * This function will block the close until one of the following: * 1. Response to our Chase comes from Edgeport * 2. A timout of 10 seconds without activity has expired * (1K of Edgeport data @ 2400 baud ==> 4 sec to empty) * ************************************************************************/static void block_until_chase_response(struct edgeport_port *edge_port){ DEFINE_WAIT(wait); __u16 lastCredits; int timeout = 1*HZ; int loop = 10; while (1) { // Save Last credits lastCredits = edge_port->txCredits; // Did we get our Chase response if (!edge_port->chaseResponsePending) { dbg("%s - Got Chase Response", __FUNCTION__); // did we get all of our credit back? if (edge_port->txCredits == edge_port->maxTxCredits ) { dbg("%s - Got all credits", __FUNCTION__); return; } } // Block the thread for a while prepare_to_wait(&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE); schedule_timeout(timeout); finish_wait(&edge_port->wait_chase, &wait); if (lastCredits == edge_port->txCredits) { // No activity.. count down. loop--; if (loop == 0) { edge_port->chaseResponsePending = false; dbg("%s - Chase TIMEOUT", __FUNCTION__); return; } } else { // Reset timout value back to 10 seconds dbg("%s - Last %d, Current %d", __FUNCTION__, lastCredits, edge_port->txCredits); loop = 10; } }}/************************************************************************ * * block_until_tx_empty * * This function will block the close until one of the following: * 1. TX count are 0 * 2. The edgeport has stopped * 3. A timout of 3 seconds without activity has expired * ************************************************************************/static void block_until_tx_empty (struct edgeport_port *edge_port){ DEFINE_WAIT(wait); struct TxFifo *fifo = &edge_port->txfifo; __u32 lastCount; int timeout = HZ/10; int loop = 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 prepare_to_wait (&edge_port->wait_chase, &wait, TASK_UNINTERRUPTIBLE); schedule_timeout(timeout); finish_wait(&edge_port->wait_chase, &wait); dbg("%s wait", __FUNCTION__); if (lastCount == fifo->count) { // No activity.. count down. loop--; if (loop == 0) { dbg("%s - TIMEOUT", __FUNCTION__); return; } } else { // Reset timout value back to seconds loop = 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; if ((!edge_serial->is_epic) || ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPChase))) { /* 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 ((!edge_serial->is_epic) || ((edge_serial->is_epic) && (edge_serial->epic_descriptor.Supports.IOSPClose))) { /* 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; usb_kill_urb(edge_port->write_urb); if (edge_port->write_urb) { /* if this urb had a transfer buffer already (old transfer) free it */ kfree(edge_port->write_urb->transfer_buffer); usb_free_urb(edge_port->write_urb); edge_port->write_urb = NULL; } 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -