aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <triad@df.lth.se>2007-01-22 06:46:08 +0000
committerLinus Walleij <triad@df.lth.se>2007-01-22 06:46:08 +0000
commit2e1c8a3bcaaf9a64e79a72a4da62ddf810a99ecc (patch)
tree3754e8ca9c7bb286c47be7386ed245398410cc1b
parentb2e105dcca5a4ed3f66a843bd9b7783e1908fe34 (diff)
downloadlibmtp-2e1c8a3bcaaf9a64e79a72a4da62ddf810a99ecc.tar.gz
Multiple devices patch from Ted Bullock
-rw-r--r--AUTHORS3
-rw-r--r--src/libmtp.h.in4
-rw-r--r--src/libusb-glue.c179
3 files changed, 184 insertions, 2 deletions
diff --git a/AUTHORS b/AUTHORS
index 33fbb9a..577896a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,7 +5,7 @@ Linus Walleij <triad@df.lth.se>
We both came to do libmtp after working on the libnjb
project, which was all about Creative Technology devices
-implementing the OaSIS and PDE protocols.
+implementing the OASiS and PDE protocols.
libmtp is however largely based on libptp2, which was created by
Mariusz Woloszyn <emsi@ipartners.pl> as part of gPhoto2 then
@@ -24,3 +24,4 @@ Dave Kelly <libmtp@ravelox.co.uk>
Matthew Wilcox <matthew@wil.cx>
Robert Reardon <rreardon@monkshatch.vispa.com>
Orson Teodoro <orsonteodoro@yahoo.com>
+Ted Bullock <tbullock@canada.com>
diff --git a/src/libmtp.h.in b/src/libmtp.h.in
index 2deb4da..5746d4d 100644
--- a/src/libmtp.h.in
+++ b/src/libmtp.h.in
@@ -95,7 +95,9 @@ typedef enum {
*/
typedef enum {
LIBMTP_ERROR_NONE,
- LIBMTP_ERROR_GENERAL
+ LIBMTP_ERROR_GENERAL,
+ LIBMTP_ERROR_N0_DEVICE_ATTACHED,
+ LIBMTP_ERROR_MEMORY_ALLOCATION
} LIBMTP_error_number_t;
typedef struct LIBMTP_device_entry_struct LIBMTP_device_entry_t; /**< @see LIBMTP_device_entry_struct */
typedef struct LIBMTP_error_struct LIBMTP_error_t; /**< @see LIBMTP_error_struct */
diff --git a/src/libusb-glue.c b/src/libusb-glue.c
index 9274897..670e082 100644
--- a/src/libusb-glue.c
+++ b/src/libusb-glue.c
@@ -5,6 +5,13 @@
* Modified by Linus Walleij 2006-03-06
* (Notice that Anglo-Saxons use little-endian dates and Swedes use big-endian dates.)
*
+ * Licensed under the LGPL GNU Lesser General Public License.
+ *
+ * Copyright Richard Low (c) 2005-2007
+ * Copyright Linus Walleij (c) 2006-2007
+ * Copyright Marcus Meissner (c) 2006-2007
+ * Copyright Ted Bullock (c) 2007
+ *
* This file adds some utils (many copied from ptpcam.c from libptp2) to
* use MTP devices. Include mtp-utils.h to use any of the ptp/mtp functions.
*
@@ -349,6 +356,178 @@ static struct usb_device *probe_usb_bus_for_mtp_devices(void)
}
/**
+ * Check for the Microsoft OS device descriptor and return device struct
+ * if the device is MTP-compliant. The function will only recognize
+ * a single device connected to the USB bus.
+ * @param MTPDeviceList dynamic array of pointers to usb devices with MTP
+ * properties. Be sure to call free(MTPDeviceList).
+ * @param numdevices number of devices in MTPDeviceList Dynamic Array
+ * @return an MTP-compliant USB device if one was found, else NULL.
+ */
+static LIBMTP_error_number_t get_mtp_usb_device_list(
+ struct usb_device ** MTPDeviceList,
+ uint8_t *numdevices)
+{
+ /* Initialize number of MTP USB devices to 0 */
+ *numdevices = 0;
+ MTPDeviceList = NULL;
+
+ struct usb_bus *bus = init_usb();
+ for (; bus != NULL; bus = bus->next)
+ {
+ struct usb_device *dev = bus->devices;
+ for (; dev != NULL; dev = dev->next)
+ {
+ usb_dev_handle *devh;
+ unsigned char buf[1024], cmd;
+ int ret;
+
+ /* Attempt to open Device on this port */
+ devh = usb_open(dev);
+ if (devh == NULL)
+ {
+ /* Could not open this device, continue */
+ continue;
+ }
+
+ /* Read the special descriptor */
+ ret = usb_get_descriptor(devh, 0x03, 0xee, buf, sizeof(buf));
+
+ /* Check if descriptor length is at least 10 bytes */
+ if (ret < 10)
+ {
+ usb_close(devh);
+ continue;
+ }
+
+ /* Check if this device has a Microsoft Descriptor */
+ if (!((buf[2] == 'M') && (buf[4] == 'S') &&
+ (buf[6] == 'F') && (buf[8] == 'T')))
+ {
+ usb_close(devh);
+ continue;
+ }
+
+ /* Check if device responds to control message 1 or if there is an error*/
+ cmd = buf[16];
+ ret = usb_control_msg (devh,
+ USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR,
+ cmd,
+ 0,
+ 4,
+ (char *) buf,
+ sizeof(buf),
+ 1000);
+
+ /* If this is true, the device either isn't MTP or there was an error */
+ if (ret <= 0x15)
+ {
+ /* TODO: If there was an error, flag it and let the user know somehow */
+ /* if(ret == -1) {} */
+ usb_close(devh);
+ continue;
+ }
+
+ /* Check if device is MTP or if it is something like a USB Mass Storage
+ device with Janus DRM support */
+ if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P'))
+ {
+ usb_close(devh);
+ continue;
+ }
+
+ /* After this point we are probably dealing with an MTP device */
+
+ /* Check if device responds to control message 2 or if there is an error*/
+ ret = usb_control_msg (devh,
+ USB_ENDPOINT_IN|USB_RECIP_DEVICE|USB_TYPE_VENDOR,
+ cmd,
+ 0,
+ 5,
+ (char *) buf,
+ sizeof(buf),
+ 1000);
+
+ /* If this is true, the device errored against control message 2 */
+ if (ret == -1)
+ {
+ /* TODO: Implement callback function to let managing program know there
+ was a problem, along with description of the problem */
+ fprintf(stderr, "Potential MTP Device with VendorID:%04x and "
+ "ProductID:%04x encountered an error responding to "
+ "control message 2. Problems may arrise but continuing",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ }
+ else if (ret <= 0x15)
+ {
+ /* TODO: Implement callback function to let managing program know there
+ was a problem, along with description of the problem */
+ fprintf(stderr, "Potential MTP Device with VendorID:%04x and "
+ "ProductID:%04x responded to control message 2 with a "
+ "response that was too short. Problems may arrise but "
+ "continuing",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ }
+ else if ((buf[0x12] != 'M') || (buf[0x13] != 'T') || (buf[0x14] != 'P'))
+ {
+ /* TODO: Implement callback function to let managing program know there
+ was a problem, along with description of the problem */
+ fprintf(stderr, "Potential MTP Device with VendorID:%04x and "
+ "ProductID:%04x encountered an error responding to "
+ "control message 2. Problems may arrise but continuing",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ }
+
+ /* Close the USB device handle */
+ usb_close(devh);
+
+ /* Append this usb device to the MTP USB Device List */
+ if(MTPDeviceList == NULL)
+ {
+ MTPDeviceList = (struct usb_device **)malloc(sizeof(void *));
+ /* Check for allocation Error */
+ if(MTPDeviceList == NULL)
+ {
+ /* TODO: Implement callback function to let managing applications know
+ there was a memory allocation problem */
+ fprintf(stderr, "Memory Allocation Problem: unable to connect MTP "
+ "Device with VendorID:%04x and ProductID:%04x. ",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return LIBMTP_ERROR_MEMORY_ALLOCATION;
+ }
+ MTPDeviceList[0] = dev;
+ (*numdevices)++;
+ }
+ else
+ {
+ MTPDeviceList = (struct usb_device **)realloc(
+ MTPDeviceList,
+ *numdevices + 1);
+
+ /* Check for allocation Error */
+ if(MTPDeviceList == NULL)
+ {
+ /* TODO: Implement callback function to let managing applications know
+ there was a memory allocation problem */
+ fprintf(stderr, "Memory Allocation Problem: unable to connect MTP "
+ "Device with VendorID:%04x and ProductID:%04x. ",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ return LIBMTP_ERROR_MEMORY_ALLOCATION;
+ }
+ MTPDeviceList[*numdevices] = dev;
+ (*numdevices)++;
+ }
+ }
+ }
+
+ /* If nothing was found we end up here. */
+ if(MTPDeviceList == NULL)
+ return LIBMTP_ERROR_N0_DEVICE_ATTACHED;
+ else
+ return LIBMTP_ERROR_NONE;
+}
+
+/**
* Detect the MTP device descriptor and return the VID and PID
* of the first device found. This is a very low-level function
* which is intended for use with <b>udev</b> or other hotplug