mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Device drivers: Allow one driver to handle devices from multiple vendors. Also allow device interface plugins to override the USB device detection code
This commit is contained in:
parent
6bf2b9fad8
commit
2f9f2439f0
@ -8,6 +8,7 @@ a backend that implement the Device interface for the SONY PRS500 Reader.
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from calibre.customize import Plugin
|
from calibre.customize import Plugin
|
||||||
|
from calibre.constants import iswindows
|
||||||
|
|
||||||
class DevicePlugin(Plugin):
|
class DevicePlugin(Plugin):
|
||||||
"""
|
"""
|
||||||
@ -22,7 +23,14 @@ class DevicePlugin(Plugin):
|
|||||||
|
|
||||||
# Ordered list of supported formats
|
# Ordered list of supported formats
|
||||||
FORMATS = ["lrf", "rtf", "pdf", "txt"]
|
FORMATS = ["lrf", "rtf", "pdf", "txt"]
|
||||||
|
#: VENDOR_ID can be either an integer, a list of integers or a dictionary
|
||||||
|
#: If it is a dictionary, it must be a dictionary of dictionaries, of the form
|
||||||
|
#: {
|
||||||
|
#: integer_vendor_id : { product_id : [list of BCDs], ... },
|
||||||
|
#: ...
|
||||||
|
#: }
|
||||||
VENDOR_ID = 0x0000
|
VENDOR_ID = 0x0000
|
||||||
|
#: An integer or a list of integers
|
||||||
PRODUCT_ID = 0x0000
|
PRODUCT_ID = 0x0000
|
||||||
# BCD can be either None to not distinguish between devices based on BCD, or
|
# BCD can be either None to not distinguish between devices based on BCD, or
|
||||||
# it can be a list of the BCD numbers of all devices supported by this driver.
|
# it can be a list of the BCD numbers of all devices supported by this driver.
|
||||||
@ -33,6 +41,85 @@ class DevicePlugin(Plugin):
|
|||||||
#: Path separator for paths to books on device
|
#: Path separator for paths to books on device
|
||||||
path_sep = os.sep
|
path_sep = os.sep
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def test_bcd_windows(cls, device_id, bcd):
|
||||||
|
if bcd is None or len(bcd) == 0:
|
||||||
|
return True
|
||||||
|
for c in bcd:
|
||||||
|
# Bug in winutil.get_usb_devices converts a to :
|
||||||
|
rev = ('rev_%4.4x'%c).replace('a', ':')
|
||||||
|
if rev in device_id:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_usb_connected_windows(cls, devices_on_system):
|
||||||
|
|
||||||
|
def id_iterator():
|
||||||
|
if hasattr(cls.VENDOR_ID, 'keys'):
|
||||||
|
for vid in cls.VENDOR_ID:
|
||||||
|
vend = cls.VENDOR_ID[vid]
|
||||||
|
for pid in vend:
|
||||||
|
bcd = vend[pid]
|
||||||
|
yield vid, pid, bcd
|
||||||
|
else:
|
||||||
|
vendors = cls.VENDOR_ID if hasattr(cls.VENDOR_ID, '__len__') else [cls.VENDOR_ID]
|
||||||
|
products = cls.PRODUCT_ID if hasattr(cls.PRODUCT_ID, '__len__') else [cls.PRODUCT_ID]
|
||||||
|
for vid in vendors:
|
||||||
|
for pid in products:
|
||||||
|
yield vid, pid, cls.BCD
|
||||||
|
|
||||||
|
for vendor_id, product_id, bcd in id_iterator():
|
||||||
|
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
|
||||||
|
vidd, pidd = 'vid_%i'%vendor_id, 'pid_%i'%product_id
|
||||||
|
for device_id in devices_on_system:
|
||||||
|
if (vid in device_id or vidd in device_id) and (pid in device_id or pidd in device_id):
|
||||||
|
if cls.test_bcd_windows(device_id, bcd) and cls.can_handle(device_id):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def test_bcd(cls, bcdDevice, bcd):
|
||||||
|
if bcd is None or len(bcd) == 0:
|
||||||
|
return True
|
||||||
|
for c in bcd:
|
||||||
|
if c == bcdDevice:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_usb_connected(cls, devices_on_system):
|
||||||
|
'''
|
||||||
|
Return True if a device handled by this plugin is currently connected.
|
||||||
|
|
||||||
|
:param devices_on_system: List of devices currently connected
|
||||||
|
'''
|
||||||
|
if iswindows:
|
||||||
|
return cls.is_usb_connected_windows(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]
|
||||||
|
if hasattr(cls.VENDOR_ID, 'keys'):
|
||||||
|
products = []
|
||||||
|
for ven in cls.VENDOR_ID:
|
||||||
|
products.extend(cls.VENDOR_ID[ven].keys())
|
||||||
|
else:
|
||||||
|
products = cls.PRODUCT_ID if hasattr(cls.PRODUCT_ID, '__len__') else [cls.PRODUCT_ID]
|
||||||
|
|
||||||
|
for vid in vendors:
|
||||||
|
if vid in vendors_on_system:
|
||||||
|
for cvid, pid, bcd in devices_on_system:
|
||||||
|
if cvid == vid:
|
||||||
|
if pid in products:
|
||||||
|
if hasattr(cls.VENDOR_ID, 'keys'):
|
||||||
|
cbcd = cls.VENDOR_ID[vid][pid]
|
||||||
|
else:
|
||||||
|
cbcd = cls.BCD
|
||||||
|
if cls.test_bcd(bcd, cbcd) and cls.can_handle((vid,
|
||||||
|
pid, bcd)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def reset(self, key='-1', log_packets=False, report_progress=None) :
|
def reset(self, key='-1', log_packets=False, report_progress=None) :
|
||||||
"""
|
"""
|
||||||
|
@ -67,44 +67,8 @@ class DeviceScanner(object):
|
|||||||
'''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()
|
||||||
|
|
||||||
def test_bcd_windows(self, device_id, bcd):
|
|
||||||
if bcd is None or len(bcd) == 0:
|
|
||||||
return True
|
|
||||||
for c in bcd:
|
|
||||||
# Bug in winutil.get_usb_devices converts a to :
|
|
||||||
rev = ('rev_%4.4x'%c).replace('a', ':')
|
|
||||||
if rev in device_id:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def test_bcd(self, bcdDevice, bcd):
|
|
||||||
if bcd is None or len(bcd) == 0:
|
|
||||||
return True
|
|
||||||
for c in bcd:
|
|
||||||
if c == bcdDevice:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_device_connected(self, device):
|
def is_device_connected(self, device):
|
||||||
vendor_ids = device.VENDOR_ID if hasattr(device.VENDOR_ID, '__len__') else [device.VENDOR_ID]
|
return device.is_usb_connected(self.devices)
|
||||||
product_ids = device.PRODUCT_ID if hasattr(device.PRODUCT_ID, '__len__') else [device.PRODUCT_ID]
|
|
||||||
if iswindows:
|
|
||||||
for vendor_id in vendor_ids:
|
|
||||||
for product_id in product_ids:
|
|
||||||
vid, pid = 'vid_%4.4x'%vendor_id, 'pid_%4.4x'%product_id
|
|
||||||
vidd, pidd = 'vid_%i'%vendor_id, 'pid_%i'%product_id
|
|
||||||
for device_id in self.devices:
|
|
||||||
if (vid in device_id or vidd in device_id) and (pid in device_id or pidd in device_id):
|
|
||||||
if self.test_bcd_windows(device_id, getattr(device, 'BCD', None)):
|
|
||||||
if device.can_handle(device_id):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
for vendor, product, bcdDevice in self.devices:
|
|
||||||
if vendor in vendor_ids and product in product_ids:
|
|
||||||
if self.test_bcd(bcdDevice, getattr(device, 'BCD', None)):
|
|
||||||
if device.can_handle((vendor, product, bcdDevice)):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
|
@ -211,8 +211,16 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
def windows_match_device(self, drive, attr):
|
def windows_match_device(self, drive, attr):
|
||||||
pnp_id = str(drive.PNPDeviceID).upper()
|
pnp_id = str(drive.PNPDeviceID).upper()
|
||||||
device_id = getattr(self, attr)
|
device_id = getattr(self, attr)
|
||||||
if device_id is None or \
|
|
||||||
'VEN_' + str(self.VENDOR_NAME).upper() not in pnp_id:
|
def test_vendor():
|
||||||
|
vendors = [self.VENDOR_NAME] if isinstance(self.VENDOR_NAME,
|
||||||
|
basestring) else self.VENDOR_NAME
|
||||||
|
for v in vendors:
|
||||||
|
if 'VEN_'+str(v).upper() in pnp_id:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
if device_id is None or not test_vendor():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if hasattr(device_id, 'search'):
|
if hasattr(device_id, 'search'):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user