ftdi_sio.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,818 行 · 第 1/5 页
C
1,818 行
dbg("%s", __FUNCTION__); if (c_cflag & HUPCL){ /* Disable flow control */ if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); } /* drop DTR */ if (set_dtr(port, LOW) < 0){ err("Error from DTR LOW urb"); } /* drop RTS */ if (set_rts(port, LOW) < 0) { err("Error from RTS LOW urb"); } } /* Note change no line if hupcl is off */ /* shutdown our bulk read */ if (port->read_urb) { if (usb_unlink_urb (port->read_urb) < 0) { /* Generally, this isn't an error. If the previous read bulk callback occurred (or is about to occur) while the port was being closed or was throtted (and is still throttled), the read urb will not have been submitted. */ dbg("%s - failed to unlink read urb (generally not an error)", __FUNCTION__); } }} /* ftdi_close */ /* The SIO requires the first byte to have: * B0 1 * B1 0 * B2..7 length of message excluding byte 0 * * The new devices do not require this byte */static int ftdi_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count){ /* ftdi_write */ struct ftdi_private *priv = usb_get_serial_port_data(port); struct urb *urb; unsigned char *buffer; int data_offset ; /* will be 1 for the SIO and 0 otherwise */ int status; int transfer_size; dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); if (count == 0) { err("write request of 0 bytes"); return 0; } data_offset = priv->write_offset; dbg("data_offset set to %d",data_offset); /* Determine total transfer size */ transfer_size = count; if (data_offset > 0) { /* Original sio needs control bytes too... */ transfer_size += (data_offset * ((count + (PKTSZ - 1 - data_offset)) / (PKTSZ - data_offset))); } buffer = kmalloc (transfer_size, GFP_ATOMIC); if (!buffer) { err("%s ran out of kernel memory for urb ...", __FUNCTION__); return -ENOMEM; } urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { err("%s - no more free urbs", __FUNCTION__); kfree (buffer); return -ENOMEM; } /* 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 */ if (from_user) { if (copy_from_user (first_byte + data_offset, current_position, user_pktsz)){ kfree (buffer); usb_free_urb (urb); return -EFAULT; } } else { 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 */ if (from_user) { if (copy_from_user (buffer, buf, count)) { kfree (buffer); usb_free_urb (urb); return -EFAULT; } } else { 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; kfree (buffer); } /* 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;} /* ftdi_write *//* This function may get called when the device is closed */static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; /* 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 (urb->status) { dbg("nonzero write bulk status received: %d", urb->status); return; } schedule_work(&port->work);} /* ftdi_write_bulk_callback */static int ftdi_write_room( struct usb_serial_port *port ){ dbg("%s - port %d", __FUNCTION__, port->number); /* * 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 */ return 2048;} /* ftdi_write_room */static int ftdi_chars_in_buffer (struct usb_serial_port *port){ /* ftdi_chars_in_buffer */ dbg("%s - port %d", __FUNCTION__, port->number); /* * We can't really account for how much data we * have sent out, but hasn't made it through to the * device, so just tell the tty layer that everything * is flushed. */ return 0;} /* ftdi_chars_in_buffer */static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs){ /* ftdi_read_bulk_callback */ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct tty_struct *tty; struct ftdi_private *priv; 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 (urb->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", urb->status); return; } /* If throttled, delay receive processing until unthrottled. */ spin_lock(&priv->rx_lock); if (priv->rx_flags & THROTTLED) { dbg("Deferring read urb processing until unthrottled"); priv->rx_flags |= ACTUALLY_THROTTLED; spin_unlock(&priv->rx_lock); return; } spin_unlock(&priv->rx_lock); ftdi_process_read(port);} /* ftdi_read_bulk_callback */static void ftdi_process_read (struct usb_serial_port *port){ /* ftdi_process_read */ struct urb *urb; struct tty_struct *tty; struct ftdi_private *priv; char error_flag; unsigned char *data; int i; int result; int need_flip; int packet_offset; 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; /* 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=0; packet_offset < urb->actual_length; packet_offset += PKTSZ) { /* Compare new line status to the old one, signal if different */ 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; } } /* 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 (urb->actual_length > packet_offset + 2) { for (i = 2; (i < PKTSZ) && ((i+packet_offset) < urb->actual_length); ++i) { /* have to make sure we don't overflow the buffer with tty_insert_flip_char's */ if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } /* 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 n
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?