📄 ftdi_sio.c
字号:
if (rv < 0) { dev_err(dev, "Unable to write latency timer: %i\n", rv); return -EIO; } return count;}/* Write an event character directly to the FTDI register. The ASCII value is in the low 8 bits, with the enable bit in the 9th bit. */static ssize_t store_event_char(struct device *dev, struct device_attribute *attr, const char *valbuf, size_t count){ struct usb_serial_port *port = to_usb_serial_port(dev); struct ftdi_private *priv = usb_get_serial_port_data(port); struct usb_device *udev = port->serial->dev; char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; dbg("%s: setting event char = %i", __FUNCTION__, v); rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, v, priv->interface, buf, 0, WDR_TIMEOUT); if (rv < 0) { dbg("Unable to write event character: %i", rv); return -EIO; } return count;}static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);static int create_sysfs_attrs(struct usb_serial_port *port){ struct ftdi_private *priv = usb_get_serial_port_data(port); int retval = 0; dbg("%s",__FUNCTION__); /* XXX I've no idea if the original SIO supports the event_char * sysfs parameter, so I'm playing it safe. */ if (priv->chip_type != SIO) { dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]); retval = device_create_file(&port->dev, &dev_attr_event_char); if ((!retval) && (priv->chip_type == FT232BM || priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || priv->chip_type == FT4232H)) { retval = device_create_file(&port->dev, &dev_attr_latency_timer); } } return retval;}static void remove_sysfs_attrs(struct usb_serial_port *port){ struct ftdi_private *priv = usb_get_serial_port_data(port); dbg("%s",__FUNCTION__); /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); if (priv->chip_type == FT232BM || priv->chip_type == FT2232C || priv->chip_type == FT232RL || priv->chip_type == FT2232H || priv->chip_type == FT4232H) { device_remove_file(&port->dev, &dev_attr_latency_timer); } }}/* * *************************************************************************** * FTDI driver specific functions * *************************************************************************** *//* Probe function to check for special devices */static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id){ struct ftdi_sio_quirk *quirk = (struct ftdi_sio_quirk *)id->driver_info; if (quirk && quirk->probe) { int ret = quirk->probe(serial); if (ret != 0) return ret; } usb_set_serial_data(serial, (void *)id->driver_info); return 0;}static int ftdi_sio_port_probe(struct usb_serial_port *port){ struct ftdi_private *priv; struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); dbg("%s",__FUNCTION__); priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv){ err("%s- kmalloc(%Zd) failed.", __FUNCTION__, sizeof(struct ftdi_private)); return -ENOMEM; } spin_lock_init(&priv->rx_lock); spin_lock_init(&priv->tx_lock); init_waitqueue_head(&priv->delta_msr_wait); /* This will push the characters through immediately rather than queue a task to deliver them */ priv->flags = ASYNC_LOW_LATENCY; if (quirk && quirk->port_probe) quirk->port_probe(priv); /* Increase the size of read buffers */ kfree(port->bulk_in_buffer); port->bulk_in_buffer = kmalloc (BUFSZ, GFP_KERNEL); if (!port->bulk_in_buffer) { kfree (priv); return -ENOMEM; } if (port->read_urb) { port->read_urb->transfer_buffer = port->bulk_in_buffer; port->read_urb->transfer_buffer_length = BUFSZ; } INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read); priv->port = port; /* Free port's existing write urb and transfer buffer. */ if (port->write_urb) { usb_free_urb (port->write_urb); port->write_urb = NULL; } kfree(port->bulk_out_buffer); port->bulk_out_buffer = NULL; usb_set_serial_port_data(port, priv); ftdi_determine_type (port); create_sysfs_attrs(port); return 0;}/* Setup for the USB-UIRT device, which requires hardwired * baudrate (38400 gets mapped to 312500) *//* Called from usbserial:serial_probe */static void ftdi_USB_UIRT_setup (struct ftdi_private *priv){ dbg("%s",__FUNCTION__); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = 38400;} /* ftdi_USB_UIRT_setup *//* Setup for the HE-TIRA1 device, which requires hardwired * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */static void ftdi_HE_TIRA1_setup (struct ftdi_private *priv){ dbg("%s",__FUNCTION__); priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = 38400; priv->force_rtscts = 1;} /* ftdi_HE_TIRA1_setup *//* * First port on Olimex arm-usb-ocd is reserved for JTAG interface * and can be accessed from userspace using openocd. */static int ftdi_olimex_probe(struct usb_serial *serial){ struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; dbg("%s",__FUNCTION__); if (interface == udev->actconfig->interface[0]) { info("Ignoring reserved serial port on Olimex arm-usb-ocd\n"); return -ENODEV; } return 0;}/* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * * usbserial:usb_serial_disconnect * calls __serial_close for each open of the port * shutdown is called then (ie ftdi_shutdown) */static void ftdi_shutdown (struct usb_serial *serial){ dbg("%s", __FUNCTION__);}static int ftdi_sio_port_remove(struct usb_serial_port *port){ struct ftdi_private *priv = usb_get_serial_port_data(port); dbg("%s", __FUNCTION__); remove_sysfs_attrs(port); /* all open ports are closed at this point * (by usbserial.c:__serial_close, which calls ftdi_close) */ if (priv) { usb_set_serial_port_data(port, NULL); kfree(priv); } return 0;}static int ftdi_open (struct usb_serial_port *port, struct file *filp){ /* ftdi_open */ struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned long flags; int result = 0; char buf[1]; /* Needed for the usb_control_msg I think */ dbg("%s", __FUNCTION__); spin_lock_irqsave(&priv->tx_lock, flags); priv->tx_bytes = 0; spin_unlock_irqrestore(&priv->tx_lock, flags); spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_bytes = 0; spin_unlock_irqrestore(&priv->rx_lock, flags); if (port->tty) port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, FTDI_SIO_RESET_SIO, priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change port->tty->termios - this would loose speed settings, etc. This is same behaviour as serial.c/rs_open() - Kuba */ /* ftdi_set_termios will send usb control messages */ if (port->tty) ftdi_set_termios(port, port->tty->termios); /* FIXME: Flow control might be enabled, so it should be checked - we have no control of defaults! */ /* Turn on RTS and DTR since we are not flow controlling by default */ set_mctrl(port, TIOCM_DTR | TIOCM_RTS); /* Not throttled */ spin_lock_irqsave(&priv->rx_lock, flags); priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); spin_unlock_irqrestore(&priv->rx_lock, flags); /* Start reading from the device */ priv->rx_processed = 0; usb_fill_bulk_urb(port->read_urb, dev, usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ftdi_read_bulk_callback, port); result = usb_submit_urb(port->read_urb, GFP_KERNEL); if (result) err("%s - failed submitting read urb, error %d", __FUNCTION__, result); return result;} /* ftdi_open *//* * usbserial:__serial_close only calls ftdi_close if the point is open * * This only gets called when it is the last close * * */static void ftdi_close (struct usb_serial_port *port, struct file *filp){ /* ftdi_close */ unsigned int c_cflag = port->tty->termios->c_cflag; struct ftdi_private *priv = usb_get_serial_port_data(port); char buf[1]; 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 RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Note change no line if hupcl is off */ /* cancel any scheduled reading */ cancel_delayed_work(&priv->rx_work); flush_scheduled_work(); /* shutdown our bulk read */ usb_kill_urb(port->read_urb);} /* 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, 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; unsigned long flags; dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count); if (count == 0) { dbg("write request of 0 bytes"); return 0; } spin_lock_irqsave(&priv->tx_lock, flags); if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) { spin_unlock_irqrestore(&priv->tx_lock, flags); dbg("%s - write limit hit\n", __FUNCTION__); return 0; } priv->tx_outstanding_urbs++; spin_unlock_irqrestore(&priv->tx_lock, flags); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -