~alexeftimie/jockey/fix-gobject

« back to all changes in this revision

Viewing changes to jockey/handlers.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2008-01-17 15:02:40 UTC
  • Revision ID: james.westby@ubuntu.com-20080117150240-djmsi8giu255vzzn
Tags: 0.1~r118
* Initial release, result of completely rewriting restricted-manager to be
  maintainable, robust, and suitable for other distributions. Some features
  and the KDE UI still need to be ported.
* See restricted-manager-rewrite specification for details.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# (c) 2007 Canonical Ltd.
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License along
 
14
# with this program; if not, write to the Free Software Foundation, Inc.,
 
15
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
16
 
 
17
'''Define some common abstract basic handler types.
 
18
 
 
19
These provide the common functionality for concrete handlers of different
 
20
classes, like handlers for a kernel module, a driver package, a handler group,
 
21
etc.
 
22
 
 
23
Custom concrete handlers need to fulfill the following requirements:
 
24
 - __init__(self, ui) must take exactly one argument (a reference to an
 
25
   AbstractUI instance). All othe properties must be detected by the
 
26
   constructor or changed with methods. These classes are instantiated
 
27
   automatically, which is not possible with constructors which need more
 
28
   arguments.
 
29
 
 
30
 - All handler types in this module have some abstract functions which need to
 
31
   be implemented (see the documentation of the particular classes).
 
32
'''
 
33
 
 
34
import subprocess, os.path, sys, logging
 
35
from gettext import gettext as _
 
36
 
 
37
import detection
 
38
from oslib import OSLib
 
39
 
 
40
#--------------------------------------------------------------------#
 
41
 
 
42
class Handler:
 
43
    '''Abstract basic handler.'''
 
44
 
 
45
    def __init__(self, ui, name, description=None, rationale=None,
 
46
        **extra_options):
 
47
        '''Create a handler with given (human readable) name.
 
48
        
 
49
        Every handler should have a human readable name. A custom rationale and
 
50
        a multi-line description can be given, too. Every handler gets a
 
51
        reference to the currently used user interface (subclass of AbstractUI)
 
52
        so that it can make callbacks and query the user.
 
53
        '''
 
54
        self._changed = False
 
55
        self._name = name
 
56
        self._description = description
 
57
        self.ui = ui
 
58
        self._rationale = rationale
 
59
        self.extra_options = extra_options
 
60
 
 
61
    def name(self):
 
62
        '''Return one-line name of the handler (for human consumption).'''
 
63
 
 
64
        return self._name
 
65
 
 
66
    def description(self):
 
67
        '''Return multi-line description of the handler.'''
 
68
 
 
69
        return self._description
 
70
 
 
71
    def rationale(self):
 
72
        '''Return rationale as to why this driver might be enabled.
 
73
        
 
74
        Might return None if no rationale is available.
 
75
        '''
 
76
        if self._rationale:
 
77
            return self._rationale
 
78
 
 
79
        # default rationale
 
80
        if self.free():
 
81
            return None
 
82
        else:
 
83
            return _('This driver is necessary to support the '
 
84
                'hardware, there is no free/open alternative.\n\n'
 
85
                'If this driver is not enabled, the hardware will not '
 
86
                'function.')
 
87
 
 
88
    def changed(self):
 
89
        '''Return if the module has been enabled/disabled at least once.'''
 
90
 
 
91
        return self._changed
 
92
 
 
93
    #
 
94
    # The following methods can be specialized in subclasses
 
95
    # 
 
96
 
 
97
    def can_change(self):
 
98
        '''Check whether we can actually modify settings of this handler.
 
99
 
 
100
        This might not be the case if e. g. the user manually modified a
 
101
        configuration file. Return an explanatory text if settings can not be
 
102
        changed, or None if changing is ok.
 
103
        '''
 
104
        return None
 
105
 
 
106
    def __str__(self):
 
107
        return '%s([%s, %s] %s)' % (
 
108
            str(self.__class__).split('.')[-1],
 
109
            self.free() and 'free' or 'nonfree',
 
110
            self.enabled() and 'enabled' or 'disabled',
 
111
            self.name())
 
112
 
 
113
    #
 
114
    # The following methods must be implemented in subclasses
 
115
    # 
 
116
 
 
117
    def free(self):
 
118
        '''Return if the handler represents a free software driver.'''
 
119
 
 
120
        raise NotImplementedError, 'subclasses need to implement this'
 
121
 
 
122
    def enabled(self):
 
123
        '''Return if the handler is enabled.
 
124
        
 
125
        'Enabled' means that the user agreed to use this driver if it is
 
126
        applicable.
 
127
        '''
 
128
        raise NotImplementedError, 'subclasses need to implement this'
 
129
 
 
130
    def used(self):
 
131
        '''Return if the handler is currently in use.'''
 
132
 
 
133
        raise NotImplementedError, 'subclasses need to implement this'
 
134
 
 
135
    def available(self):
 
136
        '''Return if the conditions to use this handler on the system are met.
 
137
 
 
138
        This usually means that the hardware for this driver is available, but
 
139
        there might be hardware independent drivers, too.
 
140
        
 
141
        If this returns True or False, the answer is definitive and no further
 
142
        detection, db querying, etc is performed. If this returns None, then
 
143
        the handler cannot decide availability on its own; in that case it is
 
144
        merely available in the handler pool, and an external driver database
 
145
        (detection.DriverDB) is queried.
 
146
        '''
 
147
        raise NotImplementedError, 'subclasses need to implement this'
 
148
 
 
149
    def ui_category(self):
 
150
        '''Return handler category (translated, human readable, short).'''
 
151
 
 
152
        raise NotImplementedError, 'subclasses need to implement this'
 
153
 
 
154
    def enable(self):
 
155
        '''Allow the OS to use it if the hardware is available.
 
156
        
 
157
        If possible, the handler should be loaded, too.
 
158
        '''
 
159
        self._changed = True
 
160
 
 
161
    def disable(self):
 
162
        '''Prevent the OS from using it even if the hardware is available.
 
163
 
 
164
        If possible, the handler should be unloaded, too.
 
165
        '''
 
166
        self._changed = True
 
167
 
 
168
#--------------------------------------------------------------------#
 
169
 
 
170
class HandlerGroup(Handler):
 
171
    '''Perform operations on a group of handlers.
 
172
 
 
173
    A group should be provided if it makes little sense to present several very
 
174
    similar handlers in the UI. For example, the three VMWare or the dozens of
 
175
    commercial OSS drivers should be grouped.
 
176
    '''
 
177
    def __init__(self, ui, name, description=None, rationale=None, **extra_options):
 
178
        Handler.__init__(self, ui, name, description, rationale, **extra_options)
 
179
        self.subhandlers = []
 
180
 
 
181
    def add(self, handler):
 
182
        '''Add a subhandler.'''
 
183
 
 
184
        self.subhandlers.append(handler)
 
185
 
 
186
    def free(self):
 
187
        '''Return if all subhandlers represent free software drivers.'''
 
188
 
 
189
        for h in self.subhandlers:
 
190
            if not h.free():
 
191
                return False
 
192
 
 
193
        return True
 
194
 
 
195
    def enabled(self):
 
196
        '''Return if all subhandlers are enabled.'''
 
197
 
 
198
        for h in self.subhandlers:
 
199
            if not h.enabled():
 
200
                return False
 
201
 
 
202
        return True
 
203
 
 
204
    def used(self):
 
205
        '''Return if any subhandler is used.'''
 
206
 
 
207
        for h in self.subhandlers:
 
208
            if h.used():
 
209
                return True
 
210
 
 
211
        return False
 
212
 
 
213
    def available(self):
 
214
        '''Return if the hardware for any subhandler is available.
 
215
        
 
216
        If all subhandlers return False, this returns False. If any subhandler
 
217
        returns True, this returns True. Otherwise this returns None.
 
218
        '''
 
219
        all_False = True
 
220
 
 
221
        for h in self.subhandlers:
 
222
            a = h.available()
 
223
            if a:
 
224
                return True
 
225
            if a == None:
 
226
                all_false = False
 
227
            else:
 
228
                assert a == False
 
229
 
 
230
        if all_false:
 
231
            return False
 
232
        else:
 
233
            return None
 
234
 
 
235
    def ui_category(self):
 
236
        '''Return handler category (translated, human readable, short).'''
 
237
 
 
238
        return self.subhandlers[0].ui_category()
 
239
 
 
240
    def enable(self):
 
241
        '''Enable all subhandlers.'''
 
242
 
 
243
        for h in self.subhandlers:
 
244
            h.enable()
 
245
 
 
246
    def disable(self):
 
247
        '''Disable all subhandlers.'''
 
248
 
 
249
        for h in self.subhandlers:
 
250
            h.disable()
 
251
 
 
252
    def changed(self):
 
253
        '''Return if at least one subhandler has been enabled/disabled at
 
254
        least once.'''
 
255
 
 
256
        for h in self.subhandlers:
 
257
            if h.changed():
 
258
                return True
 
259
 
 
260
        return False
 
261
 
 
262
    def can_change(self):
 
263
        '''Check whether we can actually modify settings of this handler.'''
 
264
 
 
265
        assert self.subhandlers
 
266
 
 
267
        for h in self.subhandlers:
 
268
            c = h.can_change()
 
269
            if c:
 
270
                return c
 
271
 
 
272
        return None
 
273
 
 
274
#--------------------------------------------------------------------#
 
275
 
 
276
class KernelModuleHandler(Handler):
 
277
    '''Handler for a kernel module.
 
278
    
 
279
    This class can be used as a standard handler for kernel modules (and in
 
280
    fact detection.get_handlers() uses this as a default handler if there is no
 
281
    custom one). Subclasses have to implement __init__() at least.
 
282
    '''
 
283
    _loaded_modules = None
 
284
    
 
285
    def __init__(self, ui, module, name=None, description=None, rationale=None,
 
286
            **extra_options):
 
287
        '''Create handler for a kernel module.
 
288
        
 
289
        If not given explicitly, the name is read from modinfo's 'description'
 
290
        field.
 
291
        '''
 
292
        self.module = module
 
293
        self._modinfo = detection.get_modinfo(self.module)
 
294
        assert self._modinfo, 'kernel module %s exists' % self.module
 
295
        if not name:
 
296
            name = '\n'.join(self._modinfo.get('description', [self.module]))
 
297
        Handler.__init__(self, ui, name, description, rationale, **extra_options)
 
298
 
 
299
    def __str__(self):
 
300
        return '%s([%s, %s, %s] %s)' % (
 
301
            str(self.__class__).split('.')[-1],
 
302
            self.module,
 
303
            self.free() and 'free' or 'nonfree',
 
304
            self.enabled() and 'enabled' or 'disabled',
 
305
            self.name())
 
306
 
 
307
    def free(self):
 
308
        '''Return if the handler represents a free software driver.'''
 
309
 
 
310
        # this function needs to be kept in sync with the kernel function
 
311
        # is_license_gpl_compatible()
 
312
 
 
313
        for l in self._modinfo.get('license', ['unknown']):
 
314
            if l in ('GPL', 'GPL v2', 'GPL and additional rights', 
 
315
                'Dual BSD/GPL', 'Dual MIT/GPL', 'Dual MPL/GPL'):
 
316
                return True
 
317
 
 
318
        return False
 
319
 
 
320
    def enabled(self):
 
321
        '''Return if the handler is enabled.
 
322
        
 
323
        'Enabled' means that the user agreed to use this driver if it is
 
324
        applicable.
 
325
        '''
 
326
        return not OSLib.inst.module_blacklisted(self.module)
 
327
 
 
328
    def used(self):
 
329
        '''Return if the handler is currently in use.'''
 
330
 
 
331
        return self.module_loaded(self.module)
 
332
 
 
333
    def available(self):
 
334
        '''Return if the conditions to use this handler on the system are met
 
335
        (e. g. hardware for this driver is available).
 
336
 
 
337
        This defaults to None, because we usually want to delegate this to the
 
338
        driver db. Subclasses are welcome to override this, of course.
 
339
        '''
 
340
        return None
 
341
 
 
342
    def ui_category(self):
 
343
        '''Return handler category (translated, human readable, short).'''
 
344
 
 
345
        return self.ui._('Device driver')
 
346
 
 
347
    def enable(self):
 
348
        '''Allow the OS to use it if the hardware is available.
 
349
        
 
350
        This removes the module from the modprobe blacklist.
 
351
        '''
 
352
        Handler.enable(self)
 
353
        OSLib.inst.blacklist_module(self.module, False)
 
354
        subprocess.call([OSLib.inst.modprobe_path, self.module])
 
355
        self.read_loaded_modules()
 
356
        self.rebind(self.module) # TODO: is this always wanted?
 
357
 
 
358
    def disable(self):
 
359
        '''Prevent the OS from using it even if the hardware is available.
 
360
 
 
361
        This adds the module to the modprobe blacklist.
 
362
        '''
 
363
        Handler.disable(self)
 
364
        OSLib.inst.blacklist_module(self.module, True)
 
365
 
 
366
    @classmethod
 
367
    def rebind(klass, module):
 
368
        '''Re-bind all devices using the module.
 
369
        
 
370
        This is necessary for example to reload firmware.
 
371
        '''
 
372
        drivers_dir = os.path.join(OSLib.inst.sys_dir, 'module', module, 'drivers')
 
373
        if not os.path.isdir(drivers_dir):
 
374
            logging.warning('%s does not exist, cannot rebind %s driver' % (
 
375
                drivers_dir, module))
 
376
            return
 
377
 
 
378
        for driver in os.listdir(drivers_dir):
 
379
            driver_path = os.path.join(drivers_dir, driver)
 
380
            for device in os.listdir(driver_path):
 
381
                # only consider subdirs which are not called 'module'
 
382
                if device == 'module' or not os.path.isdir(
 
383
                    os.path.join(driver_path, device)):
 
384
                    continue
 
385
                try:
 
386
                    logging.debug('unbind/rebind on driver %s: device %s', driver_path, device)
 
387
                    open(os.path.join(driver_path, 'unbind'), 'w').write(device)
 
388
                    open(os.path.join(driver_path, 'bind'), 'w').write(device)
 
389
                except IOError:
 
390
                    logging.warning('unbind/rebind for device %s on driver %s failed', 
 
391
                        device, driver_path, exc_info=True)
 
392
 
 
393
    @classmethod
 
394
    def read_loaded_modules(klass):
 
395
        '''Get the list of loaded kernel modules.'''
 
396
 
 
397
        klass._loaded_modules = []
 
398
 
 
399
        proc_modules = open(OSLib.inst.proc_modules)
 
400
        try:
 
401
            for line in proc_modules:
 
402
                try:
 
403
                    line = line[:line.index(' ')]
 
404
                except ValueError:
 
405
                    pass
 
406
 
 
407
                klass._loaded_modules.append(line.strip())
 
408
        finally:
 
409
            proc_modules.close()
 
410
 
 
411
    @classmethod
 
412
    def module_loaded(klass, module):
 
413
        '''Return if the handler is currently in use.'''
 
414
 
 
415
        if klass._loaded_modules == None:
 
416
            klass.read_loaded_modules()
 
417
 
 
418
        return module in klass._loaded_modules
 
419
 
 
420
#--------------------------------------------------------------------#
 
421
 
 
422
class FirmwareHandler(KernelModuleHandler):
 
423
    '''Handler for an already available kernel module needing firmware.
 
424
 
 
425
    Subclasses need to extend enable() and implement disable() to do something
 
426
    with the downloaded file (unpack it, put into the right directory, etc.).
 
427
    This class' enable() function will deal with downloading it and the UI
 
428
    progress reporting of the download.
 
429
    '''
 
430
    def __init__(self, ui, module, testfile, name=None, description=None, 
 
431
            rationale=None, **extra_options):
 
432
        '''Create handler for a piece of firmware for a kernel module.
 
433
        
 
434
        The required extra option 'url' specifies where the firmware can be
 
435
        downloaded from. The optional 'sha1sum' extra option provides a
 
436
        checksum of the downloaded file. The file will not be installed if it
 
437
        does not match.
 
438
 
 
439
        enabled() will return True iff the path in testfile exists.
 
440
 
 
441
        By default this handler assumes that the firmware is not free (since
 
442
        otherwise the distribution could ship it together with the driver). You
 
443
        can provide the extra option 'free' (any nonempty value) for free
 
444
        firmware.
 
445
    
 
446
        If not given explicitly, the name is read from modinfo's 'description'
 
447
        field.
 
448
        '''
 
449
        self.url = extra_options['url']
 
450
        self.testfile = testfile
 
451
        if not rationale:
 
452
            if 'free' in extra_options:
 
453
                rationale = ui._('The driver itself is already installed, but '
 
454
                    'it requires a piece of firmware which is not shipped with '
 
455
                    'the operating system.')
 
456
            else:
 
457
                rationale = ui._('While this driver itself is free software, '
 
458
                    'it relies on proprietary firmware which cannot be legally '
 
459
                    'shipped with the operating system.')
 
460
            rationale += ' ' + ui._('Your hardware will not work without the firmware.')
 
461
 
 
462
        KernelModuleHandler.__init__(self, ui, module, name, description,
 
463
            rationale, **extra_options)
 
464
 
 
465
    def free(self):
 
466
        '''Return if the handler represents a free software driver.'''
 
467
 
 
468
        if 'free' in self.extra_options:
 
469
            return True
 
470
        return KernelModuleHandler.free(self)
 
471
 
 
472
    def enabled(self):
 
473
        '''Return if the handler is enabled.
 
474
        
 
475
        'Enabled' means that the user agreed to use this driver if it is
 
476
        applicable.
 
477
        '''
 
478
        return os.path.exists(self.testfile) and KernelModuleHandler.enabled(self)
 
479
 
 
480
    def used(self):
 
481
        '''Return if the handler is currently in use.'''
 
482
 
 
483
        return self.enabled() and KernelModuleHandler.used(self)
 
484
 
 
485
    def ui_category(self):
 
486
        '''Return handler category (translated, human readable, short).'''
 
487
 
 
488
        return self.ui._('Firmware')
 
489
 
 
490
    def enable(self):
 
491
        '''Allow the OS to use it if the hardware is available.
 
492
        
 
493
        This downloads the url and puts it into self.firmware_file. Subclasses
 
494
        need to provide an actual implementation what to do with the file.
 
495
        '''
 
496
        self.firmware_file = self.ui.download_url(self.url)[0]
 
497
        if not self.firmware_file:
 
498
            return
 
499
 
 
500
        # TODO: sha1sum check
 
501
 
 
502
        KernelModuleHandler.enable(self)
 
503
 
 
504
    def disable(self):
 
505
        '''Prevent the OS from using it even if the hardware is available.
 
506
        
 
507
        Implementation in subclasses need to remove the firmware files and call
 
508
        KernelModuleHandler.disable().
 
509
        '''
 
510
        raise NotImplementedError, 'subclasses need to implement this'
 
511
 
 
512
#--------------------------------------------------------------------#
 
513
 
 
514
class DriverPackageHandler(Handler):
 
515
    '''Handler for a driver package, not tied to a particular kernel module.
 
516
    
 
517
    Subclasses need to implement __init__(), available() and used() at least.
 
518
    '''
 
519
    def __init__(self, ui, package, name=None, description=None, 
 
520
            rationale=None, **extra_options):
 
521
        '''Create handler for of driver package.
 
522
        
 
523
        If not given explicitly, the name and description are taken from the
 
524
        distribution package.
 
525
        '''
 
526
        self.package = package
 
527
        if not name or not description:
 
528
            (distro_name, distro_desc) = OSLib.inst.package_description(package)
 
529
            if not name:
 
530
                name = distro_name
 
531
            if not description:
 
532
                description = distro_desc
 
533
 
 
534
        Handler.__init__(self, ui, name, description, rationale, **extra_options)
 
535
 
 
536
    def free(self):
 
537
        '''Return if the handler represents a free software driver.'''
 
538
 
 
539
        return OSLib.inst.is_package_free(self.package)
 
540
 
 
541
    def enabled(self):
 
542
        '''Return if the handler is enabled.
 
543
        
 
544
        'Enabled' means that the user agreed to use this driver if it is
 
545
        applicable.
 
546
        '''
 
547
        return OSLib.inst.package_installed(self.package)
 
548
 
 
549
    def available(self):
 
550
        '''Return if the conditions to use this handler on the system are met.
 
551
 
 
552
        This usually means that the hardware for this driver is available, but
 
553
        there might be hardware independent drivers, too.
 
554
        
 
555
        This returns False if the package is not available, otherwise None.
 
556
        Subclasses are welcome to add a positive detection, but should return
 
557
        False if this method returns False, unless they require a separate
 
558
        package repository.
 
559
        '''
 
560
        try:
 
561
            OSLib.inst.package_description(self.package)
 
562
            return None
 
563
        except ValueError:
 
564
            return False
 
565
 
 
566
    def ui_category(self):
 
567
        '''Return handler category (translated, human readable, short).'''
 
568
 
 
569
        return self.ui._('Device driver')
 
570
 
 
571
    def enable(self):
 
572
        '''Allow the OS to use it if the hardware is available.
 
573
        
 
574
        If possible, the handler should be loaded, too.
 
575
        '''
 
576
        self.ui.install_package(self.package)
 
577
        Handler.enable(self)
 
578
 
 
579
    def disable(self):
 
580
        '''Prevent the OS from using it even if the hardware is available.
 
581
 
 
582
        If possible, the handler should be unloaded, too.
 
583
        '''
 
584
        self.ui.remove_package(self.package)
 
585
        Handler.disable(self)
 
586
 
 
587
#--------------------------------------------------------------------#
 
588
 
 
589
class ModulePackageHandler(KernelModuleHandler, DriverPackageHandler):
 
590
    '''Kernel module which needs an additional driver package.
 
591
    
 
592
    Subclasses need to implement __init__(), available() and used() at least.
 
593
    '''
 
594
    def __init__(self, ui, module, package, name=None, description=None, 
 
595
            rationale=None, **extra_options):
 
596
        '''Handler for a kernel module which needs an additional driver package.
 
597
        
 
598
        If not given explicitly, the name is read from modinfo's 'description'
 
599
        field.
 
600
        '''
 
601
        DriverPackageHandler.__init__(self, ui, package, name, description,
 
602
            rationale, **extra_options)
 
603
        KernelModuleHandler.__init__(self, ui, module, name, description,
 
604
            rationale, **extra_options)
 
605
 
 
606
    def can_change(self):
 
607
        '''Check whether we can actually modify settings of this handler.
 
608
 
 
609
        This might not be the case if e. g. the user manually modified a
 
610
        configuration file. Return an explanatory text if settings can not be
 
611
        changed, or None if changing is ok.
 
612
        '''
 
613
        return DriverPackageHandler.can_change(self) or \
 
614
            KernelModuleHandler.can_change(self)
 
615
 
 
616
    def free(self):
 
617
        '''Return if the handler represents a free software driver.'''
 
618
 
 
619
        return DriverPackageHandler.free(self) and \
 
620
            KernelModuleHandler.free(self)
 
621
 
 
622
    def available(self):
 
623
        '''Return if the conditions to use this handler on the system are met.
 
624
 
 
625
        This usually means that the hardware for this driver is available, but
 
626
        there might be hardware independent drivers, too.
 
627
        
 
628
        This returns False if the package is not available, otherwise None.
 
629
        Subclasses are welcome to add a positive detection, but should return
 
630
        False if this method returns False.
 
631
        '''
 
632
        # KernelModuleHandler does not have an interesting implementation, so
 
633
        # only query the package one by default
 
634
        return DriverPackageHandler.available(self)
 
635
 
 
636
    def enabled(self):
 
637
        '''Return if the handler is enabled.
 
638
        
 
639
        'Enabled' means that the user agreed to use this driver if it is
 
640
        applicable.
 
641
        '''
 
642
        return DriverPackageHandler.enabled(self) and \
 
643
            KernelModuleHandler.enabled(self)
 
644
 
 
645
    def enable(self):
 
646
        '''Allow the OS to use it if the hardware is available.
 
647
        
 
648
        If possible, the handler should be loaded, too.
 
649
        '''
 
650
        DriverPackageHandler.enable(self)
 
651
        KernelModuleHandler.enable(self)
 
652
 
 
653
    def disable(self):
 
654
        '''Prevent the OS from using it even if the hardware is available.
 
655
 
 
656
        If possible, the handler should be unloaded, too.
 
657
        '''
 
658
        DriverPackageHandler.disable(self)
 
659
        KernelModuleHandler.disable(self)