Windows PRS505 support

This commit is contained in:
Kovid Goyal 2007-10-20 05:36:04 +00:00
parent 8d46e046d4
commit 4312aff2cf
8 changed files with 172 additions and 61 deletions

View File

@ -103,7 +103,7 @@ _check_symlinks_prescript()
else: else:
debug = 0 debug = 0
return find_modules( return find_modules(
scripts=scripts['console'] + scripts['gui'], scripts=scripts['console'] + scripts['gui'][1:],
includes=list(self.includes) + main_modules['console'], includes=list(self.includes) + main_modules['console'],
packages=self.packages, packages=self.packages,
excludes=self.excludes, excludes=self.excludes,

View File

@ -32,9 +32,10 @@ class TimeoutError(ProtocolError):
class DeviceError(ProtocolError): class DeviceError(ProtocolError):
""" Raised when device is not found """ """ Raised when device is not found """
def __init__(self): def __init__(self, msg=None):
ProtocolError.__init__(self, \ if msg is None:
"Unable to find SONY Reader. Is it connected?") msg = "Unable to find SONY Reader. Is it connected?"
ProtocolError.__init__(self, msg)
class DeviceBusy(ProtocolError): class DeviceBusy(ProtocolError):
""" Raised when device is busy """ """ Raised when device is busy """

View File

@ -46,8 +46,18 @@ class Device(object):
raise NotImplementedError() raise NotImplementedError()
@classmethod @classmethod
def is_connected(cls): def get_fdi(cls):
'''Return True iff the device is physically connected to the computer''' '''Return the FDI description of this device for HAL on linux.'''
return ''
@classmethod
def is_connected(cls, helper=None):
'''
Return True iff the device is physically connected to the computer
@param helper: Platform dependent helper object. For e.g. on windows
an instantiated WMI interface.
'''
raise NotImplementedError() raise NotImplementedError()
def set_progress_reporter(self, report_progress): def set_progress_reporter(self, report_progress):

View File

@ -18,11 +18,18 @@ import shutil
from libprs500.devices.interface import Device from libprs500.devices.interface import Device
from libprs500.devices.errors import DeviceError, FreeSpaceError from libprs500.devices.errors import DeviceError, FreeSpaceError
from libprs500.devices.prs500.books import BookList from libprs500.devices.prs500.books import BookList
from libprs500 import iswindows, islinux, isosx
if not iswindows:
from libprs500.devices.libusb import get_device_by_id
from libprs500 import islinux, iswindows
import sys, os import sys, os
try:
import _winreg
except ImportError:
pass
class File(object): class File(object):
def __init__(self, path): def __init__(self, path):
stats = os.stat(path) stats = os.stat(path)
@ -40,43 +47,117 @@ class File(object):
class PRS505(Device): class PRS505(Device):
VENDOR_ID = 0x054c #: SONY Vendor Id VENDOR_ID = 0x054c #: SONY Vendor Id
PRODUCT_ID = 0x031e #: Product Id for the PRS-505 PRODUCT_ID = 0x031e #: Product Id for the PRS-505
PRODUCT_NAME = 'Sony Portable Reader System' PRODUCT_NAME = 'PRS-505'
VENDOR_NAME = 'SONY'
MEDIA_XML = 'database/cache/media.xml' MEDIA_XML = 'database/cache/media.xml'
CACHE_XML = 'Sony Reader/database/cache.xml' CACHE_XML = 'Sony Reader/database/cache.xml'
LINUX_DEVICE_NODE = 'sony_prs_505' MAIN_MEMORY_VOLUME_LABEL = 'Sony Reader Main Memory'
LINUX_DEVICE_PATH = os.path.join('/dev', LINUX_DEVICE_NODE) STORAGE_CARD_VOLUME_LABEL = 'Sony Reader Storage Card'
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">
<match key="volume.is_partition" bool="false">
<merge key="volume.label" type="string">%(main_memory)s</merge>
<merge key="libprs500.mainvolume" type="string">%(deviceclass)s</merge>
</match>
</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">
<match key="volume.is_partition" bool="true">
<merge key="volume.label" type="string">%(storage_card)s</merge>
<merge key="libprs500.cardvolume" type="string">%(deviceclass)s</merge>
</match>
</match>
</match>
</match>
</device>
'''
def __init__(self): def __init__(self):
self._main_prefix = self._card_prefix = None self._main_prefix = self._card_prefix = None
self.hm = None
if islinux: @classmethod
import dbus def get_fdi(cls):
self.bus = dbus.SystemBus() return cls.FDI_TEMPLATE%dict(
self.hm = dbus.Interface(self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager") deviceclass=cls.__name__,
vendor_id=hex(cls.VENDOR_ID),
product_id=hex(cls.PRODUCT_ID),
main_memory=cls.MAIN_MEMORY_VOLUME_LABEL,
storage_card=cls.STORAGE_CARD_VOLUME_LABEL,
)
def is_connected(self): @classmethod
if self.hm is not None: # linux def is_device(cls, device_id):
devs = self.hm.FindDeviceStringMatch('info.product', 'Sony Portable Reader System') if 'VEN_'+cls.VENDOR_NAME in device_id.upper() and \
for dev in devs: 'PROD_'+cls.PRODUCT_NAME in device_id.upper():
obj = self.bus.get_object("org.freedesktop.Hal", dev) return True
if obj.GetPropertyInteger('usb_device.product_id', dbus_interface='org.freedesktop.Hal.Device') == self.__class__.PRODUCT_ID: vid, pid = hex(cls.VENDOR_ID)[2:], hex(cls.PRODUCT_ID)[2:]
return True if len(vid) < 4: vid = '0'+vid
if len(pid) < 4: pid = '0'+pid
if 'VID_'+vid in device_id.upper() and \
'PID_'+pid in device_id.upper():
return True
return False return False
@classmethod
def is_connected(cls, helper=None):
if iswindows:
for c in helper.USBControllerDevice():
if cls.is_device(c.Dependent.DeviceID):
return True
return False
else:
return get_device_by_id(cls.VENDOR_ID, cls.PRODUCT_ID) != None
def open_windows(self):
import wmi
c = wmi.WMI()
for drive in c.Win32_DiskDrive():
if self.__class__.is_device(drive.PNPDeviceID):
if drive.Partitions == 0:
continue
try:
partition = drive.associators("Win32_DiskDriveToDiskPartition")[0]
except IndexError:
continue
logical_disk = partition.associators('Win32_LogicalDiskToPartition')[0]
prefix = logical_disk.DeviceID+os.sep
if drive.Index == 1:
self._main_prefix = prefix
else:
self._card_prefix = prefix
if self._main_prefix is None:
raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,))
def open_linux(self): def open_linux(self):
import dbus
bus = dbus.SystemBus()
hm = dbus.Interface(self.bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
try: try:
mm = self.hm.FindDeviceStringMatch('volume.label', 'Sony Reader Main Memory')[0] mm = hm.FindDeviceStringMatch('libprs500.mainvolume', self.__class__.__name__)[0]
except: except:
raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,)) raise DeviceError('Unable to find %s. Is it connected?'%(self.__class__.__name__,))
try: try:
sc = self.hm.FindDeviceStringMatch('volume.label', 'Sony Reader Storage Card')[0] sc = hm.FindDeviceStringMatch('libprs500.cardvolume', self.__class__.__name__)[0]
except: except:
sc = None sc = None
def conditional_mount(dev): def conditional_mount(dev):
mmo = self.bus.get_object("org.freedesktop.Hal", dev) mmo = bus.get_object("org.freedesktop.Hal", dev)
label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device') label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device') is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device') mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
@ -93,8 +174,10 @@ class PRS505(Device):
self._card_prefix = conditional_mount(sc)+os.sep self._card_prefix = conditional_mount(sc)+os.sep
def open(self): def open(self):
if self.hm is not None: # linux if islinux:
self.open_linux() self.open_linux()
if iswindows:
self.open_windows()
def set_progress_reporter(self, pr): def set_progress_reporter(self, pr):
self.report_progress = pr self.report_progress = pr
@ -105,29 +188,43 @@ class PRS505(Device):
def card_prefix(self, end_session=True): def card_prefix(self, end_session=True):
return self._card_prefix return self._card_prefix
@classmethod
def _windows_space(cls, prefix):
if prefix is None:
return 0, 0
import win32file
sectors_per_cluster, bytes_per_sector, free_clusters, total_clusters = \
win32file.GetDiskFreeSpace(prefix[:-1])
mult = sectors_per_cluster * bytes_per_sector
return total_clusters * mult, free_clusters * mult
def total_space(self, end_session=True): def total_space(self, end_session=True):
msz = csz = 0
if not iswindows: if not iswindows:
msz = 0
if self._main_prefix is not None: if self._main_prefix is not None:
stats = os.statvfs(self._main_prefix) stats = os.statvfs(self._main_prefix)
msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree) msz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
csz = 0
if self._card_prefix is not None: if self._card_prefix is not None:
stats = os.statvfs(self._card_prefix) stats = os.statvfs(self._card_prefix)
csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree) csz = stats.f_frsize * (stats.f_blocks + stats.f_bavail - stats.f_bfree)
else:
msz = self._windows_space(self._main_prefix)[0]
csz = self._windows_space(self._card_prefix)[0]
return (msz, 0, csz) return (msz, 0, csz)
def free_space(self, end_session=True): def free_space(self, end_session=True):
msz = csz = 0
if not iswindows: if not iswindows:
msz = 0
if self._main_prefix is not None: if self._main_prefix is not None:
stats = os.statvfs(self._main_prefix) stats = os.statvfs(self._main_prefix)
msz = stats.f_bsize * stats.f_bavail msz = stats.f_bsize * stats.f_bavail
csz = 0
if self._card_prefix is not None: if self._card_prefix is not None:
stats = os.statvfs(self._card_prefix) stats = os.statvfs(self._card_prefix)
csz = stats.f_bsize * stats.f_bavail csz = stats.f_bsize * stats.f_bavail
else:
msz = self._windows_space(self._main_prefix)[1]
csz = self._windows_space(self._card_prefix)[1]
return (msz, 0, csz) return (msz, 0, csz)

View File

@ -12,6 +12,7 @@
## You should have received a copy of the GNU General Public License along ## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
from libprs500 import iswindows
import sys, os import sys, os
from PyQt4.QtCore import QThread, SIGNAL, QObject from PyQt4.QtCore import QThread, SIGNAL, QObject
@ -42,10 +43,15 @@ class DeviceDetector(QThread):
QThread.__init__(self) QThread.__init__(self)
def run(self): def run(self):
helper = None
if iswindows:
import wmi, pythoncom
pythoncom.CoInitialize()
helper = wmi.WMI()
while True: while True:
for device in self.devices: for device in self.devices:
try: try:
connected = device[0].is_connected() connected = device[0].is_connected(helper=helper)
except: except:
connected = False connected = False
if connected and not device[1]: if connected and not device[1]:

View File

@ -709,7 +709,7 @@ class Main(MainWindow, Ui_MainWindow):
def main(args=sys.argv): def main(args=sys.argv):
from PyQt4.Qt import QApplication from PyQt4.Qt import QApplication
pid = os.fork() if islinux else -1 pid = os.fork() if islinux else -1
if pid <= 0: if pid <= 0:

View File

@ -14,9 +14,15 @@
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
import shutil import shutil
''' Post installation script for linux ''' ''' Post installation script for linux '''
import sys, os, stat import sys, os
from subprocess import check_call from subprocess import check_call
from libprs500 import __version__ from libprs500 import __version__, __appname__
from libprs500.devices.prs500.driver import PRS500
from libprs500.devices.prs505.driver import PRS505
DEVICES = (PRS500, PRS505)
def options(option_parser): def options(option_parser):
parser = option_parser() parser = option_parser()
@ -182,36 +188,24 @@ def setup_udev_rules():
'''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,) '''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,)
) )
udev.close() udev.close()
open('/usr/share/hal/fdi/policy/20thirdparty/10-libprs500.fdi', 'w').write( fdi = open('/usr/share/hal/fdi/policy/20thirdparty/10-libprs500.fdi', 'w')
'''\ fdi.write('<?xml version="1.0" encoding="UTF-8"?>\n\n<deviceinfo version="0.2">\n')
<?xml version="1.0" encoding="UTF-8"?> for cls in DEVICES:
fdi.write(\
<deviceinfo version="0.2"> '''
<device> <device>
<match key="info.category" string="volume"> <match key="usb_device.vendor_id" int="%(vendor_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="0x054c"> <match key="usb_device.product_id" int="%(product_id)s">
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="0x031e"> <merge key="libprs500.deviceclass" type="string">%(cls)s</merge>
<match key="volume.is_partition" bool="false"> <append key="info.callouts.add" type="strlist">%(prog)s</merge>
<merge key="volume.label" type="string">Sony Reader Main Memory</merge>
</match>
</match>
</match> </match>
</match> </match>
</device> </device>
<device> '''%dict(cls=cls.__name__, vendor_id=cls.VENDOR_ID, product_id=cls.PRODUCT_ID,
<match key="info.category" string="volume"> prog=__appname__))
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.vendor_id" int="0x054c"> fdi.write('\n'+cls.get_fdi())
<match key="@info.parent:@info.parent:@info.parent:@info.parent:usb.product_id" int="0x031e"> fdi.write('\n</deviceinfo>\n')
<match key="volume.is_partition" bool="true"> fdi.close()
<merge key="volume.label" type="string">Sony Reader Storage Card</merge>
</match>
</match>
</match>
</match>
</device>
</deviceinfo>
''')
check_call('/etc/init.d/hald restart', shell=True) check_call('/etc/init.d/hald restart', shell=True)
try: try:

View File

@ -446,11 +446,14 @@ setup(
options = { 'py2exe' : {'compressed': 1, options = { 'py2exe' : {'compressed': 1,
'optimize' : 2, 'optimize' : 2,
'dist_dir' : PY2EXE_DIR, 'dist_dir' : PY2EXE_DIR,
'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg', 'mechanize', 'ClientForm'], 'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg',
'mechanize', 'ClientForm', 'wmi',
'win32file', 'pythoncom'],
'packages' : ['PIL'], 'packages' : ['PIL'],
'excludes' : ["Tkconstants", "Tkinter", "tcl", 'excludes' : ["Tkconstants", "Tkinter", "tcl",
"_imagingtk", "ImageTk", "FixTk", "_imagingtk", "ImageTk", "FixTk",
'pydoc'], 'pydoc'],
'dll_excludes' : ['mswsock.dll'],
}, },
}, },