mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Speed up device detection on windows. Difference will be noticeable for all the EB600 clones in particular
This commit is contained in:
parent
0496407296
commit
f061a40650
@ -37,6 +37,10 @@ def debug(ioreg_to_tmp=False, buf=None):
|
|||||||
if buf is None:
|
if buf is None:
|
||||||
buf = StringIO()
|
buf = StringIO()
|
||||||
sys.stdout = sys.stderr = buf
|
sys.stdout = sys.stderr = buf
|
||||||
|
if iswindows:
|
||||||
|
import pythoncom
|
||||||
|
pythoncom.CoInitialize()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
out = partial(prints, file=buf)
|
out = partial(prints, file=buf)
|
||||||
out('Version:', __version__)
|
out('Version:', __version__)
|
||||||
@ -50,16 +54,14 @@ def debug(ioreg_to_tmp=False, buf=None):
|
|||||||
d[i] = hex(d[i])
|
d[i] = hex(d[i])
|
||||||
out('USB devices on system:')
|
out('USB devices on system:')
|
||||||
out(pprint.pformat(devices))
|
out(pprint.pformat(devices))
|
||||||
|
wmi = Wmi =None
|
||||||
if iswindows:
|
if iswindows:
|
||||||
if iswindows:
|
|
||||||
import pythoncom
|
|
||||||
pythoncom.CoInitialize()
|
|
||||||
try:
|
|
||||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||||
|
Wmi = wmi.WMI(find_classes=False)
|
||||||
drives = []
|
drives = []
|
||||||
out('Drives detected:')
|
out('Drives detected:')
|
||||||
out('\t', '(ID, Partitions, Drive letter)')
|
out('\t', '(ID, Partitions, Drive letter)')
|
||||||
for drive in wmi.WMI(find_classes=False).Win32_DiskDrive():
|
for drive in Wmi.Win32_DiskDrive():
|
||||||
if drive.Partitions == 0:
|
if drive.Partitions == 0:
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
@ -71,8 +73,6 @@ def debug(ioreg_to_tmp=False, buf=None):
|
|||||||
drives.append((str(drive.PNPDeviceID), 'No mount points found'))
|
drives.append((str(drive.PNPDeviceID), 'No mount points found'))
|
||||||
for drive in drives:
|
for drive in drives:
|
||||||
out('\t', drive)
|
out('\t', drive)
|
||||||
finally:
|
|
||||||
pythoncom.CoUninitialize()
|
|
||||||
|
|
||||||
ioreg = None
|
ioreg = None
|
||||||
if isosx:
|
if isosx:
|
||||||
@ -81,17 +81,26 @@ def debug(ioreg_to_tmp=False, buf=None):
|
|||||||
ioreg = Device.run_ioreg()
|
ioreg = Device.run_ioreg()
|
||||||
ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg
|
ioreg = 'Output from mount:\n\n'+mount+'\n\n'+ioreg
|
||||||
connected_devices = []
|
connected_devices = []
|
||||||
|
s.wmi = Wmi
|
||||||
for dev in device_plugins():
|
for dev in device_plugins():
|
||||||
|
owmi = getattr(dev, 'wmi', None)
|
||||||
|
dev.wmi = Wmi
|
||||||
out('Looking for', dev.__class__.__name__)
|
out('Looking for', dev.__class__.__name__)
|
||||||
connected, det = s.is_device_connected(dev, debug=True)
|
connected, det = s.is_device_connected(dev, debug=True)
|
||||||
if connected:
|
if connected:
|
||||||
connected_devices.append((dev, det))
|
connected_devices.append((dev, det))
|
||||||
|
dev.wmi = owmi
|
||||||
|
|
||||||
errors = {}
|
errors = {}
|
||||||
success = False
|
success = False
|
||||||
|
out('Devices possibly connected:', end=' ')
|
||||||
for dev, det in connected_devices:
|
for dev, det in connected_devices:
|
||||||
out('Device possibly connected:', dev.__class__.name)
|
out(dev.name, end=', ')
|
||||||
out('Trying to open device...', end=' ')
|
out(' ')
|
||||||
|
for dev, det in connected_devices:
|
||||||
|
out('Trying to open', dev.name, '...', end=' ')
|
||||||
|
owmi = getattr(dev, 'wmi', None)
|
||||||
|
dev.wmi = Wmi
|
||||||
try:
|
try:
|
||||||
dev.reset(detected_device=det)
|
dev.reset(detected_device=det)
|
||||||
dev.open()
|
dev.open()
|
||||||
@ -101,6 +110,8 @@ def debug(ioreg_to_tmp=False, buf=None):
|
|||||||
errors[dev] = traceback.format_exc()
|
errors[dev] = traceback.format_exc()
|
||||||
out('failed')
|
out('failed')
|
||||||
continue
|
continue
|
||||||
|
finally:
|
||||||
|
dev.wmi = owmi
|
||||||
success = True
|
success = True
|
||||||
if hasattr(dev, '_main_prefix'):
|
if hasattr(dev, '_main_prefix'):
|
||||||
out('Main memory:', repr(dev._main_prefix))
|
out('Main memory:', repr(dev._main_prefix))
|
||||||
@ -128,4 +139,7 @@ def debug(ioreg_to_tmp=False, buf=None):
|
|||||||
finally:
|
finally:
|
||||||
sys.stdout = oldo
|
sys.stdout = oldo
|
||||||
sys.stderr = olde
|
sys.stderr = olde
|
||||||
|
if iswindows:
|
||||||
|
import pythoncom
|
||||||
|
pythoncom.CoUninitialize()
|
||||||
|
|
||||||
|
@ -43,8 +43,7 @@ class DevicePlugin(Plugin):
|
|||||||
#: Icon for this device
|
#: Icon for this device
|
||||||
icon = I('reader.svg')
|
icon = I('reader.svg')
|
||||||
|
|
||||||
@classmethod
|
def test_bcd_windows(self, device_id, bcd):
|
||||||
def test_bcd_windows(cls, device_id, bcd):
|
|
||||||
if bcd is None or len(bcd) == 0:
|
if bcd is None or len(bcd) == 0:
|
||||||
return True
|
return True
|
||||||
for c in bcd:
|
for c in bcd:
|
||||||
@ -54,30 +53,28 @@ class DevicePlugin(Plugin):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
def print_usb_device_info(self, info):
|
||||||
def print_usb_device_info(cls, info):
|
|
||||||
try:
|
try:
|
||||||
print '\t', repr(info)
|
print '\t', repr(info)
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
@classmethod
|
def is_usb_connected_windows(self, devices_on_system, pnp_id_iterator, debug=False):
|
||||||
def is_usb_connected_windows(cls, devices_on_system, debug=False):
|
|
||||||
|
|
||||||
def id_iterator():
|
def id_iterator():
|
||||||
if hasattr(cls.VENDOR_ID, 'keys'):
|
if hasattr(self.VENDOR_ID, 'keys'):
|
||||||
for vid in cls.VENDOR_ID:
|
for vid in self.VENDOR_ID:
|
||||||
vend = cls.VENDOR_ID[vid]
|
vend = self.VENDOR_ID[vid]
|
||||||
for pid in vend:
|
for pid in vend:
|
||||||
bcd = vend[pid]
|
bcd = vend[pid]
|
||||||
yield vid, pid, bcd
|
yield vid, pid, bcd
|
||||||
else:
|
else:
|
||||||
vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
|
vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
|
||||||
products = cls.PRODUCT_ID if hasattr(cls.PRODUCT_ID, '__len__') else [cls.PRODUCT_ID]
|
products = self.PRODUCT_ID if hasattr(self.PRODUCT_ID, '__len__') else [self.PRODUCT_ID]
|
||||||
for vid in vendors:
|
for vid in vendors:
|
||||||
for pid in products:
|
for pid in products:
|
||||||
yield vid, pid, cls.BCD
|
yield vid, pid, self.BCD
|
||||||
|
|
||||||
for vendor_id, product_id, bcd in id_iterator():
|
for vendor_id, product_id, bcd in id_iterator():
|
||||||
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
|
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
|
||||||
@ -85,15 +82,14 @@ class DevicePlugin(Plugin):
|
|||||||
for device_id in devices_on_system:
|
for device_id in devices_on_system:
|
||||||
if (vid in device_id or vidd in device_id) and \
|
if (vid in device_id or vidd in device_id) and \
|
||||||
(pid in device_id or pidd in device_id) and \
|
(pid in device_id or pidd in device_id) and \
|
||||||
cls.test_bcd_windows(device_id, bcd):
|
self.test_bcd_windows(device_id, bcd):
|
||||||
if debug:
|
if debug:
|
||||||
cls.print_usb_device_info(device_id)
|
self.print_usb_device_info(device_id)
|
||||||
if cls.can_handle(device_id):
|
if self.can_handle_windows(device_id, pnp_id_iterator, debug=debug):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
def test_bcd(self, bcdDevice, bcd):
|
||||||
def test_bcd(cls, bcdDevice, bcd):
|
|
||||||
if bcd is None or len(bcd) == 0:
|
if bcd is None or len(bcd) == 0:
|
||||||
return True
|
return True
|
||||||
for c in bcd:
|
for c in bcd:
|
||||||
@ -101,24 +97,24 @@ class DevicePlugin(Plugin):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@classmethod
|
def is_usb_connected(self, devices_on_system, pnp_id_iterator, debug=False):
|
||||||
def is_usb_connected(cls, devices_on_system, debug=False):
|
|
||||||
'''
|
'''
|
||||||
Return True, device_info if a device handled by this plugin is currently connected.
|
Return True, device_info if a device handled by this plugin is currently connected.
|
||||||
|
|
||||||
:param devices_on_system: List of devices currently connected
|
:param devices_on_system: List of devices currently connected
|
||||||
'''
|
'''
|
||||||
if iswindows:
|
if iswindows:
|
||||||
return cls.is_usb_connected_windows(devices_on_system, debug=debug), None
|
return self.is_usb_connected_windows(devices_on_system,
|
||||||
|
pnp_id_iterator, debug=debug), None
|
||||||
|
|
||||||
vendors_on_system = set([x[0] for x in devices_on_system])
|
vendors_on_system = set([x[0] for x in devices_on_system])
|
||||||
vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
|
vendors = self.VENDOR_ID if hasattr(self.VENDOR_ID, '__len__') else [self.VENDOR_ID]
|
||||||
if hasattr(cls.VENDOR_ID, 'keys'):
|
if hasattr(self.VENDOR_ID, 'keys'):
|
||||||
products = []
|
products = []
|
||||||
for ven in cls.VENDOR_ID:
|
for ven in self.VENDOR_ID:
|
||||||
products.extend(cls.VENDOR_ID[ven].keys())
|
products.extend(self.VENDOR_ID[ven].keys())
|
||||||
else:
|
else:
|
||||||
products = cls.PRODUCT_ID if hasattr(cls.PRODUCT_ID, '__len__') else [cls.PRODUCT_ID]
|
products = self.PRODUCT_ID if hasattr(self.PRODUCT_ID, '__len__') else [self.PRODUCT_ID]
|
||||||
|
|
||||||
for vid in vendors:
|
for vid in vendors:
|
||||||
if vid in vendors_on_system:
|
if vid in vendors_on_system:
|
||||||
@ -126,14 +122,14 @@ class DevicePlugin(Plugin):
|
|||||||
cvid, pid, bcd = dev[:3]
|
cvid, pid, bcd = dev[:3]
|
||||||
if cvid == vid:
|
if cvid == vid:
|
||||||
if pid in products:
|
if pid in products:
|
||||||
if hasattr(cls.VENDOR_ID, 'keys'):
|
if hasattr(self.VENDOR_ID, 'keys'):
|
||||||
cbcd = cls.VENDOR_ID[vid][pid]
|
cbcd = self.VENDOR_ID[vid][pid]
|
||||||
else:
|
else:
|
||||||
cbcd = cls.BCD
|
cbcd = self.BCD
|
||||||
if cls.test_bcd(bcd, cbcd):
|
if self.test_bcd(bcd, cbcd):
|
||||||
if debug:
|
if debug:
|
||||||
cls.print_usb_device_info(dev)
|
self.print_usb_device_info(dev)
|
||||||
if cls.can_handle(dev, debug=debug):
|
if self.can_handle(dev, debug=debug):
|
||||||
return True, dev
|
return True, dev
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
@ -151,25 +147,30 @@ class DevicePlugin(Plugin):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@classmethod
|
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
|
||||||
def get_fdi(cls):
|
|
||||||
'''Return the FDI description of this device for HAL on linux.'''
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def can_handle(cls, device_info, debug=False):
|
|
||||||
'''
|
'''
|
||||||
Optional method to perform further checks on a device to see if this driver
|
Optional method to perform further checks on a device to see if this driver
|
||||||
is capable of handling it. If it is not it should return False. This method
|
is capable of handling it. If it is not it should return False. This method
|
||||||
is only called after the vendor, product ids and the bcd have matched, so
|
is only called after the vendor, product ids and the bcd have matched, so
|
||||||
it can do some relatively time intensive checks. The default implementation
|
it can do some relatively time intensive checks. The default implementation
|
||||||
returns True.
|
returns True. This method is called only on windows. See also
|
||||||
|
:method:`can_handle`.
|
||||||
|
|
||||||
:param device_info: On windows a device ID string. On Unix a tuple of
|
:param device_info: On windows a device ID string. On Unix a tuple of
|
||||||
``(vendor_id, product_id, bcd)``.
|
``(vendor_id, product_id, bcd)``.
|
||||||
'''
|
'''
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def can_handle(self, device_info, debug=False):
|
||||||
|
'''
|
||||||
|
Unix version of :method:`can_handle_windows`
|
||||||
|
|
||||||
|
:param device_info: Is a tupe of (vid, pid, bcd, manufacturer, product,
|
||||||
|
serial number)
|
||||||
|
'''
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
'''
|
'''
|
||||||
Perform any device specific initialization. Called after the device is
|
Perform any device specific initialization. Called after the device is
|
||||||
|
@ -197,15 +197,15 @@ def main():
|
|||||||
command = args[0]
|
command = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
dev = None
|
dev = None
|
||||||
_wmi = None
|
scanner = DeviceScanner()
|
||||||
if iswindows:
|
if iswindows:
|
||||||
import wmi, pythoncom
|
import wmi, pythoncom
|
||||||
pythoncom.CoInitialize()
|
pythoncom.CoInitialize()
|
||||||
_wmi = wmi.WMI()
|
scanner.wmi = wmi.WMI(find_classes=False)
|
||||||
scanner = DeviceScanner(_wmi)
|
|
||||||
scanner.scan()
|
scanner.scan()
|
||||||
connected_devices = []
|
connected_devices = []
|
||||||
for d in device_plugins():
|
for d in device_plugins():
|
||||||
|
d.wmi = scanner.wmi
|
||||||
ok, det = scanner.is_device_connected(d)
|
ok, det = scanner.is_device_connected(d)
|
||||||
if ok:
|
if ok:
|
||||||
dev = d
|
dev = d
|
||||||
|
@ -85,13 +85,26 @@ class DeviceScanner(object):
|
|||||||
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
|
raise RuntimeError('DeviceScanner requires the /sys filesystem to work.')
|
||||||
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
|
self.scanner = win_scanner if iswindows else osx_scanner if isosx else linux_scanner
|
||||||
self.devices = []
|
self.devices = []
|
||||||
|
self.wmi = None
|
||||||
|
self.pnp_ids = set([])
|
||||||
|
self.rescan_pnp_ids = True
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
'''Fetch list of connected USB devices from operating system'''
|
'''Fetch list of connected USB devices from operating system'''
|
||||||
self.devices = self.scanner()
|
self.devices = self.scanner()
|
||||||
|
if self.rescan_pnp_ids:
|
||||||
|
self.pnp_ids = set([])
|
||||||
|
|
||||||
|
def pnp_id_iterator(self):
|
||||||
|
if self.wmi is not None and not self.pnp_ids:
|
||||||
|
for drive in self.wmi.Win32_DiskDrive():
|
||||||
|
if drive.Partitions > 0:
|
||||||
|
self.pnp_ids.add(str(drive.PNPDeviceID))
|
||||||
|
for x in self.pnp_ids:
|
||||||
|
yield x
|
||||||
|
|
||||||
def is_device_connected(self, device, debug=False):
|
def is_device_connected(self, device, debug=False):
|
||||||
return device.is_usb_connected(self.devices, debug=debug)
|
return device.is_usb_connected(self.devices, self.pnp_id_iterator, debug=debug)
|
||||||
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
|
@ -22,7 +22,7 @@ from itertools import repeat
|
|||||||
from calibre.devices.interface import DevicePlugin
|
from calibre.devices.interface import DevicePlugin
|
||||||
from calibre.devices.errors import DeviceError, FreeSpaceError
|
from calibre.devices.errors import DeviceError, FreeSpaceError
|
||||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
||||||
from calibre.constants import iswindows, islinux, isosx, __appname__, plugins
|
from calibre.constants import iswindows, islinux, isosx, plugins
|
||||||
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
|
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
|
||||||
|
|
||||||
if isosx:
|
if isosx:
|
||||||
@ -83,53 +83,6 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
EBOOK_DIR_CARD_B = ''
|
EBOOK_DIR_CARD_B = ''
|
||||||
DELETE_EXTS = []
|
DELETE_EXTS = []
|
||||||
|
|
||||||
FDI_TEMPLATE = \
|
|
||||||
'''
|
|
||||||
<device>
|
|
||||||
<match key="info.category" string="volume">
|
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
|
||||||
%(BCD_start)s
|
|
||||||
<match key="@info.parent:storage.lun" int="%(lun0)d">
|
|
||||||
<merge key="volume.label" type="string">%(main_memory)s</merge>
|
|
||||||
<merge key="%(app)s.mainvolume" type="string">%(deviceclass)s</merge>
|
|
||||||
</match>
|
|
||||||
%(BCD_end)s
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</device>
|
|
||||||
<device>
|
|
||||||
<match key="info.category" string="volume">
|
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
|
||||||
%(BCD_start)s
|
|
||||||
<match key="@info.parent:storage.lun" int="%(lun1)d">
|
|
||||||
<merge key="volume.label" type="string">%(storage_card)s</merge>
|
|
||||||
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
|
|
||||||
</match>
|
|
||||||
%(BCD_end)s
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</device>
|
|
||||||
<device>
|
|
||||||
<match key="info.category" string="volume">
|
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="%(vendor_id)s">
|
|
||||||
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="%(product_id)s">
|
|
||||||
%(BCD_start)s
|
|
||||||
<match key="@info.parent:storage.lun" int="%(lun2)d">
|
|
||||||
<merge key="volume.label" type="string">%(storage_card)s</merge>
|
|
||||||
<merge key="%(app)s.cardvolume" type="string">%(deviceclass)s</merge>
|
|
||||||
</match>
|
|
||||||
%(BCD_end)s
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</device>
|
|
||||||
'''
|
|
||||||
FDI_LUNS = {'lun0':0, 'lun1':1, 'lun2':2}
|
|
||||||
FDI_BCD_TEMPLATE = '<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.device_revision_bcd" int="%(bcd)s">'
|
|
||||||
|
|
||||||
def reset(self, key='-1', log_packets=False, report_progress=None,
|
def reset(self, key='-1', log_packets=False, report_progress=None,
|
||||||
detected_device=None):
|
detected_device=None):
|
||||||
@ -138,6 +91,7 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
self.detected_device = USBDevice(detected_device)
|
self.detected_device = USBDevice(detected_device)
|
||||||
except: # On windows detected_device is None
|
except: # On windows detected_device is None
|
||||||
self.detected_device = None
|
self.detected_device = None
|
||||||
|
self.set_progress_reporter(report_progress)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_gui_name(cls):
|
def get_gui_name(cls):
|
||||||
@ -146,37 +100,11 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
x = cls.__name__
|
x = cls.__name__
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_fdi(cls):
|
|
||||||
fdi = ''
|
|
||||||
for vid in cls.VENDOR_ID:
|
|
||||||
for pid in cls.PRODUCT_ID:
|
|
||||||
fdi_base_values = dict(
|
|
||||||
app=__appname__,
|
|
||||||
deviceclass=cls.__name__,
|
|
||||||
vendor_id=hex(vid),
|
|
||||||
product_id=hex(pid),
|
|
||||||
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
|
|
||||||
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
|
|
||||||
)
|
|
||||||
fdi_base_values.update(cls.FDI_LUNS)
|
|
||||||
|
|
||||||
if cls.BCD is None:
|
|
||||||
fdi_base_values['BCD_start'] = ''
|
|
||||||
fdi_base_values['BCD_end'] = ''
|
|
||||||
fdi += cls.FDI_TEMPLATE % fdi_base_values
|
|
||||||
else:
|
|
||||||
for bcd in cls.BCD:
|
|
||||||
fdi_bcd_values = fdi_base_values
|
|
||||||
fdi_bcd_values['BCD_start'] = cls.FDI_BCD_TEMPLATE % dict(bcd=hex(bcd))
|
|
||||||
fdi_bcd_values['BCD_end'] = '</match>'
|
|
||||||
fdi += cls.FDI_TEMPLATE % fdi_bcd_values
|
|
||||||
|
|
||||||
return fdi
|
|
||||||
|
|
||||||
def set_progress_reporter(self, report_progress):
|
def set_progress_reporter(self, report_progress):
|
||||||
self.report_progress = report_progress
|
self.report_progress = report_progress
|
||||||
|
self.report_progress = report_progress
|
||||||
|
if self.report_progress is None:
|
||||||
|
self.report_progress = lambda x, y: x
|
||||||
|
|
||||||
def card_prefix(self, end_session=True):
|
def card_prefix(self, end_session=True):
|
||||||
return (self._card_a_prefix, self._card_b_prefix)
|
return (self._card_a_prefix, self._card_b_prefix)
|
||||||
@ -239,9 +167,7 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
def windows_filter_pnp_id(self, pnp_id):
|
def windows_filter_pnp_id(self, pnp_id):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def windows_match_device(self, drive, attr):
|
def windows_match_device(self, pnp_id, attr):
|
||||||
pnp_id = (str(drive.PNPDeviceID) if not isinstance(drive, basestring)
|
|
||||||
else str(drive)).upper()
|
|
||||||
device_id = getattr(self, attr)
|
device_id = getattr(self, attr)
|
||||||
|
|
||||||
def test_vendor():
|
def test_vendor():
|
||||||
@ -292,6 +218,12 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
'''
|
'''
|
||||||
return drives
|
return drives
|
||||||
|
|
||||||
|
def can_handle_windows(self, device_id, pnp_id_iterator, debug=False):
|
||||||
|
for pnp_id in pnp_id_iterator():
|
||||||
|
if self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
def open_windows(self):
|
def open_windows(self):
|
||||||
|
|
||||||
def matches_q(drive, attr):
|
def matches_q(drive, attr):
|
||||||
@ -307,14 +239,14 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
time.sleep(8)
|
time.sleep(8)
|
||||||
drives = {}
|
drives = {}
|
||||||
wmi = __import__('wmi', globals(), locals(), [], -1)
|
c = self.wmi
|
||||||
c = wmi.WMI(find_classes=False)
|
|
||||||
for drive in c.Win32_DiskDrive():
|
for drive in c.Win32_DiskDrive():
|
||||||
if self.windows_match_device(drive, 'WINDOWS_CARD_A_MEM') and not drives.get('carda', None):
|
pnp_id = str(drive.PNPDeviceID)
|
||||||
|
if self.windows_match_device(pnp_id, 'WINDOWS_CARD_A_MEM') and not drives.get('carda', None):
|
||||||
drives['carda'] = self.windows_get_drive_prefix(drive)
|
drives['carda'] = self.windows_get_drive_prefix(drive)
|
||||||
elif self.windows_match_device(drive, 'WINDOWS_CARD_B_MEM') and not drives.get('cardb', None):
|
elif self.windows_match_device(pnp_id, 'WINDOWS_CARD_B_MEM') and not drives.get('cardb', None):
|
||||||
drives['cardb'] = self.windows_get_drive_prefix(drive)
|
drives['cardb'] = self.windows_get_drive_prefix(drive)
|
||||||
elif self.windows_match_device(drive, 'WINDOWS_MAIN_MEM') and not drives.get('main', None):
|
elif self.windows_match_device(pnp_id, 'WINDOWS_MAIN_MEM') and not drives.get('main', None):
|
||||||
drives['main'] = self.windows_get_drive_prefix(drive)
|
drives['main'] = self.windows_get_drive_prefix(drive)
|
||||||
|
|
||||||
if 'main' in drives.keys() and 'carda' in drives.keys() and \
|
if 'main' in drives.keys() and 'carda' in drives.keys() and \
|
||||||
|
@ -72,15 +72,12 @@ class DeviceManager(Thread):
|
|||||||
|
|
||||||
def __init__(self, connected_slot, job_manager, sleep_time=2):
|
def __init__(self, connected_slot, job_manager, sleep_time=2):
|
||||||
'''
|
'''
|
||||||
@param sleep_time: Time to sleep between device probes in secs
|
:sleep_time: Time to sleep between device probes in secs
|
||||||
@type sleep_time: integer
|
|
||||||
'''
|
'''
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.setDaemon(True)
|
self.setDaemon(True)
|
||||||
# [Device driver, Showing in GUI, Ejected]
|
# [Device driver, Showing in GUI, Ejected]
|
||||||
self.devices = [[d, False, False] for d in device_plugins()]
|
self.devices = list(device_plugins())
|
||||||
self.device = None
|
|
||||||
self.device_class = None
|
|
||||||
self.sleep_time = sleep_time
|
self.sleep_time = sleep_time
|
||||||
self.connected_slot = connected_slot
|
self.connected_slot = connected_slot
|
||||||
self.jobs = Queue.Queue(0)
|
self.jobs = Queue.Queue(0)
|
||||||
@ -88,41 +85,37 @@ class DeviceManager(Thread):
|
|||||||
self.job_manager = job_manager
|
self.job_manager = job_manager
|
||||||
self.current_job = None
|
self.current_job = None
|
||||||
self.scanner = DeviceScanner()
|
self.scanner = DeviceScanner()
|
||||||
|
self.wmi = None
|
||||||
|
self.connected_device = None
|
||||||
|
self.ejected_devices = set([])
|
||||||
|
|
||||||
|
def report_progress(self, *args):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_device_connected(self):
|
||||||
|
return self.connected_device is not None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device(self):
|
||||||
|
return self.connected_device
|
||||||
|
|
||||||
def do_connect(self, connected_devices):
|
def do_connect(self, connected_devices):
|
||||||
if iswindows:
|
|
||||||
import pythoncom
|
|
||||||
pythoncom.CoInitialize()
|
|
||||||
try:
|
|
||||||
for dev, detected_device in connected_devices:
|
for dev, detected_device in connected_devices:
|
||||||
dev.reset(detected_device=detected_device)
|
dev.reset(detected_device=detected_device,
|
||||||
|
report_progress=self.report_progress)
|
||||||
try:
|
try:
|
||||||
dev.open()
|
dev.open()
|
||||||
except:
|
except:
|
||||||
print 'Unable to open device', dev
|
print 'Unable to open device', dev
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
continue
|
||||||
self.device = dev
|
self.connected_device = dev
|
||||||
self.device_class = dev.__class__
|
|
||||||
self.connected_slot(True)
|
self.connected_slot(True)
|
||||||
return True
|
return True
|
||||||
finally:
|
|
||||||
if iswindows:
|
|
||||||
pythoncom.CoUninitialize()
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def connected_device_removed(self):
|
||||||
def detect_device(self):
|
|
||||||
self.scanner.scan()
|
|
||||||
connected_devices = []
|
|
||||||
for device in self.devices:
|
|
||||||
connected, detected_device = self.scanner.is_device_connected(device[0])
|
|
||||||
if connected and not device[1] and not device[2]:
|
|
||||||
# If connected and not showing in GUI and not ejected
|
|
||||||
connected_devices.append((device[0], detected_device))
|
|
||||||
device[1] = True
|
|
||||||
elif not connected and device[1]:
|
|
||||||
# Disconnected but showing in GUI
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
job = self.jobs.get_nowait()
|
job = self.jobs.get_nowait()
|
||||||
@ -130,33 +123,45 @@ class DeviceManager(Thread):
|
|||||||
except Queue.Empty:
|
except Queue.Empty:
|
||||||
break
|
break
|
||||||
try:
|
try:
|
||||||
self.device.post_yank_cleanup()
|
self.connected_device.post_yank_cleanup()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
device[2] = False
|
if self.connected_device in self.ejected_devices:
|
||||||
self.device = None
|
self.ejected_devices.remove(self.connected_device)
|
||||||
|
else:
|
||||||
self.connected_slot(False)
|
self.connected_slot(False)
|
||||||
device[1] ^= True
|
self.connected_device = None
|
||||||
if connected_devices:
|
|
||||||
if not self.do_connect(connected_devices):
|
def detect_device(self):
|
||||||
|
self.scanner.rescan_pnp_ids = not self.is_device_connected
|
||||||
|
self.scanner.scan()
|
||||||
|
if self.is_device_connected:
|
||||||
|
connected, detected_device = \
|
||||||
|
self.scanner.is_device_connected(self.connected_device)
|
||||||
|
if not connected:
|
||||||
|
self.connected_device_removed()
|
||||||
|
else:
|
||||||
|
possibly_connected_devices = []
|
||||||
|
for device in self.devices:
|
||||||
|
if device in self.ejected_devices:
|
||||||
|
continue
|
||||||
|
possibly_connected, detected_device = \
|
||||||
|
self.scanner.is_device_connected(device)
|
||||||
|
if possibly_connected:
|
||||||
|
possibly_connected_devices.append((device, detected_device))
|
||||||
|
if possibly_connected_devices:
|
||||||
|
if not self.do_connect(possibly_connected_devices):
|
||||||
print 'Connect to device failed, retying in 5 seconds...'
|
print 'Connect to device failed, retying in 5 seconds...'
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
if not self.do_connect(connected_devices):
|
if not self.do_connect(possibly_connected_devices):
|
||||||
print 'Device connect failed again, giving up'
|
print 'Device connect failed again, giving up'
|
||||||
|
|
||||||
def umount_device(self):
|
def umount_device(self):
|
||||||
if self.device is not None:
|
if self.is_device_connected:
|
||||||
self.device.eject()
|
self.connected_device.eject()
|
||||||
dev = None
|
self.ejected_devices.add(self.connected_device)
|
||||||
for x in self.devices:
|
|
||||||
if x[0] is self.device:
|
|
||||||
dev = x
|
|
||||||
break
|
|
||||||
if dev is not None:
|
|
||||||
dev[2] = True
|
|
||||||
self.connected_slot(False)
|
self.connected_slot(False)
|
||||||
|
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
if not self.jobs.empty():
|
if not self.jobs.empty():
|
||||||
try:
|
try:
|
||||||
@ -165,6 +170,15 @@ class DeviceManager(Thread):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
if iswindows:
|
||||||
|
import pythoncom
|
||||||
|
pythoncom.CoInitialize()
|
||||||
|
wmi = __import__('wmi', globals(), locals(), [], -1)
|
||||||
|
self.wmi = wmi.WMI(find_classes=False)
|
||||||
|
self.scanner.wmi = self.wmi
|
||||||
|
for x in self.devices:
|
||||||
|
x[0].wmi = self.wmi
|
||||||
|
try:
|
||||||
while self.keep_going:
|
while self.keep_going:
|
||||||
self.detect_device()
|
self.detect_device()
|
||||||
while True:
|
while True:
|
||||||
@ -177,6 +191,10 @@ class DeviceManager(Thread):
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
time.sleep(self.sleep_time)
|
time.sleep(self.sleep_time)
|
||||||
|
finally:
|
||||||
|
if iswindows:
|
||||||
|
pythoncom.CoUninitialize()
|
||||||
|
|
||||||
|
|
||||||
def create_job(self, func, done, description, args=[], kwargs={}):
|
def create_job(self, func, done, description, args=[], kwargs={}):
|
||||||
job = DeviceJob(func, done, self.job_manager,
|
job = DeviceJob(func, done, self.job_manager,
|
||||||
@ -495,7 +513,7 @@ class DeviceGUI(object):
|
|||||||
fmt = None
|
fmt = None
|
||||||
if specific:
|
if specific:
|
||||||
d = ChooseFormatDialog(self, _('Choose format to send to device'),
|
d = ChooseFormatDialog(self, _('Choose format to send to device'),
|
||||||
self.device_manager.device_class.settings().format_map)
|
self.device_manager.device.settings().format_map)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
fmt = d.format().lower()
|
fmt = d.format().lower()
|
||||||
dest, sub_dest = dest.split(':')
|
dest, sub_dest = dest.split(':')
|
||||||
@ -637,7 +655,7 @@ class DeviceGUI(object):
|
|||||||
p = QPixmap()
|
p = QPixmap()
|
||||||
p.loadFromData(data)
|
p.loadFromData(data)
|
||||||
if not p.isNull():
|
if not p.isNull():
|
||||||
ht = self.device_manager.device_class.THUMBNAIL_HEIGHT \
|
ht = self.device_manager.device.THUMBNAIL_HEIGHT \
|
||||||
if self.device_manager else DevicePlugin.THUMBNAIL_HEIGHT
|
if self.device_manager else DevicePlugin.THUMBNAIL_HEIGHT
|
||||||
p = p.scaledToHeight(ht, Qt.SmoothTransformation)
|
p = p.scaledToHeight(ht, Qt.SmoothTransformation)
|
||||||
return (p.width(), p.height(), pixmap_to_data(p))
|
return (p.width(), p.height(), pixmap_to_data(p))
|
||||||
@ -675,10 +693,11 @@ class DeviceGUI(object):
|
|||||||
|
|
||||||
def sync_news(self, send_ids=None, do_auto_convert=True):
|
def sync_news(self, send_ids=None, do_auto_convert=True):
|
||||||
if self.device_connected:
|
if self.device_connected:
|
||||||
|
settings = self.device_manager.device.settings()
|
||||||
ids = list(dynamic.get('news_to_be_synced', set([]))) if send_ids is None else send_ids
|
ids = list(dynamic.get('news_to_be_synced', set([]))) if send_ids is None else send_ids
|
||||||
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
|
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
|
||||||
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(
|
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(
|
||||||
ids, self.device_manager.device_class.settings().format_map,
|
ids, settings.format_map,
|
||||||
exclude_auto=do_auto_convert)
|
exclude_auto=do_auto_convert)
|
||||||
auto = []
|
auto = []
|
||||||
if do_auto_convert and _auto_ids:
|
if do_auto_convert and _auto_ids:
|
||||||
@ -687,12 +706,12 @@ class DeviceGUI(object):
|
|||||||
formats = [] if dbfmts is None else \
|
formats = [] if dbfmts is None else \
|
||||||
[f.lower() for f in dbfmts.split(',')]
|
[f.lower() for f in dbfmts.split(',')]
|
||||||
if set(formats).intersection(available_input_formats()) \
|
if set(formats).intersection(available_input_formats()) \
|
||||||
and set(self.device_manager.device_class.settings().format_map).intersection(available_output_formats()):
|
and set(settings.format_map).intersection(available_output_formats()):
|
||||||
auto.append(id)
|
auto.append(id)
|
||||||
if auto:
|
if auto:
|
||||||
format = None
|
format = None
|
||||||
for fmt in self.device_manager.device_class.settings().format_map:
|
for fmt in settings.format_map:
|
||||||
if fmt in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))):
|
if fmt in list(set(settings.format_map).intersection(set(available_output_formats()))):
|
||||||
format = fmt
|
format = fmt
|
||||||
break
|
break
|
||||||
if format is not None:
|
if format is not None:
|
||||||
@ -738,8 +757,10 @@ class DeviceGUI(object):
|
|||||||
if not self.device_manager or not ids or len(ids) == 0:
|
if not self.device_manager or not ids or len(ids) == 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
settings = self.device_manager.device.settings()
|
||||||
|
|
||||||
_files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids,
|
_files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(ids,
|
||||||
self.device_manager.device_class.settings().format_map,
|
settings.format_map,
|
||||||
paths=True, set_metadata=True,
|
paths=True, set_metadata=True,
|
||||||
specific_format=specific_format,
|
specific_format=specific_format,
|
||||||
exclude_auto=do_auto_convert)
|
exclude_auto=do_auto_convert)
|
||||||
@ -790,21 +811,21 @@ class DeviceGUI(object):
|
|||||||
formats = self.library_view.model().db.formats(id, index_is_id=True)
|
formats = self.library_view.model().db.formats(id, index_is_id=True)
|
||||||
formats = formats.split(',') if formats is not None else []
|
formats = formats.split(',') if formats is not None else []
|
||||||
formats = [f.lower().strip() for f in formats]
|
formats = [f.lower().strip() for f in formats]
|
||||||
if list(set(formats).intersection(available_input_formats())) != [] and list(set(self.device_manager.device_class.settings().format_map).intersection(available_output_formats())) != []:
|
if list(set(formats).intersection(available_input_formats())) != [] and list(set(settings.format_map).intersection(available_output_formats())) != []:
|
||||||
auto.append(id)
|
auto.append(id)
|
||||||
else:
|
else:
|
||||||
bad.append(self.library_view.model().db.title(id, index_is_id=True))
|
bad.append(self.library_view.model().db.title(id, index_is_id=True))
|
||||||
else:
|
else:
|
||||||
if specific_format in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))):
|
if specific_format in list(set(settings.format_map).intersection(set(available_output_formats()))):
|
||||||
auto.append(id)
|
auto.append(id)
|
||||||
else:
|
else:
|
||||||
bad.append(self.library_view.model().db.title(id, index_is_id=True))
|
bad.append(self.library_view.model().db.title(id, index_is_id=True))
|
||||||
|
|
||||||
if auto != []:
|
if auto != []:
|
||||||
format = specific_format if specific_format in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))) else None
|
format = specific_format if specific_format in list(set(settings.format_map).intersection(set(available_output_formats()))) else None
|
||||||
if not format:
|
if not format:
|
||||||
for fmt in self.device_manager.device_class.settings().format_map:
|
for fmt in settings.format_map:
|
||||||
if fmt in list(set(self.device_manager.device_class.settings().format_map).intersection(set(available_output_formats()))):
|
if fmt in list(set(settings.format_map).intersection(set(available_output_formats()))):
|
||||||
format = fmt
|
format = fmt
|
||||||
break
|
break
|
||||||
if not format:
|
if not format:
|
||||||
|
@ -840,11 +840,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
return
|
return
|
||||||
mainlist, cardalist, cardblist = job.result
|
mainlist, cardalist, cardblist = job.result
|
||||||
self.memory_view.set_database(mainlist)
|
self.memory_view.set_database(mainlist)
|
||||||
self.memory_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
|
self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
|
||||||
self.card_a_view.set_database(cardalist)
|
self.card_a_view.set_database(cardalist)
|
||||||
self.card_a_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
|
self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
|
||||||
self.card_b_view.set_database(cardblist)
|
self.card_b_view.set_database(cardblist)
|
||||||
self.card_b_view.set_editable(self.device_manager.device_class.CAN_SET_METADATA)
|
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
|
||||||
for view in (self.memory_view, self.card_a_view, self.card_b_view):
|
for view in (self.memory_view, self.card_a_view, self.card_b_view):
|
||||||
view.sortByColumn(3, Qt.DescendingOrder)
|
view.sortByColumn(3, Qt.DescendingOrder)
|
||||||
view.read_settings()
|
view.read_settings()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user