• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021 The ChromiumOS Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4"""Plugin for merging HWID information into ConfigBundle format"""
5
6import copy
7import logging as _logging
8import re
9import yaml
10
11from chromiumos.config.api.component_pb2 import Component
12from chromiumos.config.payload.config_bundle_pb2 import ConfigBundle
13
14from common import config_bundle_utils as cbu
15from .merge_plugin import MergePlugin
16
17# Create named logger
18logging = _logging.getLogger(__name__)
19
20
21def _include_item(item):
22  """Predicate to determine whether to include a HWID item.
23
24  Modify this to add additional exclusion conditions.
25  """
26
27  # Status values that indicate we should exclude the item
28  bad_status_values = set([])
29
30  if not item['values']:
31    return False
32
33  if item.get('status', '').lower() in bad_status_values:
34    return False
35
36  return True
37
38
39def _set_support_status(component, item):
40  """Set the supported_status field of a component from its status."""
41
42  status = item.get('status')
43  if not status:
44    return component
45
46  status_map = {
47      'deprecated': component.SupportStatus.STATUS_DEPRECATED,
48      'supported': component.SupportStatus.STATUS_SUPPORTED,
49      'unqualified': component.SupportStatus.STATUS_UNQUALIFIED,
50      'unsupported': component.SupportStatus.STATUS_UNSUPPORTED,
51  }
52
53  component.support_status = status_map.get(
54      status.lower(),
55      component.SupportStatus.STATUS_UNKNOWN,
56  )
57
58  return component
59
60
61def _maybe_delete(val, key):
62  """Delete key from dict, but degrade to noop if it's not present."""
63  if key in val:
64    del val[key]
65
66
67def _del_if_empty(val, key):
68  """Delete a key from a dict if it's empty"""
69  if key in val and not val[key]:
70    del val[key]
71
72
73def _non_null_items(items):
74  """Unwrap a HWID item block into a dictionary for non-null values.
75
76  a HWID item block looks like:
77    items:
78      storage_device:
79        status: unsupported
80        values:
81          class: '0x010101'
82          device: '0xff00'
83          sectors: '5000000'
84          vendor: '0xbeef'
85      some_hardware:
86         values:
87      FAKE_RAM_CHIP:
88        values:
89          class: '0x010101'
90          device: '0xff00'
91          sectors: '250000000'
92          vendor: '0xabcd'
93
94  We'll iterate over the items and check whether it should be excluded
95  based on _include_item.
96
97  The resulting output is a dict with unwrapped item values:
98    {
99      'storage_device': {'class' : '0x010101', ...},
100      ...
101    }
102  """
103  return {key: item for key, item in items.items() if _include_item(item)}
104
105
106class MergeHwid(MergePlugin):
107  """Merge plugin for HWID files.
108
109  After calling merge(), residual() can be called to get an object containing
110  any remaining values in the HWID data.
111  """
112
113  def __init__(self, hwid_path=None, hwid_data=None):
114    """Create a new HWID merger.
115
116    Args:
117      hwid_path (str): Path to the HWID file on disk to read
118      hwid_data (dict): HWID data specified directly
119    """
120
121    if hwid_path and hwid_data:
122      raise RuntimeError('Only one of hwid_path or hwid_data can be specified')
123
124    if hwid_path:
125      with open(hwid_path, 'r', encoding='utf-8') as hwid_file:
126        self.data = yaml.load(hwid_file, Loader=yaml.SafeLoader)
127    else:
128      self.data = copy.deepcopy(hwid_data)
129
130    # We're not interested in the details of the HWID encoding so remove those
131    # fields from the residual
132    _maybe_delete(self.data, 'pattern')
133    _maybe_delete(self.data, 'encoded_fields')
134    _maybe_delete(self.data, 'encoding_patterns')
135
136    # And remove any other fields that would just be residual noise
137    _maybe_delete(self.data, 'checksum')
138    _maybe_delete(self.data, 'image_id')
139    _maybe_delete(self.data, 'rules')
140    _maybe_delete(self.data, 'project')
141
142  def residual(self):
143    """Get any remaining data that hasn't been parsed."""
144    return self.data
145
146  def merge(self, bundle: ConfigBundle):
147    """Merge our data into the given ConfigBundle instance."""
148    components = self.data['components']
149    for component_type in list(components.keys()):
150      value = components[component_type]
151      if not value:
152        _del_if_empty(components, component_type)
153        continue
154
155      # yapf: disable
156      callback = {
157        'audio_codec':         MergeHwid._merge_audio,
158        'battery':             MergeHwid._merge_battery,
159        'bluetooth':           MergeHwid._merge_bluetooth,
160        'cellular':            MergeHwid._merge_cellular,
161        'cpu':                 MergeHwid._merge_cpu,
162        'display_panel':       MergeHwid._merge_display_panel,
163        'dram':                MergeHwid._merge_dram,
164        'ec_flash_chip':       MergeHwid._merge_ec_flash,
165        'embedded_controller': MergeHwid._merge_ec,
166        'flash_chip':          MergeHwid._merge_flash,
167        'storage':             MergeHwid._merge_storage,
168        'stylus':              MergeHwid._merge_stylus,
169        'touchpad':            MergeHwid._merge_touchpad,
170        'tpm':                 MergeHwid._merge_tpm,
171        'touchscreen':         MergeHwid._merge_touchscreen,
172        'usb_hosts':           MergeHwid._merge_usb_hosts,
173        'video':               MergeHwid._merge_video,
174        'wireless':            MergeHwid._merge_wireless,
175      }.get(component_type)
176      # yapf: enable
177
178      if callback:
179        value['items'] = _non_null_items(value['items'])
180        MergeHwid._iterate_items(bundle, value['items'], callback)
181
182        _del_if_empty(value, 'items')
183        _del_if_empty(components, component_type)
184
185    _del_if_empty(self.data, 'components')
186
187  @staticmethod
188  def _iterate_items(bundle, items, callback):
189    """Iterate items in an item dict and call callback on them.
190
191    Handle boilerplate for callbacks to delete empty/touched
192    fields as we go to leave an informative residual.
193
194    Callbacks must take a ConfigBundle and an item and return
195    an iterable of fields in the item that were touched/used.
196
197    Args:
198      bundle: ConfigBundle instance to modify
199      items:  dict of label => [item]
200      callback: callback to process a single item.
201    """
202
203    # Copy keys list so that we can remove from items as we go.
204    for label in list(items.keys()):
205      item = items[label]
206      touched = callback(bundle, label, item)
207
208      values = item.get('values', {})
209      for name in touched:
210        _maybe_delete(values, name)
211
212      _del_if_empty(item, 'values')
213      _del_if_empty(items, label)
214
215  @staticmethod
216  def _merge_audio(bundle, label, item):
217    """Merge audio_codec items."""
218    values = item.get('values', {})
219
220    component = cbu.find_component(bundle, id_value=label, create=True)
221    component = _set_support_status(component, item)
222
223    # save HWID values
224    component.hwid_type = 'audio_codec'
225    component.hwid_label = label
226
227    # configure component
228    component.name = values.get('name', label)
229    component.audio_codec.name = component.name
230
231    return ['name']
232
233  @staticmethod
234  def _merge_battery(bundle, label, item):
235    """Merge battery items."""
236    values = item.get('values', {})
237
238    touched = set()
239
240    component = cbu.find_component(bundle, id_value=label, create=True)
241    component = _set_support_status(component, item)
242    component.name = component.id.value
243
244    # save HWID values
245    component.hwid_type = 'battery'
246    component.hwid_label = label
247
248    # lookup or create manufacturer
249    if 'manufacturer' in values:
250      # We seem to have some bad manufacturer values in the battery component.
251      # If we can't decode them to a valid unicode string, skip them.
252      mfgr = values['manufacturer']
253      if isinstance(mfgr, bytes):
254        try:
255          mfgr = mfgr.decode()
256        except UnicodeDecodeError as exception:
257          logging.error("Error decoding '%s' to string: %s", mfgr, exception)
258          return set()
259
260      component.manufacturer_id.MergeFrom(
261          cbu.find_partner(bundle, mfgr, create=True).id)
262      touched.add('manufacturer')
263
264    # set model
265    if 'model_name' in values:
266      component.battery.model = values['model_name']
267      touched.add('model_name')
268
269    # set battery technology
270    if 'technology' in values:
271      tech = values['technology'].lower().replace('-', '')
272
273      tech_map = {
274          'liion': Component.Battery.LI_ION,
275          'lipoly': Component.Battery.LI_POLY,
276      }
277
278      if tech in tech_map:
279        component.battery.technology = tech_map[tech]
280        touched.add('technology')
281
282    return touched
283
284  @staticmethod
285  def _merge_bluetooth(bundle, label, item):
286    """Merge bluetooth items."""
287    values = item.get('values', {})
288
289    touched = set()
290
291    component = cbu.find_component(bundle, id_value=label, create=True)
292    component = _set_support_status(component, item)
293    component.name = component.id.value
294
295    # save HWID values
296    component.hwid_type = 'bluetooth'
297    component.hwid_label = label
298
299    # lookup or create manufacturer
300    if 'manufacturer' in values:
301      component.manufacturer_id.MergeFrom(
302          cbu.find_partner(bundle, values['manufacturer'], create=True).id)
303      touched.add('manufacturer')
304
305    fields = [
306        ('vendor_id', 'idVendor'),
307        ('product_id', 'idProduct'),
308        ('bcd_device', 'bcdDevice'),
309    ]
310
311    for attr, key in fields:
312      if key in values:
313        setattr(component.bluetooth.usb, attr, values[key])
314        touched.add(key)
315
316    return touched
317
318  @staticmethod
319  def _merge_cellular(bundle, label, item):
320    """Merge cellular items."""
321    values = item.get('values', {})
322
323    touched = set()
324
325    component = cbu.find_component(bundle, id_value=label, create=True)
326    component = _set_support_status(component, item)
327    component.name = component.id.value
328
329    # save HWID values
330    component.hwid_type = 'cellular'
331    component.hwid_label = label
332
333    # lookup or create manufacturer
334    if 'manufacturer' in values:
335      component.manufacturer_id.MergeFrom(
336          cbu.find_partner(bundle, values['manufacturer'], create=True).id)
337      touched.add('manufacturer')
338
339    fields = [
340        ('vendor_id', 'idVendor'),
341        ('product_id', 'idProduct'),
342        ('bcd_device', 'bcdDevice'),
343    ]
344
345    for attr, key in fields:
346      if key in values:
347        setattr(component.cellular.usb, attr, values[key])
348        touched.add(key)
349
350    return touched
351
352  @staticmethod
353  def _merge_cpu(bundle, label, item):
354    """Merge cpu items."""
355    values = item.get('values', {})
356
357    touched = set()
358
359    component = cbu.find_component(bundle, id_value=label, create=True)
360    component = _set_support_status(component, item)
361    component.name = component.id.value
362
363    # save HWID values
364    component.hwid_type = 'cpu'
365    component.hwid_label = label
366
367    model_re = re.compile(  # reversed from HWID cpu model values
368        '(a[0-9]?-[0-9]+[a-z]?|(m3-|i3-|i5-|i7-)*[0-9y]{4,5}[uy]?|n[0-9]{4})')
369
370    component.soc.cores = int(values.get('cores', 0))
371    touched.add('cores')
372
373    if 'model' in values:
374      component.soc.model = values['model']
375      touched.add('model')
376
377      model_string = values['model'].lower()
378      if 'intel' in model_string or 'amd' in model_string:
379        component.soc.family.arch = component.soc.X86_64
380      elif 'aarch64' in model_string or 'armv8' in model_string:
381        component.soc.family.arch = component.soc.ARM64
382      elif 'armv7' in model_string:
383        component.soc.family.arch = component.soc.ARM
384      else:
385        logging.warning('unknown family for cpu model \'%s\'', model_string)
386
387      match = model_re.search(model_string)
388      if match:
389        component.soc.family.name = match.group(0).upper()
390
391    return touched
392
393  @staticmethod
394  def _merge_display_panel(bundle, label, item):
395    """Merge display panel items."""
396    values = item.get('values', {})
397
398    component = cbu.find_component(bundle, id_value=label, create=True)
399    component = _set_support_status(component, item)
400    component.name = component.id.value
401
402    # save HWID values
403    component.hwid_type = 'display_panel'
404    component.hwid_label = label
405
406    if 'vendor' in values:
407      component.manufacturer_id.MergeFrom(
408          cbu.find_partner(bundle, values['vendor'], create=True).id)
409
410    component.display_panel.product_id = values.get('product_id', '')
411    component.display_panel.properties.width_px = int(values.get('width', 0))
412    component.display_panel.properties.height_px = int(values.get('height', 0))
413
414    return set(['vendor', 'product_id', 'width', 'height'])
415
416  @staticmethod
417  def _merge_dram(bundle, label, item):
418    """Merge dram items."""
419    values = item.get('values', {})
420
421    component = cbu.find_component(bundle, id_value=label, create=True)
422    component = _set_support_status(component, item)
423    component.name = component.id.value
424
425    # save HWID values
426    component.hwid_type = 'dram'
427    component.hwid_label = label
428
429    component.memory.part_number = values.get('part', '')
430    component.memory.profile.size_megabytes = int(values.get('size', 0))
431
432    if 'timing' in values:
433      memory_type = values['timing'].split('-')[0]
434      if memory_type == 'LPDDR4':
435        component.memory.profile.type = component.memory.LP_DDR4
436      elif memory_type == 'LPDDR3':
437        component.memory.profile.type = component.memory.LP_DDR3
438      elif memory_type == 'DDR4':
439        component.memory.profile.type = component.memory.DDR4
440      elif memory_type == 'DDR3':
441        component.memory.profile.type = component.memory.DDR3
442      elif memory_type == 'DDR2':
443        component.memory.profile.type = component.memory.DDR2
444      elif memory_type == 'DDR':
445        component.memory.profile.type = component.memory.DDR
446
447    return set(['part', 'size', 'timing'])
448
449  @staticmethod
450  def _merge_ec_flash(bundle, label, item):
451    """Merge EC flash items."""
452    values = item.get('values', {})
453
454    touched = set()
455
456    component = cbu.find_component(bundle, id_value=label, create=True)
457    component = _set_support_status(component, item)
458    component.name = component.id.value
459
460    # save HWID values
461    component.hwid_type = 'ec_flash_chip'
462    component.hwid_label = label
463
464    component.ec_flash_chip.part_number = values.get('name', '')
465    touched.add('name')
466
467    if 'vendor' in values:
468      component.manufacturer_id.MergeFrom(
469          cbu.find_partner(bundle, values['vendor'], create=True).id)
470      touched.add('vendor')
471
472    return touched
473
474  @staticmethod
475  def _merge_ec(bundle, label, item):
476    """Merge EC items."""
477    values = item.get('values', {})
478
479    touched = set()
480
481    component = cbu.find_component(bundle, id_value=label, create=True)
482    component = _set_support_status(component, item)
483    component.name = component.id.value
484
485    # save HWID values
486    component.hwid_type = 'embedded_controller'
487    component.hwid_label = label
488
489    component.ec.part_number = values.get('name', '')
490    touched.add('name')
491
492    if 'vendor' in values:
493      component.manufacturer_id.MergeFrom(
494          cbu.find_partner(bundle, values['vendor'], create=True).id)
495      touched.add('vendor')
496
497    return touched
498
499  @staticmethod
500  def _merge_flash(bundle, label, item):
501    """Merge flash items."""
502    values = item.get('values', {})
503
504    touched = set()
505
506    component = cbu.find_component(bundle, id_value=label, create=True)
507    component = _set_support_status(component, item)
508    component.name = component.id.value
509
510    # save HWID values
511    component.hwid_type = 'flash_chip'
512    component.hwid_label = label
513
514    component.system_flash_chip.part_number = values.get('name', '')
515    touched.add('name')
516
517    if 'vendor' in values:
518      component.manufacturer_id.MergeFrom(
519          cbu.find_partner(bundle, values['vendor'], create=True).id)
520      touched.add('vendor')
521
522    return touched
523
524  @staticmethod
525  def _merge_storage(bundle, label, item):
526    """Merge storage items."""
527    values = item.get('values', {})
528
529    touched = set()
530
531    component = cbu.find_component(bundle, id_value=label, create=True)
532    component = _set_support_status(component, item)
533    component.name = values.get('model', label)
534    touched.add('model')
535
536    # save HWID values
537    component.hwid_type = 'storage'
538    component.hwid_label = label
539
540    component.storage.emmc5_fw_ver = values.get('emmc5_fw_ver', '')
541    component.storage.manfid = values.get('manfid', '')
542    component.storage.name = values.get('name', '')
543    component.storage.oemid = values.get('oemid', '')
544    component.storage.prv = values.get('prv', '')
545    component.storage.sectors = values.get('sectors', '')
546
547    touched.update(
548        ['emmc5_fw_ver', 'manfid', 'name', 'oemid', 'prv', 'sectors'])
549
550    pcie_fields = ['class', 'device', 'vendor']
551    if all(field in values for field in pcie_fields):
552      component.storage.type = component.storage.NVME
553      component.storage.pci.vendor_id = values['vendor']
554      component.storage.pci.device_id = values['device']
555      component.storage.pci.class_id = values['class']
556      touched.update(pcie_fields)
557
558    if values.get('type', '').lower() == 'mmc':
559      component.storage.type = component.storage.EMMC
560    touched.add('type')
561
562    if values.get('vendor', '').lower() == 'ata':
563      component.storage.type = component.storage.SATA
564    touched.add('vendor')
565
566    return touched
567
568  @staticmethod
569  def _merge_stylus(bundle, label, item):
570    """Merge stylus items."""
571    values = item.get('values', {})
572
573    touched = set()
574
575    component = cbu.find_component(bundle, id_value=label, create=True)
576    component = _set_support_status(component, item)
577    component.name = values.get('name', label)
578    touched.add('name')
579
580    # save HWID values
581    component.hwid_type = 'stylus'
582    component.hwid_label = label
583
584    i2c_keys = ['product', 'vendor']
585    if all(key in values for key in i2c_keys):
586      component.stylus.i2c.product = values['product']
587      component.stylus.i2c.vendor = values['vendor']
588      touched.update(i2c_keys)
589
590    usb_keys = ['product_id', 'vendor_id']
591    if all(key in values for key in usb_keys):
592      component.stylus.usb.product_id = values['product_id']
593      component.stylus.usb.vendor_id = values['vendor_id']
594      touched.update(usb_keys)
595
596      if 'bcd_device' in values:
597        component.stylus.usb.bcd_device = values['bcd_device']
598      touched.add('bcd_device')
599
600      if 'version' in values:
601        component.stylus.usb.bcd_device = values['version']
602      touched.add('version')
603
604    return touched
605
606  @staticmethod
607  def _merge_touchpad(bundle, label, item):
608    """Merge touchpad items."""
609    values = item.get('values', {})
610
611    touched = set()
612
613    component = cbu.find_component(bundle, id_value=label, create=True)
614    component = _set_support_status(component, item)
615    component.name = values.get('model', label)
616    touched.add('model')
617
618    # save HWID values
619    component.hwid_type = 'touchpad'
620    component.hwid_label = label
621
622    # Check for USB based touchpad
623    # We don't receive an explicit type for the touchpad bus type, so
624    # we assume that if we have a product and vendor id, that it's USB,
625    # otherwise it's I2C (rare)
626    if 'product' in values and 'vendor' in values:
627      component.touchpad.type = component.touchpad.USB
628      component.touchpad.product_id = component.name
629      component.touchpad.usb.vendor_id = values['vendor']
630      component.touchpad.usb.product_id = values['product']
631      touched.update(['vendor', 'product'])
632
633    elif 'fw_version' in values and 'fw_csum' in values:
634      # i2c based touchpad
635      component.touchpad.type = component.touchpad.I2C
636      component.touchpad.product_id = values.get('product_id', '')
637      component.touchpad.fw_version = values['fw_version']
638      component.touchpad.fw_checksum = values['fw_csum']
639      touched.update(['fw_version', 'fw_csum', 'product_id'])
640
641    return touched
642
643  @staticmethod
644  def _merge_tpm(bundle, label, item):
645    """Merge tpm items."""
646    values = item.get('values', {})
647
648    touched = set()
649
650    component = cbu.find_component(bundle, id_value=label, create=True)
651    component = _set_support_status(component, item)
652    component.name = label
653
654    # save HWID values
655    component.hwid_type = 'tpm'
656    component.hwid_label = label
657
658    component.tpm.manufacturer_info = values.get('manufacturer_info', '')
659    component.tpm.version = values.get('version', '')
660
661    touched.update(['manufacturer_info', 'version'])
662    return touched
663
664  @staticmethod
665  def _merge_touchscreen(bundle, label, item):
666    """Merge touchscreen items."""
667    values = item.get('values', {})
668
669    touched = set()
670
671    component = cbu.find_component(bundle, id_value=label, create=True)
672    component = _set_support_status(component, item)
673    component.name = values.get('name', label)
674    touched.add('name')
675
676    # save HWID values
677    component.hwid_type = 'touchscreen'
678    component.hwid_label = label
679
680    def oneof(values, keys, default=""):
681      for key in keys:
682        if key in values:
683          return values[key]
684      return default
685
686    component.touchscreen.product_id = label
687    component.touchscreen.usb.product_id = oneof(
688        values,
689        ['product', 'product_id'],
690    )
691    component.touchscreen.usb.vendor_id = oneof(values, ['vendor', 'vendor_id'])
692    component.touchscreen.usb.bcd_device = values.get('bcd_device', '')
693
694    if all([
695        component.touchscreen.usb.product_id,
696        component.touchscreen.usb.vendor_id
697    ]):
698      component.touchscreen.type = component.touchscreen.USB
699
700    touched.update(
701        ['product', 'product_id', 'vendor', 'vendor_id', 'bcd_device'])
702    return touched
703
704  @staticmethod
705  def _merge_usb_hosts(bundle, label, item):
706    """Merge USB host items."""
707    values = item.get('values', {})
708
709    touched = set()
710
711    component = cbu.find_component(bundle, id_value=label, create=True)
712    component = _set_support_status(component, item)
713    component.name = values.get('product', label)
714    touched.add('product')
715
716    # save HWID values
717    component.hwid_type = 'usb_hosts'
718    component.hwid_label = label
719
720    def get_oneof(obj, keys, default=None):
721      """Get one of a set of keys from values, or return a default value."""
722      for key in keys:
723        if key in obj:
724          touched.add(key)
725          return obj[key]
726      return default
727
728    if 'manufacturer' in values:
729      component.manufacturer_id.MergeFrom(
730          cbu.find_partner(bundle, values['manufacturer'], create=True).id)
731      touched.add('manufacturer')
732
733    host = component.usb_host
734    host.product_id = get_oneof(values, ['idProduct', 'device'], '')
735    host.vendor_id = get_oneof(values, ['idVendor', 'vendor'], '')
736    host.bcd_device = get_oneof(values, ['bcdDevice', 'revision_id'], '')
737
738    return touched
739
740  @staticmethod
741  def _merge_video(bundle, label, item):
742    """Merge video items."""
743    values = item.get('values', {})
744
745    touched = set()
746
747    component = cbu.find_component(bundle, id_value=label, create=True)
748    component = _set_support_status(component, item)
749    component.name = values.get('product', label)
750    touched.add('product')
751
752    # save HWID values
753    component.hwid_type = 'video'
754    component.hwid_label = label
755
756    usb_fields = ['bcdDevice', 'idProduct', 'idVendor']
757    pci_fields = ['vendor', 'device', 'revision_id']
758
759    if values.get('bus_type') == 'usb' or \
760       all(key in values for key in usb_fields):
761
762      if 'manufacturer' in values:
763        component.manufacturer_id.MergeFrom(
764            cbu.find_partner(bundle, values['manufacturer'], create=True).id)
765
766      component.camera.usb.vendor_id = values.get('idVendor', '')
767      component.camera.usb.product_id = values.get('idProduct', '')
768      component.camera.usb.bcd_device = values.get('bcdDevice', '')
769      touched.update(usb_fields)
770
771    if values.get('bus_type') == 'pci' or \
772       all(key in values for key in pci_fields):
773
774      component.camera.pci.vendor_id = values.get('vendor', '')
775      component.camera.pci.device_id = values.get('device', '')
776      component.camera.pci.revision_id = values.get('revision_id', '')
777      touched.update(pci_fields)
778
779    touched.add('bus_type')
780    return touched
781
782  @staticmethod
783  def _merge_wireless(bundle, label, item):
784    """Merge wireless items."""
785    values = item.get('values', {})
786
787    touched = set()
788
789    component = cbu.find_component(bundle, id_value=label, create=True)
790    component = _set_support_status(component, item)
791    component.name = label
792
793    # save HWID values
794    component.hwid_type = 'wireless'
795    component.hwid_label = label
796
797    component.wifi.pci.vendor_id = values.get('vendor', '')
798    component.wifi.pci.device_id = values.get('device', '')
799    component.wifi.pci.revision_id = values.get('revision_id', '')
800    touched.update(['vendor', 'device', 'revision_id'])
801    return touched
802