📄 ftdi_sio.c
字号:
if (!buffer) { err("%s ran out of kernel memory for urb ...", __FUNCTION__); count = -ENOMEM; goto error_no_buffer; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { err("%s - no more free urbs", __FUNCTION__); count = -ENOMEM; goto error_no_urb; } /* Copy data */ if (data_offset > 0) { /* Original sio requires control byte at start of each packet. */ int user_pktsz = PKTSZ - data_offset; int todo = count; unsigned char *first_byte = buffer; const unsigned char *current_position = buf; while (todo > 0) { if (user_pktsz > todo) { user_pktsz = todo; } /* Write the control byte at the front of the packet*/ *first_byte = 1 | ((user_pktsz) << 2); /* Copy data for packet */ memcpy (first_byte + data_offset, current_position, user_pktsz); first_byte += user_pktsz + data_offset; current_position += user_pktsz; todo -= user_pktsz; } } else { /* No control byte required. */ /* Copy in the data to send */ memcpy (buffer, buf, count); } usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); /* fill the buffer and send it */ usb_fill_bulk_urb(urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), buffer, transfer_size, ftdi_write_bulk_callback, port); status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { err("%s - failed submitting write urb, error %d", __FUNCTION__, status); count = status; goto error; } else { spin_lock_irqsave(&priv->tx_lock, flags); priv->tx_outstanding_bytes += count; priv->tx_bytes += count; spin_unlock_irqrestore(&priv->tx_lock, flags); } /* we are done with this urb, so let the host driver * really free it when it is finished with it */ usb_free_urb(urb); dbg("%s write returning: %d", __FUNCTION__, count); return count;error: usb_free_urb(urb);error_no_urb: kfree (buffer);error_no_buffer: spin_lock_irqsave(&priv->tx_lock, flags); priv->tx_outstanding_urbs--; spin_unlock_irqrestore(&priv->tx_lock, flags); return count;} /* ftdi_write *//* This function may get called when the device is closed */static void ftdi_write_bulk_callback (struct urb *urb){ unsigned long flags; struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct ftdi_private *priv; int data_offset; /* will be 1 for the SIO and 0 otherwise */ unsigned long countback; int status = urb->status; /* free up the transfer buffer, as usb_free_urb() does not do this */ kfree (urb->transfer_buffer); dbg("%s - port %d", __FUNCTION__, port->number); if (status) { dbg("nonzero write bulk status received: %d", status); return; } priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __FUNCTION__); return; } /* account for transferred data */ countback = urb->actual_length; data_offset = priv->write_offset; if (data_offset > 0) { /* Subtract the control bytes */ countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ)); } spin_lock_irqsave(&priv->tx_lock, flags); --priv->tx_outstanding_urbs; priv->tx_outstanding_bytes -= countback; spin_unlock_irqrestore(&priv->tx_lock, flags); usb_serial_port_softint(port);} /* ftdi_write_bulk_callback */static int ftdi_write_room( struct usb_serial_port *port ){ struct ftdi_private *priv = usb_get_serial_port_data(port); int room; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->tx_lock, flags); if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) { /* * We really can take anything the user throws at us * but let's pick a nice big number to tell the tty * layer that we have lots of free space */ room = 2048; } else { room = 0; } spin_unlock_irqrestore(&priv->tx_lock, flags); return room;} /* ftdi_write_room */static int ftdi_chars_in_buffer (struct usb_serial_port *port){ /* ftdi_chars_in_buffer */ struct ftdi_private *priv = usb_get_serial_port_data(port); int buffered; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->tx_lock, flags); buffered = (int)priv->tx_outstanding_bytes; spin_unlock_irqrestore(&priv->tx_lock, flags); if (buffered < 0) { err("%s outstanding tx bytes is negative!", __FUNCTION__); buffered = 0; } return buffered;} /* ftdi_chars_in_buffer */static void ftdi_read_bulk_callback (struct urb *urb){ /* ftdi_read_bulk_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; struct ftdi_private *priv; unsigned long countread; unsigned long flags; int status = urb->status; if (urb->number_of_packets > 0) { err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__, urb->transfer_buffer_length, urb->actual_length, urb->number_of_packets ); err("%s transfer_flags %x ", __FUNCTION__,urb->transfer_flags ); } dbg("%s - port %d", __FUNCTION__, port->number); if (port->open_count <= 0) return; tty = port->tty; if (!tty) { dbg("%s - bad tty pointer - exiting",__FUNCTION__); return; } priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __FUNCTION__); return; } if (urb != port->read_urb) { err("%s - Not my urb!", __FUNCTION__); } if (status) { /* This will happen at close every time so it is a dbg not an err */ dbg("(this is ok on close) nonzero read bulk status received: " "%d", status); return; } /* count data bytes, but not status bytes */ countread = urb->actual_length; countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ); spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_bytes += countread; spin_unlock_irqrestore(&priv->rx_lock, flags); ftdi_process_read(&priv->rx_work.work);} /* ftdi_read_bulk_callback */static void ftdi_process_read (struct work_struct *work){ /* ftdi_process_read */ struct ftdi_private *priv = container_of(work, struct ftdi_private, rx_work.work); struct usb_serial_port *port = priv->port; struct urb *urb; struct tty_struct *tty; char error_flag; unsigned char *data; int i; int result; int need_flip; int packet_offset; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); if (port->open_count <= 0) return; tty = port->tty; if (!tty) { dbg("%s - bad tty pointer - exiting",__FUNCTION__); return; } priv = usb_get_serial_port_data(port); if (!priv) { dbg("%s - bad port private data pointer - exiting", __FUNCTION__); return; } urb = port->read_urb; if (!urb) { dbg("%s - bad read_urb pointer - exiting", __FUNCTION__); return; } data = urb->transfer_buffer; if (priv->rx_processed) { dbg("%s - already processed: %d bytes, %d remain", __FUNCTION__, priv->rx_processed, urb->actual_length - priv->rx_processed); } else { /* The first two bytes of every read packet are status */ if (urb->actual_length > 2) { usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data); } else { dbg("Status only: %03oo %03oo",data[0],data[1]); } } /* TO DO -- check for hung up line and handle appropriately: */ /* send hangup */ /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */ /* if CD is dropped and the line is not CLOCAL then we should hangup */ need_flip = 0; for (packet_offset = priv->rx_processed; packet_offset < urb->actual_length; packet_offset += PKTSZ) { int length; /* Compare new line status to the old one, signal if different */ /* N.B. packet may be processed more than once, but differences * are only processed once. */ if (priv != NULL) { char new_status = data[packet_offset+0] & FTDI_STATUS_B0_MASK; if (new_status != priv->prev_status) { priv->diff_status |= new_status ^ priv->prev_status; wake_up_interruptible(&priv->delta_msr_wait); priv->prev_status = new_status; } } length = min(PKTSZ, urb->actual_length-packet_offset)-2; if (length < 0) { err("%s - bad packet length: %d", __FUNCTION__, length+2); length = 0; } if (priv->rx_flags & THROTTLED) { dbg("%s - throttled", __FUNCTION__); break; } if (tty_buffer_request_room(tty, length) < length) { /* break out & wait for throttling/unthrottling to happen */ dbg("%s - receive room low", __FUNCTION__); break; } /* Handle errors and break */ error_flag = TTY_NORMAL; /* Although the device uses a bitmask and hence can have multiple */ /* errors on a packet - the order here sets the priority the */ /* error is returned to the tty layer */ if ( data[packet_offset+1] & FTDI_RS_OE ) { error_flag = TTY_OVERRUN; dbg("OVERRRUN error"); } if ( data[packet_offset+1] & FTDI_RS_BI ) { error_flag = TTY_BREAK; dbg("BREAK received"); } if ( data[packet_offset+1] & FTDI_RS_PE ) { error_flag = TTY_PARITY; dbg("PARITY error"); } if ( data[packet_offset+1] & FTDI_RS_FE ) { error_flag = TTY_FRAME; dbg("FRAMING error"); } if (length > 0) { for (i = 2; i < length+2; i++) { /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ tty_insert_flip_char(tty, data[packet_offset+i], error_flag); } need_flip = 1; }#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW /* if a parity error is detected you get status packets forever until a character is sent without a parity error. This doesn't work well since the application receives a never ending stream of bad data - even though new data hasn't been sent. Therefore I (bill) have taken this out. However - this might make sense for framing errors and so on so I am leaving the code in for now. */ else { if (error_flag != TTY_NORMAL){ dbg("error_flag is not normal"); /* In this case it is just status - if that is an error send a bad character */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } tty_insert_flip_char(tty, 0xff, error_flag); need_flip = 1; } }#endif } /* "for(packet_offset=0..." */ /* Low latency */ if (need_flip) { tty_flip_buffer_push(tty); } if (packet_offset < urb->actual_length) { /* not completely processed - record progress */ priv->rx_processed = packet_offset; dbg("%s - incomplete, %d bytes processed, %d remain", __FUNCTION__, packet_offset, urb->actual_length - packet_offset); /* check if we were throttled while processing */ spin_lock_irqsave(&priv->rx_lock, flags); if (priv->rx_flags & THROTTLED) { priv->rx_flags |= ACTUALLY_THROTTLED; spin_unlock_irqrestore(&priv->rx_lock, flags); dbg("%s - deferring r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -