Add kernel driver auto attach/detach
[libftdi] / src / ftdi.c
index c26ab72..52266d0 100644 (file)
@@ -87,7 +87,7 @@ static void ftdi_usb_close_internal (struct ftdi_context *ftdi)
 */
 int ftdi_init(struct ftdi_context *ftdi)
 {
-    struct ftdi_eeprom* eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom));
+    struct ftdi_eeprom* eeprom;
     ftdi->usb_ctx = NULL;
     ftdi->usb_dev = NULL;
     ftdi->usb_read_timeout = 5000;
@@ -111,6 +111,7 @@ int ftdi_init(struct ftdi_context *ftdi)
     ftdi_set_interface(ftdi, INTERFACE_ANY);
     ftdi->bitbang_mode = 1; /* when bitbang is enabled this holds the number of the mode  */
 
+    eeprom = (struct ftdi_eeprom *)malloc(sizeof(struct ftdi_eeprom));
     if (eeprom == 0)
         ftdi_error_return(-2, "Can't malloc struct ftdi_eeprom");
     memset(eeprom, 0, sizeof(struct ftdi_eeprom));
@@ -613,6 +614,11 @@ int ftdi_usb_open_dev(struct ftdi_context *ftdi, libusb_device *dev)
         if (libusb_detach_kernel_driver(ftdi->usb_dev, ftdi->interface) !=0)
             detach_errno = errno;
     }
+    else if (ftdi->module_detach_mode == AUTO_DETACH_REATACH_SIO_MODULE)
+    {
+        if (libusb_set_auto_detach_kernel_driver(ftdi->usb_dev, 1) != LIBUSB_SUCCESS)
+            detach_errno = errno;
+    }
 
     if (libusb_get_configuration (ftdi->usb_dev, &cfg) < 0)
         ftdi_error_return(-12, "libusb_get_configuration () failed");
@@ -750,6 +756,7 @@ int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product,
     \retval -9: get serial number failed
     \retval -10: unable to close device
     \retval -11: ftdi context invalid
+    \retval -12: libusb_get_device_list() failed
 */
 int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
                              const char* description, const char* serial, unsigned int index)
@@ -824,11 +831,11 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
 }
 
 /**
-    Opens the device at a given USB bus and port.
+    Opens the device at a given USB bus and device address.
 
     \param ftdi pointer to ftdi_context
     \param bus Bus number
-    \param port Port number
+    \param addr Device address
 
     \retval  0: all fine
     \retval -1: usb_find_busses() failed
@@ -842,8 +849,9 @@ int ftdi_usb_open_desc_index(struct ftdi_context *ftdi, int vendor, int product,
     \retval -9: get serial number failed
     \retval -10: unable to close device
     \retval -11: ftdi context invalid
+    \retval -12: libusb_get_device_list() failed
 */
-int ftdi_usb_open_bus_port(struct ftdi_context *ftdi, uint8_t bus, uint8_t port)
+int ftdi_usb_open_bus_addr(struct ftdi_context *ftdi, uint8_t bus, uint8_t addr)
 {
     libusb_device *dev;
     libusb_device **devs;
@@ -857,7 +865,7 @@ int ftdi_usb_open_bus_port(struct ftdi_context *ftdi, uint8_t bus, uint8_t port)
 
     while ((dev = devs[i++]) != NULL)
     {
-        if (libusb_get_bus_number(dev) == bus && libusb_get_port_number(dev) == port)
+        if (libusb_get_bus_number(dev) == bus && libusb_get_device_address(dev) == addr)
         {
             int res;
             res = ftdi_usb_open_dev(ftdi, dev);
@@ -1906,13 +1914,14 @@ int ftdi_write_data_get_chunksize(struct ftdi_context *ftdi, unsigned int *chunk
 int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size)
 {
     int offset = 0, ret, i, num_of_chunks, chunk_remains;
-    int packet_size = ftdi->max_packet_size;
+    int packet_size;
     int actual_length = 1;
 
     if (ftdi == NULL || ftdi->usb_dev == NULL)
         ftdi_error_return(-666, "USB device unavailable");
 
     // Packet size sanity check (avoid division by zero)
+    packet_size = ftdi->max_packet_size;
     if (packet_size == 0)
         ftdi_error_return(-1, "max_packet_size is bogus (zero)");
 
@@ -2260,9 +2269,11 @@ int ftdi_poll_modem_status(struct ftdi_context *ftdi, unsigned short *status)
 /**
     Set flowcontrol for ftdi chip
 
+    Note: Do not use this function to enable XON/XOFF mode, use ftdi_setflowctrl_xonxoff() instead.
+
     \param ftdi pointer to ftdi_context
     \param flowctrl flow control to use. should be
-           SIO_DISABLE_FLOW_CTRL, SIO_RTS_CTS_HS, SIO_DTR_DSR_HS or SIO_XON_XOFF_HS
+           SIO_DISABLE_FLOW_CTRL, SIO_RTS_CTS_HS, SIO_DTR_DSR_HS
 
     \retval  0: all fine
     \retval -1: set flow control failed
@@ -2282,6 +2293,31 @@ int ftdi_setflowctrl(struct ftdi_context *ftdi, int flowctrl)
 }
 
 /**
+    Set XON/XOFF flowcontrol for ftdi chip
+
+    \param ftdi pointer to ftdi_context
+    \param xon character code used to resume transmission
+    \param xoff character code used to pause transmission
+
+    \retval  0: all fine
+    \retval -1: set flow control failed
+    \retval -2: USB device unavailable
+*/
+int ftdi_setflowctrl_xonxoff(struct ftdi_context *ftdi, unsigned char xon, unsigned char xoff)
+{
+    if (ftdi == NULL || ftdi->usb_dev == NULL)
+        ftdi_error_return(-2, "USB device unavailable");
+
+    uint16_t xonxoff = xon | (xoff << 8);
+    if (libusb_control_transfer(ftdi->usb_dev, FTDI_DEVICE_OUT_REQTYPE,
+                                SIO_SET_FLOW_CTRL_REQUEST, xonxoff, (SIO_XON_XOFF_HS | ftdi->index),
+                                NULL, 0, ftdi->usb_write_timeout) < 0)
+        ftdi_error_return(-1, "set flow control failed");
+
+    return 0;
+}
+
+/**
     Set dtr line
 
     \param ftdi pointer to ftdi_context