1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#!perl -w
#
# UsbMapEntry -- encapsulate single line from modules.usbmap
# Copyright (C) 2005 Erik van Konijnenburg
#
# 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 St, Fifth Floor, Boston, MA 02110-1301 USA
#
#
# Knows how to match, can return module name.
#
# The ultimate authority on matching is
# linux/drivers/usb/core/usb.c:usb_match_id(),
# the routine where the kernel determines whether to let a particular
# driver probe an interface. Both the hotplug usb.agent and this
# script mimic the behaviour of that function.
# AFAICS, usb_match_id is only invoked on interfaces, not on the devices
# these interfaces are part of.
# However, driver/usb/core/hub.c:usb_new_device() invokes device_add()
# for both the device and (via usb_set_configuration()) for the interfaces;
# this in turn will produce hotplut events (in the case of interfaces with
# a callback to usb_hotplug(), which puts product information in the hotplug
# environment), and the hotplug scripts will do matching for both devices
# and interfaces. The coldplug script usb.rc emulates this kernel behaviour.
#
# Thus, there seems to be a discrepancy between what gets matched in the
# kernel and what gets matched in hotplug; we follow hotplug behaviour.
#
# Note that hotplug uses this matching algorithm not only on the module
# map provided by the kernel, but also on /etc/hotplug/usb/*.usermap;
# the latter results not in loading of a module but in execution of a script.
# This can be used to start gphoto, or it can be used to push firmware
# to a device. Question: what should mkinitrd know about this?
#
use strict;
use warnings;
package UsbMapEntry;
use base 'Obj';
sub fill {
my $self = shift;
$self->SUPER::fill();
$self->takeArgs ('module', 'match_flags', 'idVendor',
'idProduct', 'bcdDevice_lo', 'bcdDevice_hi',
'bDeviceClass', 'bDeviceSubClass', 'bDeviceProtocol',
'bInterfaceClass', 'bInterfaceSubClass',
'bInterfaceProtocol', 'driver_info');
}
sub module { return $_[0]->{module}; }
sub match_flags { return $_[0]->{match_flags}; }
sub idVendor { return $_[0]->{idVendor}; }
sub idProduct { return $_[0]->{idProduct}; }
sub bcdDevice_lo { return $_[0]->{bcdDevice_lo}; }
sub bcdDevice_hi { return $_[0]->{bcdDevice_hi}; }
sub bDeviceClass { return $_[0]->{bDeviceClass}; }
sub bDeviceSubClass { return $_[0]->{bDeviceSubClass}; }
sub bDeviceProtocol { return $_[0]->{bDeviceProtocol}; }
sub bInterfaceClass { return $_[0]->{bInterfaceClass}; }
sub bInterfaceSubClass { return $_[0]->{bInterfaceSubClass}; }
sub bInterfaceProtocol { return $_[0]->{bInterfaceProtocol}; }
sub driver_info { return $_[0]->{driver_info}; }
# we could do the USB_MATCH_XXX processing in init,
# if it turns out to be time critical.
my $USB_MATCH_VENDOR = 0x0001;
my $USB_MATCH_PRODUCT = 0x0002;
my $USB_MATCH_DEV_LO = 0x0004;
my $USB_MATCH_DEV_HI = 0x0008;
my $USB_MATCH_DEV_CLASS = 0x0010;
my $USB_MATCH_DEV_SUBCLASS = 0x0020;
my $USB_MATCH_DEV_PROTOCOL = 0x0040;
my $USB_MATCH_INT_CLASS = 0x0080;
my $USB_MATCH_INT_SUBCLASS = 0x0100;
my $USB_MATCH_INT_PROTOCOL = 0x0200;
sub matches {
my ($self, $dev) = @_;
my $match = $self->match_flags;
if ($match & $USB_MATCH_VENDOR && $self->idVendor != $dev->idVendor) {
return 0;
}
if ($match & $USB_MATCH_PRODUCT && $self->idProduct != $dev->idProduct) {
return 0;
}
if ($match & $USB_MATCH_DEV_LO && $self->bcdDevice_lo > $dev->bcdDevice) {
return 0;
}
if ($match & $USB_MATCH_DEV_HI && $self->bcdDevice_hi < $dev->bcdDevice) {
return 0;
}
if ($match & $USB_MATCH_DEV_CLASS && $self->bDeviceClass != $dev->bDeviceClass) {
return 0;
}
if ($match & $USB_MATCH_DEV_SUBCLASS && $self->bDeviceSubClass != $dev->bDeviceSubClass) {
return 0;
}
if ($match & $USB_MATCH_DEV_PROTOCOL && $self->bDeviceProtocol != $dev->bDeviceProtocol) {
return 0;
}
# Quoting usb.agent:
# for now, this only checks the first of perhaps
# several interfaces for this device.
if ($match & $USB_MATCH_INT_CLASS && $self->bInterfaceClass != $dev->bInterfaceClass) {
return 0;
}
if ($match & $USB_MATCH_INT_SUBCLASS && $self->bInterfaceSubClass != $dev->bInterfaceSubClass) {
return 0;
}
if ($match & $USB_MATCH_INT_PROTOCOL && $self->bInterfaceProtocol != $dev->bInterfaceProtocol) {
return 0;
}
return 1;
}
1;
|