Home | History | Annotate | Download | only in mbim_compliance
      1 # Copyright 2015 The chromimn OS Authros. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 
      6 from usb import core
      7 from usb import util as usb_util
      8 from autotest_lib.client.cros.cellular.mbim_compliance import mbim_errors
      9 from autotest_lib.client.cros.cellular.mbim_compliance import \
     10         mbim_descriptor_cache
     11 
     12 # Device types.
     13 DEVICE_TYPE_UNKNOWN = 0
     14 DEVICE_TYPE_MBIM = 1
     15 DEVICE_TYPE_NCM_MBIM = 2
     16 # MBIM Communication interface codes
     17 INTERFACE_MBIM_CLASS = 0x02
     18 INTERFACE_MBIM_SUBCLASS = 0x0E
     19 INTERFACE_MBIM_PROTOCOL = 0x00
     20 
     21 
     22 class MbimDeviceContext:
     23     """ Context of device under test. """
     24 
     25     def __init__(self, id_vendor=None, id_product=None):
     26         """
     27         Initialize the MBIM modem device test context.
     28 
     29         @param id_vendor: Specific vendor ID for the modem to be tested.
     30         @param id_product: Specific product ID for the modem to be tested.
     31 
     32         """
     33         # Find the device to be tested
     34         self._device = self._find_device(id_vendor, id_product)
     35         # Set the device vendor/product ID in the test context
     36         self._id_vendor = self._device.idVendor
     37         self._id_product = self._device.idProduct
     38 
     39         # TODO(mcchou): Generalize the order of running sequence and tests by
     40         # extracting the information retrieval logic as utility functions.
     41         # These utility functions will be used by |get_descriptors_sequence| and
     42         # DES_xx tests. Instead of retrieving information from DES_xx tests,
     43         # the information should be obtained from |get_descriptors_sequence|.
     44 
     45         # Once a device has been discovered, and its USB descriptors have been
     46         # parsed, this property determines whether the discovered device is an
     47         # MBIM only function (DEVICE_TYPE_MBIM) or an NCM/MBIM combined function
     48         # (DEVICE_TYPE_NCM_MBIM). The other |*_interface| properties are
     49         # determined accordingly.
     50         self.device_type = DEVICE_TYPE_UNKNOWN
     51 
     52         # The USB descriptor for the communication interface for the modem. This
     53         # descirptor corresponds to the alternate setting of the interface over
     54         # which mbim control command can be transferred.
     55         self.mbim_communication_interface = None
     56 
     57         # The USB descriptor for the communication interface for the modem. This
     58         # descriptor corresponds to the alternate setting of the interface over
     59         # which ncm control command can be transferred.
     60         self.ncm_communication_interface = None
     61 
     62         # The USB descriptor for the CDC Data interface for the modem. This
     63         # descriptor corresponds to the alternate setting of the interface over
     64         # which no data can be transferred.
     65         self.no_data_data_interface = None
     66 
     67         # The USB descriptor for the CDC Data interface for the modem. This
     68         # descriptor corresponds to the alternate setting of the interface over
     69         # which MBIM data must be transferred.
     70         self.mbim_data_interface = None
     71 
     72         # The USB descriptor for the CDC Data interface for the modem. This
     73         # descriptor corresponds to the alternate setting of the interface over
     74         # which NCM data must be transferred.
     75         self.ncm_data_interface = None
     76 
     77         # The USB descriptor for the MBIM functional settings for the modem.
     78         # This descriptor corresponds to the MBIM functional descriptor in the
     79         # MBIM communication interface settings.
     80         self.mbim_functional = None
     81 
     82         # The USB descriptor for the interrupt endpoint. This descriptor
     83         # corresponds to the interrupt endpoint in the MBIM communication
     84         # interface where MBIM control messages are sent and received.
     85         self.interrupt_endpoint = None
     86 
     87 
     88     def _find_device(self, id_vendor, id_product):
     89         """
     90         Find and initialize the MBIM modem device under consideration.
     91 
     92         @param id_vendor: Specific vendor ID for the modem to be tested.
     93         @param id_product: Specific product ID for the modem to be tested.
     94         @returns The PyUSB handle to the device.
     95 
     96         """
     97         # If a specific device VID/PID is sent, we'll use that info to find
     98         # the modem, else we'll try to find any MBIM CDC device attached
     99         if id_vendor is not None and id_product is not None:
    100             device = core.find(idVendor=id_vendor, idProduct=id_product)
    101             if device is None:
    102                 mbim_errors.log_and_raise(
    103                         mbim_errors.MBIMComplianceFrameworkError,
    104                         'Device not found with VID: %04X, PID: %04X. ' % (
    105                                 id_vendor, id_product))
    106         else:
    107             # Find device based on the communication class interface descriptor
    108             devices = core.find(
    109                     find_all=1,
    110                     custom_match=(lambda device: self._device_interface_matcher(
    111                             device,
    112                             interface_class=INTERFACE_MBIM_CLASS,
    113                             interface_subclass=INTERFACE_MBIM_SUBCLASS,
    114                             interface_protocol=INTERFACE_MBIM_PROTOCOL)))
    115             if not devices:
    116                 mbim_errors.log_and_raise(
    117                         mbim_errors.MBIMComplianceFrameworkError,
    118                         'MBIM device not found. ')
    119             elif len(devices) > 1:
    120                 mbim_errors.log_and_raise(
    121                         mbim_errors.MBIMComplianceFrameworkError,
    122                         'More than one MBIM device found: %d. ' %
    123                         len(devices))
    124             else:
    125                 device = devices[0]
    126         return device
    127 
    128 
    129     def _device_interface_matcher(self,
    130                                   device,
    131                                   interface_class,
    132                                   interface_subclass,
    133                                   interface_protocol):
    134         """
    135         Find the USB device with a specific set of interface parameters.
    136 
    137         Go thru all the USB configurations and find an interface
    138         descriptor that matches the specified class, subclass and
    139         protocol.
    140 
    141         @param device: USB device under consideration.
    142         @param interface_class: Class ID to be matched in Interface
    143                                 descriptor.
    144         @param interface_sub_class: Sub class ID to be matched in
    145                                     Interface descriptor.
    146         @param interface_protocol: Protocol ID to be matched in
    147                                    Interface descriptor.
    148         @returns True if the device's interface descriptor matches,
    149                  False otherwise.
    150         """
    151         for cfg in device:
    152             interface = usb_util.find_descriptor(
    153                     cfg,
    154                     bInterfaceClass=interface_class,
    155                     bInterfaceSubClass=interface_subclass,
    156                     bInterfaceProtocol=interface_protocol)
    157             if interface is not None:
    158                 return True
    159         return False
    160 
    161 
    162     def update_descriptor_cache(self, descriptors):
    163         """
    164         Fetch and store the MBIM descriptor cache into the test context.
    165 
    166         @param descriptors: Raw descriptor set obtained from the device.
    167                             Type: Array of |usb_descriptors.Descriptor| objects.
    168 
    169         """
    170         self.descriptor_cache = (
    171                 mbim_descriptor_cache.MbimDescriptorCache(descriptors))
    172         if self.descriptor_cache.is_mbim_only:
    173             self.device_type = DEVICE_TYPE_MBIM
    174         else:
    175             self.device_type = DEVICE_TYPE_NCM_MBIM
    176 
    177 
    178     @property
    179     def id_vendor(self):
    180         """
    181         Refer to the idVendor for the device under test.
    182 
    183         @returns The value of idVendor.
    184 
    185         """
    186         return self._id_vendor
    187 
    188 
    189     @property
    190     def id_product(self):
    191         """
    192         Refer to the idProduct for the device under test.
    193 
    194         @returns The value of idProduct.
    195 
    196         """
    197         return self._id_product
    198 
    199 
    200     @property
    201     def device(self):
    202         """
    203         Refer to the device under test.
    204 
    205         @returns The usb.core.Device object.
    206 
    207         """
    208         return self._device
    209