1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-31 11:35:24 +01:00

MTP support for Mac... Currently crashes the entire USB bus so I wouldn't use it.

This commit is contained in:
John Maguire 2010-09-02 21:20:27 +00:00
parent 4235c0f49d
commit 75a576a5c2
7 changed files with 110 additions and 19 deletions

View File

@ -30,9 +30,13 @@ class MacDeviceLister : public DeviceLister {
struct MTPDevice {
QString vendor;
quint16 vendor_id;
QString product;
quint16 vendor_id;
quint16 product_id;
int quirks;
int bus;
int address;
};
public slots:
@ -48,10 +52,13 @@ class MacDeviceLister : public DeviceLister {
static void DiskUnmountCallback(
DADiskRef disk, DADissenterRef dissenter, void* context);
void FoundMTPDevice(const MTPDevice& device, const QString& serial);
DASessionRef loop_session_;
CFRunLoopRef run_loop_;
QMap<QString, QString> current_devices_;
QMap<QString, MTPDevice> mtp_devices_;
static QSet<MTPDevice> sMTPDeviceList;
};

View File

@ -81,6 +81,7 @@ void MacDeviceLister::Init() {
d.vendor_id = device.vendor_id;
d.product = QString::fromAscii(device.product);
d.product_id = device.product_id;
d.quirks = device.device_flags;
}
}
}
@ -227,6 +228,11 @@ QString GetSerialForDevice(io_object_t device) {
"USB/" + GetUSBRegistryEntryString(device, CFSTR(kUSBSerialNumberString)));
}
QString GetSerialForMTPDevice(io_object_t device) {
return QString(
"MTP/" + GetUSBRegistryEntryString(device, CFSTR(kUSBSerialNumberString)));
}
QString FindDeviceProperty(const QString& bsd_name, CFStringRef property) {
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk = DADiskCreateFromBSDName(
@ -340,6 +346,11 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
io_object_t object;
while ((object = IOIteratorNext(it))) {
CFStringRef class_name = IOObjectCopyClass(object);
BOOST_SCOPE_EXIT((class_name)(object)) {
CFRelease(class_name);
IOObjectRelease(object);
} BOOST_SCOPE_EXIT_END
if (CFStringCompare(class_name, CFSTR(kIOUSBDeviceClassName), 0) == kCFCompareEqualTo) {
NSString* vendor = (NSString*)GetPropertyForDevice(object, CFSTR(kUSBVendorString));
NSString* product = (NSString*)GetPropertyForDevice(object, CFSTR(kUSBProductString));
@ -351,6 +362,10 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
device.product = QString::fromUtf8([product UTF8String]);
device.vendor_id = [vendor_id unsignedShortValue];
device.product_id = [product_id unsignedShortValue];
device.quirks = 0;
device.bus = -1;
device.address = -1;
if (device.vendor_id == 0x5ac) {
// I think we can safely skip Apple products.
@ -369,12 +384,17 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
// Failed to get bus or address number.
continue;
}
device.bus = bus;
device.address = [addr intValue];
// First check the libmtp device list.
if (sMTPDeviceList.contains(device)) {
QSet<MTPDevice>::const_iterator it = sMTPDeviceList.find(device);
if (it != sMTPDeviceList.end()) {
qDebug() << "Matched device to libmtp list!";
// emit.
return;
// Fill in quirks flags from libmtp.
device.quirks = it->quirks;
me->FoundMTPDevice(device, GetSerialForMTPDevice(object));
continue;
}
IOCFPlugInInterface** plugin_interface = NULL;
@ -457,16 +477,31 @@ void MacDeviceLister::USBDeviceAddedCallback(void* refcon, io_iterator_t it) {
continue;
}
// Hurray! We made it!
qDebug() << "New MTP device detected!";
me->FoundMTPDevice(device, GetSerialForMTPDevice(object));
}
}
CFRelease(class_name);
IOObjectRelease(object);
}
}
void MacDeviceLister::FoundMTPDevice(const MTPDevice& device, const QString& serial) {
qDebug() << "New MTP device detected!";
mtp_devices_[serial] = device;
emit DeviceAdded(serial);
}
bool IsMTPSerial(const QString& serial) {
return serial.startsWith("MTP");
}
QString MacDeviceLister::MakeFriendlyName(const QString& serial) {
if (IsMTPSerial(serial)) {
const MTPDevice& device = mtp_devices_[serial];
if (device.vendor.isEmpty()) {
return device.product;
} else {
return device.vendor + " " + device.product;
}
}
QString bsd_name = current_devices_[serial];
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk = DADiskCreateFromBSDName(
@ -487,6 +522,19 @@ QString MacDeviceLister::MakeFriendlyName(const QString& serial) {
}
QList<QUrl> MacDeviceLister::MakeDeviceUrls(const QString& serial) {
if (IsMTPSerial(serial)) {
const MTPDevice& device = mtp_devices_[serial];
QString str;
str.sprintf("gphoto2://usb-%d-%d/", device.bus, device.address);
QUrl url(str);
url.addQueryItem("vendor", device.vendor);
url.addQueryItem("vendor_id", QString::number(device.vendor_id));
url.addQueryItem("product", device.product);
url.addQueryItem("product_id", QString::number(device.product_id));
url.addQueryItem("quirks", QString::number(device.quirks));
return QList<QUrl>() << url;
}
QString bsd_name = current_devices_[serial];
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk = DADiskCreateFromBSDName(
@ -506,10 +554,13 @@ QList<QUrl> MacDeviceLister::MakeDeviceUrls(const QString& serial) {
}
QStringList MacDeviceLister::DeviceUniqueIDs() {
return current_devices_.keys();
return current_devices_.keys() + mtp_devices_.keys();
}
QVariantList MacDeviceLister::DeviceIcons(const QString& serial) {
if (IsMTPSerial(serial)) {
return QVariantList();
}
QString bsd_name = current_devices_[serial];
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk = DADiskCreateFromBSDName(
@ -538,14 +589,23 @@ QVariantList MacDeviceLister::DeviceIcons(const QString& serial) {
}
QString MacDeviceLister::DeviceManufacturer(const QString& serial){
if (IsMTPSerial(serial)) {
return mtp_devices_[serial].vendor;
}
return FindDeviceProperty(current_devices_[serial], CFSTR(kUSBVendorString));
}
QString MacDeviceLister::DeviceModel(const QString& serial){
if (IsMTPSerial(serial)) {
return mtp_devices_[serial].product;
}
return FindDeviceProperty(current_devices_[serial], CFSTR(kUSBProductString));
}
quint64 MacDeviceLister::DeviceCapacity(const QString& serial){
if (IsMTPSerial(serial)) {
return 10000000;
}
QString bsd_name = current_devices_[serial];
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk = DADiskCreateFromBSDName(
@ -566,6 +626,9 @@ quint64 MacDeviceLister::DeviceCapacity(const QString& serial){
}
quint64 MacDeviceLister::DeviceFreeSpace(const QString& serial){
if (IsMTPSerial(serial)) {
return 10000000;
}
QString bsd_name = current_devices_[serial];
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
DADiskRef disk = DADiskCreateFromBSDName(
@ -597,6 +660,8 @@ quint64 MacDeviceLister::DeviceFreeSpace(const QString& serial){
QVariantMap MacDeviceLister::DeviceHardwareInfo(const QString& serial){return QVariantMap();}
void MacDeviceLister::UnmountDevice(const QString& serial) {
if (IsMTPSerial(serial)) return;
QString bsd_name = current_devices_[serial];
DADiskRef disk = DADiskCreateFromBSDName(
kCFAllocatorDefault, loop_session_, bsd_name.toAscii().constData());

View File

@ -19,9 +19,10 @@
#include <QRegExp>
#include <QtDebug>
MtpConnection::MtpConnection(const QString& hostname)
MtpConnection::MtpConnection(const QUrl& url)
: device_(NULL)
{
QString hostname = url.host();
// Parse the URL
QRegExp host_re("^usb-(\\d+)-(\\d+)$");
@ -33,6 +34,23 @@ MtpConnection::MtpConnection(const QString& hostname)
const unsigned int bus_location = host_re.cap(1).toInt();
const unsigned int device_num = host_re.cap(2).toInt();
if (url.hasQueryItem("vendor")) {
LIBMTP_raw_device_t* raw_device = (LIBMTP_raw_device_t*)malloc(sizeof(LIBMTP_raw_device_t));
raw_device->device_entry.vendor = url.queryItemValue("vendor").toAscii().data();
raw_device->device_entry.product = url.queryItemValue("product").toAscii().data();
raw_device->device_entry.vendor_id = url.queryItemValue("vendor_id").toUShort();
raw_device->device_entry.product_id = url.queryItemValue("product_id").toUShort();
raw_device->device_entry.device_flags = url.queryItemValue("quirks").toUInt();
raw_device->bus_location = bus_location;
raw_device->devnum = device_num;
qDebug() << "\\o/" << url;
device_ = LIBMTP_Open_Raw_Device(raw_device);
return;
}
// Get a list of devices from libmtp and figure out which one is ours
int count = 0;
LIBMTP_raw_device_t* raw_devices = NULL;

View File

@ -17,13 +17,13 @@
#ifndef MTPCONNECTION_H
#define MTPCONNECTION_H
#include <QString>
#include <QUrl>
#include <libmtp.h>
class MtpConnection {
public:
MtpConnection(const QString& hostname);
MtpConnection(const QUrl& url);
~MtpConnection();
bool is_valid() const { return device_; }

View File

@ -47,7 +47,7 @@ void MtpDevice::Init() {
InitBackendDirectory("/", first_time_, false);
model_->Init();
loader_ = new MtpLoader(url_.host(), manager_->task_manager(), backend_,
loader_ = new MtpLoader(url_, manager_->task_manager(), backend_,
shared_from_this());
loader_->moveToThread(loader_thread_);

View File

@ -23,11 +23,11 @@
#include <libmtp.h>
MtpLoader::MtpLoader(const QString& hostname, TaskManager* task_manager,
MtpLoader::MtpLoader(const QUrl& url, TaskManager* task_manager,
LibraryBackend* backend, boost::shared_ptr<ConnectedDevice> device)
: QObject(NULL),
device_(device),
hostname_(hostname),
url_(url),
task_manager_(task_manager),
backend_(backend)
{
@ -50,7 +50,7 @@ void MtpLoader::LoadDatabase() {
}
bool MtpLoader::TryLoad() {
MtpConnection dev(hostname_);
MtpConnection dev(url_);
if (!dev.is_valid()) {
emit Error(tr("Error connecting MTP device"));
return false;
@ -65,7 +65,7 @@ bool MtpLoader::TryLoad() {
Song song;
song.InitFromMTP(track);
song.set_directory_id(1);
song.set_filename("mtp://" + hostname_ + "/" + song.filename());
song.set_filename("mtp://" + url_.host() + "/" + song.filename());
songs << song;
tracks = tracks->next;

View File

@ -18,6 +18,7 @@
#define MTPLOADER_H
#include <QObject>
#include <QUrl>
#include <boost/shared_ptr.hpp>
@ -29,7 +30,7 @@ class MtpLoader : public QObject {
Q_OBJECT
public:
MtpLoader(const QString& hostname, TaskManager* task_manager,
MtpLoader(const QUrl& url, TaskManager* task_manager,
LibraryBackend* backend, boost::shared_ptr<ConnectedDevice> device);
~MtpLoader();
@ -48,7 +49,7 @@ private:
boost::shared_ptr<ConnectedDevice> device_;
QThread* original_thread_;
QString hostname_;
QUrl url_;
TaskManager* task_manager_;
LibraryBackend* backend_;
};