root/branches/0.3/src/devices.py

Revision 797, 7.7 kB (checked in by nicfit, 1 year ago)

configure option / ebuild USE flag fixes (#331)

Line 
1 ################################################################################
2 #  Copyright (C) 2006  Travis Shirk <travis@pobox.com>
3 #  Copyright (C) 2003 Thomas Schueppel, Dirk Meyer (cdrom_disc_status)
4 #
5 #  This program is free software; you can redistribute it and/or modify
6 #  it under the terms of the GNU General Public License as published by
7 #  the Free Software Foundation; either version 2 of the License, or
8 #  (at your option) any later version.
9 #
10 #  This program is distributed in the hope that it will be useful,
11 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 #  GNU General Public License for more details.
14 #
15 #  You should have received a copy of the GNU General Public License
16 #  along with this program; if not, write to the Free Software
17 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 #
19 #  $Id$
20 ################################################################################
21 import os
22 import gobject
23 import mesk, mesk.audio.cdaudio
24
25 from fcntl import ioctl
26
27 __DEVICE_MGR = None
28 def get_mgr():
29     global __DEVICE_MGR
30     if __DEVICE_MGR is None:
31         __DEVICE_MGR = DeviceMgr()
32     return __DEVICE_MGR
33
34 class Device(object):
35     def __init__(self, hal_udi, hal_dev):
36         self.udi = hal_udi
37         self.dev = hal_dev
38         self.volume_udi = None
39
40 class DeviceMgr(gobject.GObject):
41     def __init__(self):
42         gobject.GObject.__init__(self)
43         self._optical_devices = {}
44
45         # A signal emitted when the device media changes
46         gobject.signal_new('media-changed', DeviceMgr,
47                            gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
48                            [gobject.TYPE_PYOBJECT])
49
50         if mesk.info.DISABLE_DBUS_SUPPORT:
51             mesk.log.info('DeviceMgr is a stub due to DBus being disabled.')
52             return
53         else:
54             import dbus
55
56         # Get a handle to HAL
57         self.bus = dbus.SystemBus()
58         hal_manager_obj = self.bus.get_object('org.freedesktop.Hal',
59                                               '/org/freedesktop/Hal/Manager')
60         self.hal_manager = dbus.Interface(hal_manager_obj,
61                                           'org.freedesktop.Hal.Manager')
62
63         if not mesk.info.DISABLE_CDROM_SUPPORT:
64             # Find all optical (CDs, DVDs, etc.) drives
65             cdroms = self.hal_manager.FindDeviceByCapability('storage.cdrom')
66             for dev_udi in cdroms:
67                 # Get HAL device for drive
68                 dev_obj = self.bus.get_object('org.freedesktop.Hal', dev_udi)
69                 dev = dbus.Interface(dev_obj, 'org.freedesktop.Hal.Device')
70
71                 self._optical_devices[dev_udi] = Device(dev_udi, dev)
72
73         if self._optical_devices:
74             # Probe optical drives for media
75             volumes = self.hal_manager.FindDeviceByCapability('volume')
76             for vol_udi in volumes:
77                 dev_obj = self.bus.get_object('org.freedesktop.Hal', vol_udi)
78                 dev = dbus.Interface(dev_obj, 'org.freedesktop.Hal.Device')
79                 parent_udi = dev.GetProperty('info.parent')
80                 if parent_udi in self._optical_devices.keys():
81                     # Stash volume_udi so we can map the volume being removed
82                     self._optical_devices[parent_udi].volume_udi = vol_udi
83
84
85         # Device add/remove callback
86         def device_add(udi):
87             dev_obj = self.bus.get_object('org.freedesktop.Hal', udi)
88             hal_dev = dbus.Interface(dev_obj, 'org.freedesktop.Hal.Device')
89             if hal_dev.QueryCapability('volume'):
90                 # We have a mountable volume, check to see if it is a volume
91                 # for one of the CD devices
92                 parent = hal_dev.GetProperty('info.parent')
93                 if parent in self._optical_devices.keys():
94                     self._optical_devices[parent].volume_udi = udi
95                     self.emit('media-changed', self._optical_devices[parent])
96
97         def device_removed(udi):
98             for cd in self._optical_devices.values():
99                 if cd.volume_udi == udi:
100                     self.emit('media-changed', cd)
101                     cd.volume_udi = None
102                     break
103
104         # Register for device added/removed callbacks
105         self.bus.add_signal_receiver(device_add, 'DeviceAdded',
106                                      'org.freedesktop.Hal.Manager',
107                                      'org.freedesktop.Hal',
108                                      '/org/freedesktop/Hal/Manager')
109         self.bus.add_signal_receiver(device_removed, 'DeviceRemoved',
110                                      'org.freedesktop.Hal.Manager',
111                                      'org.freedesktop.Hal',
112                                      '/org/freedesktop/Hal/Manager')
113
114     def get_optical_devices(self):
115         '''Returns a dictionary of optical device objects.  The key into the
116         dict is the assigned unique name of the device, the value is the
117         Hal.Device instance.'''
118         return self._optical_devices
119
120     def get_device_display_name(self, device):
121         capability = 'CD'
122         for cap in ['dvdrw', 'dvdr', 'dvd', 'cdrw', 'cdr']:
123             if device.dev.GetProperty('storage.cdrom.%s' % cap):
124                 capability = cap.upper()
125                 break
126
127         dev_file = os.path.basename(device.dev.GetProperty('block.device'))
128         return '%s (%s)' % (capability, dev_file)
129
130     def shutdown(self):
131         pass
132
133 ### CDROM utils ###
134
135 # Constants from linux/cdrom.h #
136 # ioctl's
137 CDROMEJECT           = 0x5309
138 CDROMCLOSETRAY       = 0x5319
139 CDROM_MEDIA_CHANGED  = 0x5325
140 CDROM_DRIVE_STATUS   = 0x5326
141 CDROM_DISC_STATUS    = 0x5327
142 CDROM_LOCKDOOR       = 0x5329
143 CDROM_GET_CAPABILITY = 0x5331
144 # Disc selector for multi disc drives
145 CDSL_CURRENT = (int)(~ 0 >> 1)
146 # Status Constants
147 CDS_DISC_OK = 4
148 CDS_AUDIO   = 100
149 CDS_MIXED   = 105
150 # Capability constants
151 CDC_CLOSE_TRAY    = 0x01
152 CDC_OPEN_TRAY     = 0x02
153 CDC_MEDIA_CHANGED = 0x80
154
155 # Return codes for cdrom_disc_status
156 (CD_STATUS_NONE,
157  CD_STATUS_AUDIO,
158  CD_STATUS_DATA,
159  CD_STATUS_BLANK,
160 ) = range(4)
161
162 def cdrom_check_capablities(device):
163     caps = 0
164     try:
165         fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
166         caps = ioctl(fd, CDROM_GET_CAPABILITY)
167     finally:
168         os.close(fd)
169     return (caps & CDC_CLOSE_TRAY and
170             caps & CDC_OPEN_TRAY and
171             caps & CDC_MEDIA_CHANGED)
172
173 def cdrom_eject(device):
174     s = -1
175     try:
176         fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
177         s = ioctl(fd, CDROMEJECT)
178     finally:
179         os.close(fd)
180     return bool(not s)
181
182 def cdrom_close(device):
183     s = -1
184     try:
185         fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
186         s = ioctl(fd, CDROMCLOSETRAY)
187     finally:
188         os.close(fd)
189     return bool(not s)
190
191 def cdrom_disc_status(device):
192     """
193     Check status of CD device.
194     return: CD_STATUS_NONE, CD_STATUS_AUDIO, CD_STATUS_DATA, CD_STATUS_BLANK
195     """
196     try:
197         fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK)
198         s = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)
199         if s != CDS_DISC_OK:
200             return CD_STATUS_NONE
201         s = ioctl(fd, CDROM_DISC_STATUS)
202     finally:
203         os.close(fd)
204
205     if s == CDS_AUDIO or s == CDS_MIXED:
206         return CD_STATUS_AUDIO
207
208     try:
209         fd = open(device, 'rb')
210         # try to read from the disc to get information if the disc
211         # is a rw medium not written yet
212         fd.seek(32768) # 2048 multiple boundary for FreeBSD
213         # FreeBSD doesn't return IOError unless we try and read:
214         fd.read(1)
215     except IOError:
216         # not readable, blank disc
217         fd.close()
218         return CD_STATUS_BLANK
219     else:
220         # data disc
221         fd.close()
222         return CD_STATUS_DATA
Note: See TracBrowser for help on using the browser.