mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Fix #278
This commit is contained in:
parent
f1a6c8c706
commit
2d0e0707a6
@ -234,7 +234,7 @@ setup(
|
|||||||
'iconfile' : 'icons/library.icns',
|
'iconfile' : 'icons/library.icns',
|
||||||
'frameworks': ['libusb.dylib', 'libunrar.dylib'],
|
'frameworks': ['libusb.dylib', 'libunrar.dylib'],
|
||||||
'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg',
|
'includes' : ['sip', 'pkg_resources', 'PyQt4.QtSvg',
|
||||||
'mechanize', 'ClientForm'],
|
'mechanize', 'ClientForm', 'usbobserver'],
|
||||||
'packages' : ['PIL', 'Authorization', 'rtf2xml', 'lxml'],
|
'packages' : ['PIL', 'Authorization', 'rtf2xml', 'lxml'],
|
||||||
'excludes' : ['pydoc'],
|
'excludes' : ['pydoc'],
|
||||||
'plist' : { 'CFBundleGetInfoString' : '''libprs500, an E-book management application.'''
|
'plist' : { 'CFBundleGetInfoString' : '''libprs500, an E-book management application.'''
|
||||||
|
@ -50,16 +50,6 @@ class Device(object):
|
|||||||
'''Return the FDI description of this device for HAL on linux.'''
|
'''Return the FDI description of this device for HAL on linux.'''
|
||||||
return ''
|
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()
|
|
||||||
|
|
||||||
def set_progress_reporter(self, report_progress):
|
def set_progress_reporter(self, report_progress):
|
||||||
'''
|
'''
|
||||||
@param report_progress: Function that is called with a % progress
|
@param report_progress: Function that is called with a % progress
|
||||||
|
@ -118,21 +118,6 @@ class KINDLE(Device):
|
|||||||
return True
|
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:
|
|
||||||
try:
|
|
||||||
return get_device_by_id(cls.VENDOR_ID, cls.PRODUCT_ID) != None
|
|
||||||
except USBError:
|
|
||||||
return False
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def open_osx(self):
|
def open_osx(self):
|
||||||
mount = subprocess.Popen('mount', shell=True,
|
mount = subprocess.Popen('mount', shell=True,
|
||||||
stdout=subprocess.PIPE).stdout.read()
|
stdout=subprocess.PIPE).stdout.read()
|
||||||
|
@ -207,11 +207,11 @@ class DeviceHandle(Structure):
|
|||||||
"""
|
"""
|
||||||
Perform a control request to the default control pipe on the device.
|
Perform a control request to the default control pipe on the device.
|
||||||
@param rtype: specifies the direction of data flow, the type
|
@param rtype: specifies the direction of data flow, the type
|
||||||
of request, and the recipient.
|
of request, and the recipient.
|
||||||
@param request: specifies the request.
|
@param request: specifies the request.
|
||||||
@param bytes: if the transfer is a write transfer, buffer is a sequence
|
@param bytes: if the transfer is a write transfer, buffer is a sequence
|
||||||
with the transfer data, otherwise, buffer is the number of
|
with the transfer data, otherwise, buffer is the number of
|
||||||
bytes to read.
|
bytes to read.
|
||||||
@param value: specific information to pass to the device.
|
@param value: specific information to pass to the device.
|
||||||
@param index: specific information to pass to the device.
|
@param index: specific information to pass to the device.
|
||||||
"""
|
"""
|
||||||
@ -357,3 +357,16 @@ def get_device_by_id(idVendor, idProduct):
|
|||||||
if dev.device_descriptor.idVendor == idVendor and \
|
if dev.device_descriptor.idVendor == idVendor and \
|
||||||
dev.device_descriptor.idProduct == idProduct:
|
dev.device_descriptor.idProduct == idProduct:
|
||||||
return dev
|
return dev
|
||||||
|
|
||||||
|
def has_library():
|
||||||
|
return _libusb is not None
|
||||||
|
|
||||||
|
def get_devices():
|
||||||
|
buslist = busses()
|
||||||
|
ans = []
|
||||||
|
for bus in buslist:
|
||||||
|
devices = bus.device_list
|
||||||
|
for dev in devices:
|
||||||
|
device = (dev.device_descriptor.idVendor, dev.device_descriptor.idProduct)
|
||||||
|
ans.append(device)
|
||||||
|
return ans
|
@ -26,6 +26,7 @@ from libprs500.devices.errors import PathError
|
|||||||
from libprs500.devices.prs500.cli.terminfo import TerminalController
|
from libprs500.devices.prs500.cli.terminfo import TerminalController
|
||||||
from libprs500.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
from libprs500.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
||||||
from libprs500.devices import devices
|
from libprs500.devices import devices
|
||||||
|
from libprs500.devices.scanner import DeviceScanner
|
||||||
|
|
||||||
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
MINIMUM_COL_WIDTH = 12 #: Minimum width of columns in ls output
|
||||||
|
|
||||||
@ -207,13 +208,15 @@ def main():
|
|||||||
command = args[0]
|
command = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
dev = None
|
dev = None
|
||||||
helper = None
|
_wmi = None
|
||||||
if iswindows:
|
if iswindows:
|
||||||
import wmi, pythoncom
|
import wmi, pythoncom
|
||||||
pythoncom.CoInitialize()
|
pythoncom.CoInitialize()
|
||||||
helper = wmi.WMI()
|
_wmi = wmi.WMI()
|
||||||
|
scanner = DeviceScanner(_wmi)
|
||||||
|
scanner.scan()
|
||||||
for d in devices():
|
for d in devices():
|
||||||
if d.is_connected(helper):
|
if scanner.is_device_connected(d):
|
||||||
dev = d(log_packets=options.log_packets)
|
dev = d(log_packets=options.log_packets)
|
||||||
|
|
||||||
if dev is None:
|
if dev is None:
|
||||||
|
@ -113,21 +113,6 @@ class PRS505(Device):
|
|||||||
return True
|
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:
|
|
||||||
try:
|
|
||||||
return get_device_by_id(cls.VENDOR_ID, cls.PRODUCT_ID) != None
|
|
||||||
except USBError:
|
|
||||||
return False
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def open_osx(self):
|
def open_osx(self):
|
||||||
mount = subprocess.Popen('mount', shell=True,
|
mount = subprocess.Popen('mount', shell=True,
|
||||||
stdout=subprocess.PIPE).stdout.read()
|
stdout=subprocess.PIPE).stdout.read()
|
||||||
|
84
src/libprs500/devices/scanner.py
Normal file
84
src/libprs500/devices/scanner.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
## Copyright (C) 2008 Kovid Goyal kovid@kovidgoyal.net
|
||||||
|
## This program is free software; you can redistribute it and/or modify
|
||||||
|
## it under the terms of the GNU General Public License as published by
|
||||||
|
## the Free Software Foundation; either version 2 of the License, or
|
||||||
|
## (at your option) any later version.
|
||||||
|
##
|
||||||
|
## This program is distributed in the hope that it will be useful,
|
||||||
|
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
## GNU General Public License for more details.
|
||||||
|
##
|
||||||
|
## 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.,
|
||||||
|
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
'''
|
||||||
|
Device scanner that fetches list of devices on system ina platform dependent
|
||||||
|
manner.
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from libprs500 import iswindows, isosx
|
||||||
|
from libprs500.devices import libusb
|
||||||
|
|
||||||
|
osx_scanner = None
|
||||||
|
try:
|
||||||
|
import usbobserver
|
||||||
|
osx_scanner = usbobserver.get_devices
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
linux_scanner = libusb.get_devices
|
||||||
|
|
||||||
|
class DeviceScanner(object):
|
||||||
|
|
||||||
|
def __init__(self, wmi=None):
|
||||||
|
self.wmi = wmi
|
||||||
|
if iswindows and wmi is None:
|
||||||
|
raise RuntimeError('You must pass a wmi instance to DeviceScanner on windows.')
|
||||||
|
if isosx and osx_scanner is None:
|
||||||
|
raise RuntimeError('The Python extension usbobserver must be available on OS X.')
|
||||||
|
if not (isosx or iswindows) and not libusb.has_library():
|
||||||
|
raise RuntimeError('DeviceScanner requires libusb to work.')
|
||||||
|
|
||||||
|
self.devices = []
|
||||||
|
|
||||||
|
def get_devices(self):
|
||||||
|
if iswindows:
|
||||||
|
devices = []
|
||||||
|
for c in self.wmi.USBControllerDevice():
|
||||||
|
devices.append(c.Dependent.DeviceID.upper())
|
||||||
|
return devices
|
||||||
|
if isosx:
|
||||||
|
return osx_scanner()
|
||||||
|
return linux_scanner()
|
||||||
|
|
||||||
|
def scan(self):
|
||||||
|
self.devices = self.get_devices()
|
||||||
|
|
||||||
|
def is_device_connected(self, device):
|
||||||
|
if iswindows:
|
||||||
|
for device_id in self.devices:
|
||||||
|
if 'VEN_'+device.VENDOR_NAME in device_id and \
|
||||||
|
'PROD_'+device.PRODUCT_NAME in device_id:
|
||||||
|
return True
|
||||||
|
vid, pid = hex(device.VENDOR_ID)[2:], hex(device.PRODUCT_ID)[2:]
|
||||||
|
if len(vid) < 4: vid = '0'+vid
|
||||||
|
if len(pid) < 4: pid = '0'+pid
|
||||||
|
if 'VID_'+vid in device_id and \
|
||||||
|
'PID_'+pid in device_id:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
for vendor, product in self.devices:
|
||||||
|
if device.VENDOR_ID == vendor and device.PRODUCT_ID == product:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main(args=sys.argv):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
12
src/libprs500/devices/usbobserver/Makefile
Normal file
12
src/libprs500/devices/usbobserver/Makefile
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
usbobserver.so : usbobserver.o
|
||||||
|
gcc -arch i386 -arch ppc -bundle usbobserver.o -o usbobserver.so -framework Python -framework IOKit -framework CoreFoundation
|
||||||
|
|
||||||
|
usbobserver.o : usbobserver.c
|
||||||
|
gcc -arch i386 -arch ppc -dynamic -I/Library/Frameworks/Python.framework/Versions/2.5/include/python2.5 -c usbobserver.c -o usbobserver.o
|
||||||
|
|
||||||
|
|
||||||
|
install : usbobserver.so
|
||||||
|
cp usbobserver.so /Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/
|
||||||
|
|
||||||
|
clean :
|
||||||
|
rm -f *.o *.so
|
7
src/libprs500/devices/usbobserver/test.py
Normal file
7
src/libprs500/devices/usbobserver/test.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import gc, usbobserver
|
||||||
|
|
||||||
|
a = None
|
||||||
|
print len(gc.get_objects())
|
||||||
|
usbobserver.get_devices()
|
||||||
|
gc.collect()
|
||||||
|
print len(gc.get_objects())
|
124
src/libprs500/devices/usbobserver/usbobserver.c
Normal file
124
src/libprs500/devices/usbobserver/usbobserver.c
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/* Copyright (C) 2008 Kovid Goyal kovid@kovidgoyal.net
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* 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.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Python extension to scan the system for USB devices on OS X machines.
|
||||||
|
* To use
|
||||||
|
* >>> import usbobserver
|
||||||
|
* >>> usbobserver.get_devices()
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <IOKit/usb/IOUSBLib.h>
|
||||||
|
#include <IOKit/IOCFPlugIn.h>
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
usbobserver_get_devices(PyObject *self, PyObject *args) {
|
||||||
|
|
||||||
|
mach_port_t masterPort;
|
||||||
|
CFMutableDictionaryRef matchingDict;
|
||||||
|
kern_return_t kr;
|
||||||
|
|
||||||
|
/* Create a master port for communication with IOKit */
|
||||||
|
kr = IOMasterPort(MACH_PORT_NULL, &masterPort);
|
||||||
|
|
||||||
|
if (kr || !masterPort) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Couldn't create master IOKit port");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set up matching dictionary for class IOUSBDevice and its subclasses
|
||||||
|
matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
|
||||||
|
if (!matchingDict) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Couldn't create a USB matching dictionary");
|
||||||
|
mach_port_deallocate(mach_task_self(), masterPort);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_iterator_t iter;
|
||||||
|
IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
|
||||||
|
io_service_t usbDevice;
|
||||||
|
IOCFPlugInInterface **plugInInterface = NULL;
|
||||||
|
SInt32 score;
|
||||||
|
IOUSBDeviceInterface182 **dev = NULL;
|
||||||
|
UInt16 vendor, product;
|
||||||
|
|
||||||
|
PyObject *devices, *device;
|
||||||
|
devices = PyList_New(0);
|
||||||
|
if (devices == NULL) {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Out of memory allocating list");
|
||||||
|
mach_port_deallocate(mach_task_self(), masterPort);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (usbDevice = IOIteratorNext(iter)) {
|
||||||
|
plugInInterface = NULL; dev = NULL;
|
||||||
|
//Create an intermediate plugin
|
||||||
|
kr = IOCreatePlugInInterfaceForService(usbDevice, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score);
|
||||||
|
if ((kIOReturnSuccess != kr) || !plugInInterface)
|
||||||
|
printf("Unable to create a plug-in (%08x)\n", kr);
|
||||||
|
//Now create the device interface
|
||||||
|
HRESULT result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev);
|
||||||
|
|
||||||
|
if (result || !dev) printf("Couldn't create a device interface (%08x)\n", (int) result);
|
||||||
|
|
||||||
|
kr = (*dev)->GetDeviceVendor(dev, &vendor);
|
||||||
|
kr = (*dev)->GetDeviceProduct(dev, &product);
|
||||||
|
device = Py_BuildValue("(ii)", vendor, product);
|
||||||
|
if (device == NULL) {
|
||||||
|
IOObjectRelease(usbDevice);
|
||||||
|
(*plugInInterface)->Release(plugInInterface);
|
||||||
|
(*dev)->Release(dev);
|
||||||
|
Py_DECREF(devices);
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (PyList_Append(devices, device) == -1) {
|
||||||
|
IOObjectRelease(usbDevice);
|
||||||
|
(*plugInInterface)->Release(plugInInterface);
|
||||||
|
(*dev)->Release(dev);
|
||||||
|
Py_DECREF(devices);
|
||||||
|
Py_DECREF(device);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
IOObjectRelease(usbDevice);
|
||||||
|
(*plugInInterface)->Release(plugInInterface);
|
||||||
|
(*dev)->Release(dev);
|
||||||
|
Py_DECREF(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Finished with master port
|
||||||
|
mach_port_deallocate(mach_task_self(), masterPort);
|
||||||
|
|
||||||
|
return Py_BuildValue("N", devices);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef usbobserver_methods[] = {
|
||||||
|
{"get_devices", usbobserver_get_devices, METH_VARARGS,
|
||||||
|
"Get list of connected USB devices. Returns a list of tuples. Each tuple is of the form (vendor_id, product_id)."
|
||||||
|
},
|
||||||
|
{NULL, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
initusbobserver(void) {
|
||||||
|
(void) Py_InitModule("usbobserver", usbobserver_methods);
|
||||||
|
}
|
@ -12,12 +12,13 @@
|
|||||||
## 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
|
||||||
import os, sys, traceback
|
import os, traceback
|
||||||
|
|
||||||
from PyQt4.QtCore import QThread, SIGNAL, QObject
|
from PyQt4.QtCore import QThread, SIGNAL, QObject
|
||||||
|
|
||||||
from libprs500 import iswindows
|
from libprs500 import iswindows
|
||||||
from libprs500.devices import devices
|
from libprs500.devices import devices
|
||||||
|
from libprs500.devices.scanner import DeviceScanner
|
||||||
|
|
||||||
class DeviceDetector(QThread):
|
class DeviceDetector(QThread):
|
||||||
'''
|
'''
|
||||||
@ -35,17 +36,16 @@ class DeviceDetector(QThread):
|
|||||||
QThread.__init__(self)
|
QThread.__init__(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
helper = None
|
_wmi = None
|
||||||
if iswindows:
|
if iswindows:
|
||||||
import wmi, pythoncom
|
import wmi, pythoncom
|
||||||
pythoncom.CoInitialize()
|
pythoncom.CoInitialize()
|
||||||
helper = wmi.WMI()
|
_wmi = wmi.WMI()
|
||||||
|
scanner = DeviceScanner(_wmi)
|
||||||
while True:
|
while True:
|
||||||
|
scanner.scan()
|
||||||
for device in self.devices:
|
for device in self.devices:
|
||||||
try:
|
connected = scanner.is_device_connected(device[0])
|
||||||
connected = device[0].is_connected(helper=helper)
|
|
||||||
except:
|
|
||||||
connected = False
|
|
||||||
if connected and not device[1]:
|
if connected and not device[1]:
|
||||||
try:
|
try:
|
||||||
dev = device[0]()
|
dev = device[0]()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user