#!/usr/bin/env python # # PCI Device Information Class # - Helps obtain information about which I/O resources a PCI device needs # # Author: Ryan Wilson import sys import os, os.path import errno import resource import re import types import struct import time import threading from xen.util import utils from xen.xend import uuid from xen.xend import sxp from xen.xend.XendConstants import AUTO_PHP_SLOT from xen.xend.XendSXPDev import dev_dict_to_sxp from xen.xend.XendLogging import log # for 2.3 compatibility try: set() except NameError: from sets import Set as set PROC_PCI_PATH = '/proc/bus/pci/devices' PROC_PCI_NUM_RESOURCES = 7 SYSFS_PCI_DEVS_PATH = '/bus/pci/devices' SYSFS_PCI_DEV_RESOURCE_PATH = '/resource' SYSFS_PCI_DEV_CONFIG_PATH = '/config' SYSFS_PCI_DEV_IRQ_PATH = '/irq' SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver' SYSFS_PCI_DEV_VENDOR_PATH = '/vendor' SYSFS_PCI_DEV_DEVICE_PATH = '/device' SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor' SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device' SYSFS_PCI_DEV_CLASS_PATH = '/class' SYSFS_PCIBACK_PATH = '/bus/pci/drivers/pciback/' SYSFS_PCISTUB_PATH = '/bus/pci/drivers/pci-stub/' LSPCI_CMD = 'lspci' PCI_DEV_REG_EXPRESS_STR = r"[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}."+ \ r"[0-9a-fA-F]{1}" DEV_TYPE_PCIe_ENDPOINT = 0 DEV_TYPE_PCIe_BRIDGE = 1 DEV_TYPE_PCI_BRIDGE = 2 DEV_TYPE_PCI = 3 PCI_VENDOR_ID = 0x0 PCI_STATUS = 0x6 PCI_CLASS_DEVICE = 0x0a PCI_CLASS_BRIDGE_PCI = 0x0604 PCI_HEADER_TYPE = 0x0e PCI_HEADER_TYPE_MASK = 0x7f PCI_HEADER_TYPE_NORMAL = 0 PCI_HEADER_TYPE_BRIDGE = 1 PCI_HEADER_TYPE_CARDBUS = 2 PCI_CAPABILITY_LIST = 0x34 PCI_CB_BRIDGE_CONTROL = 0x3e PCI_BRIDGE_CTL_BUS_RESET= 0x40 PCI_CAP_ID_EXP = 0x10 PCI_EXP_FLAGS = 0x2 PCI_EXP_FLAGS_TYPE = 0x00f0 PCI_EXP_TYPE_DOWNSTREAM = 0x6 PCI_EXP_TYPE_PCI_BRIDGE = 0x7 PCI_EXP_DEVCAP = 0x4 PCI_EXP_DEVCAP_FLR = (0x1 << 28) PCI_EXP_DEVCTL = 0x8 PCI_EXP_DEVCTL_FLR = (0x1 << 15) PCI_EXT_CAP_ID_ACS = 0x000d PCI_EXT_CAP_ACS_ENABLED = 0x1d # The bits V, R, C, U. PCI_EXT_ACS_CTRL = 0x06 PCI_CAP_ID_PM = 0x01 PCI_PM_CTRL = 4 PCI_PM_CTRL_NO_SOFT_RESET = 0x0008 PCI_PM_CTRL_STATE_MASK = 0x0003 PCI_D3hot = 3 PCI_D0hot = 0 VENDOR_INTEL = 0x8086 PCI_CAP_ID_VENDOR_SPECIFIC_CAP = 0x09 PCI_CLASS_ID_USB = 0x0c03 PCI_USB_FLRCTRL = 0x4 PCI_DEVICE_ID = 0x02 PCI_COMMAND = 0x04 PCI_CLASS_ID_VGA = 0x0300 PCI_DEVICE_ID_IGFX_GM45 = 0x2a42 PCI_DEVICE_ID_IGFX_EAGLELAKE = 0x2e02 PCI_DEVICE_ID_IGFX_Q45 = 0x2e12 PCI_DEVICE_ID_IGFX_G45 = 0x2e22 PCI_DEVICE_ID_IGFX_G41 = 0x2e32 PCI_CAP_IGFX_CAP09_OFFSET = 0xa4 PCI_CAP_IGFX_CAP13_OFFSET = 0xa4 PCI_CAP_IGFX_GDRST = 0X0d PCI_CAP_IGFX_GDRST_OFFSET = 0xc0 # The VF of Intel 82599 10GbE Controller # See http://download.intel.com/design/network/datashts/82599_datasheet.pdf # For 'VF PCIe Configuration Space', see its Table 9.7. DEVICE_ID_82599 = 0x10ed PCI_CAP_ID_AF = 0x13 PCI_AF_CAPs = 0x3 PCI_AF_CAPs_TP_FLR = 0x3 PCI_AF_CTL = 0x4 PCI_AF_CTL_FLR = 0x1 PCI_BAR_0 = 0x10 PCI_BAR_5 = 0x24 PCI_BAR_SPACE = 0x01 PCI_BAR_IO = 0x01 PCI_BAR_IO_MASK = ~0x03 PCI_BAR_MEM = 0x00 PCI_BAR_MEM_MASK = ~0x0f PCI_STATUS_CAP_MASK = 0x10 PCI_STATUS_OFFSET = 0x6 PCI_CAP_OFFSET = 0x34 MSIX_BIR_MASK = 0x7 MSIX_SIZE_MASK = 0x7ff # Global variable to store information from lspci lspci_info = None lspci_info_lock = threading.RLock() #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number PAGE_SIZE = resource.getpagesize() PAGE_SHIFT = 0 t = PAGE_SIZE while not (t&1): t>>=1 PAGE_SHIFT+=1 PAGE_MASK=~(PAGE_SIZE - 1) # Definitions from Linux: include/linux/pci.h def PCI_DEVFN(slot, func): return ((((slot) & 0x1f) << 3) | ((func) & 0x07)) def PCI_SLOT(devfn): return (devfn >> 3) & 0x1f def PCI_FUNC(devfn): return devfn & 0x7 def PCI_BDF(domain, bus, slot, func): return (((domain & 0xffff) << 16) | ((bus & 0xff) << 8) | PCI_DEVFN(slot, func)) def check_pci_opts(opts): def f((k, v)): if k not in ['msitranslate', 'power_mgmt'] or \ not v.lower() in ['0', '1', 'yes', 'no']: raise PciDeviceParseError('Invalid pci option %s=%s: ' % (k, v)) map(f, opts) def serialise_pci_opts(opts): return ','.join(map(lambda x: '='.join(x), opts)) def split_pci_opts(opts): return map(lambda x: x.split('='), filter(lambda x: x != '', opts.split(','))) def append_default_pci_opts(opts, defopts): optsdict = dict(opts) return opts + filter(lambda (k, v): not optsdict.has_key(k), defopts) def pci_opts_list_to_sxp(list): return dev_dict_to_sxp({'opts': list}) def pci_opts_list_from_sxp(dev): return map(lambda x: sxp.children(x)[0], sxp.children(dev, 'opts')) def pci_convert_dict_to_sxp(dev, state, sub_state = None): pci_sxp = ['pci', dev_dict_to_sxp(dev), ['state', state]] if sub_state != None: pci_sxp.append(['sub_state', sub_state]) return pci_sxp def pci_convert_sxp_to_dict(dev_sxp): """Convert pci device sxp to dict @param dev_sxp: device configuration @type dev_sxp: SXP object (parsed config) @return: dev_config @rtype: dictionary """ # Parsing the device SXP's. In most cases, the SXP looks # like this: # # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]] # # However, for PCI devices it looks like this: # # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2]]] # # It seems the reasoning for this difference is because # pciif.py needs all the PCI device configurations at # the same time when creating the devices. # # To further complicate matters, Xen 2.0 configuration format # uses the following for pci device configuration: # # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]] # For PCI device hotplug support, the SXP of PCI devices is # extendend like this: # # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2], # [vdevfn, 0]], # [state, 'Initialising']]] # # 'vdevfn' shows the virtual hotplug slot number which the PCI device # is inserted in. This is only effective for HVM domains. # # state 'Initialising' indicates that the device is being attached, # while state 'Closing' indicates that the device is being detached. # # The Dict looks like this: # # { devs: [{domain: 0, bus: 0, slot: 1, func: 2, vdevfn: 0}], # states: ['Initialising'] } dev_config = {} pci_devs = [] for pci_dev in sxp.children(dev_sxp, 'dev'): pci_dev_info = dict(pci_dev[1:]) if 'opts' in pci_dev_info: pci_dev_info['opts'] = pci_opts_list_from_sxp(pci_dev) # If necessary, initialize uuid, key, and vdevfn for each pci device if not pci_dev_info.has_key('uuid'): pci_dev_info['uuid'] = uuid.createString() if not pci_dev_info.has_key('key'): pci_dev_info['key'] = "%02x:%02x.%x" % \ (int(pci_dev_info['bus'], 16), int(pci_dev_info['slot'], 16), int(pci_dev_info['func'], 16)) if not pci_dev_info.has_key('vdevfn'): pci_dev_info['vdevfn'] = "0x%02x" % AUTO_PHP_SLOT pci_devs.append(pci_dev_info) dev_config['devs'] = pci_devs pci_states = [] for pci_state in sxp.children(dev_sxp, 'state'): try: pci_states.append(pci_state[1]) except IndexError: raise XendError("Error reading state while parsing pci sxp") dev_config['states'] = pci_states return dev_config def parse_hex(val): try: if isinstance(val, types.StringTypes): return int(val, 16) else: return val except ValueError: return None AUTO_PHP_FUNC = 1 MANUAL_PHP_FUNC = 2 def parse_pci_pfunc_vfunc(func_str): list = func_str.split('=') l = len(list) if l == 0 or l > 2: raise PciDeviceParseError('Invalid function: ' + func_str) p = int(list[0], 16) if p < 0 or p > 7: raise PciDeviceParseError('Invalid physical function in: ' + func_str) if l == 1: # This defaults to linear mapping of physical to virtual functions return (p, p, AUTO_PHP_FUNC) else: v = int(list[1], 16) if v < 0 or v > 7: raise PciDeviceParseError('Invalid virtual function in: ' + func_str) return (p, v, MANUAL_PHP_FUNC) def pci_func_range(start, end): if end < start: x = pci_func_range(end, start) x.reverse() return x return range(start, end + 1) def pci_pfunc_vfunc_range(orig, a, b): phys = pci_func_range(a[0], b[0]) virt = pci_func_range(a[1], b[1]) if len(phys) != len(virt): raise PciDeviceParseError('Invalid range in: ' + orig) return map(lambda x: x + (MANUAL_PHP_FUNC,), zip(phys, virt)) def pci_func_list_map_fn(key, func_str): if func_str == "*": return map(lambda x: parse_pci_pfunc_vfunc(x['func']), filter(lambda x: pci_dict_cmp(x, key, ['domain', 'bus', 'slot']), get_all_pci_dict())) l = map(parse_pci_pfunc_vfunc, func_str.split("-")) if len(l) == 1: return l if len(l) == 2: return pci_pfunc_vfunc_range(func_str, l[0], l[1]) return [] def pci_func_list_process(pci_dev_str, template, func_str): l = reduce(lambda x, y: x + y, (map(lambda x: pci_func_list_map_fn(template, x), func_str.split(",")))) phys = map(lambda x: x[0], l) virt = map(lambda x: x[1], l) if len(phys) != len(set(phys)) or len(virt) != len(set(virt)): raise PciDeviceParseError("Duplicate functions: %s" % pci_dev_str) return l def parse_pci_name_extended(pci_dev_str): pci_match = re.match(r"((?P[0-9a-fA-F]{1,4})[:,])?" + r"(?P[0-9a-fA-F]{1,2})[:,]" + r"(?P[0-9a-fA-F]{1,2})[.,]" + r"(?P(\*|[0-7]([,-=][0-7])*))" + r"(@(?P[01]?[0-9a-fA-F]))?" + r"(,(?P.*))?$", pci_dev_str) if pci_match == None: raise PciDeviceParseError("Failed to parse pci device: %s" % pci_dev_str) pci_dev_info = pci_match.groupdict('') template = {} if pci_dev_info['domain'] != '': domain = int(pci_dev_info['domain'], 16) else: domain = 0 template['domain'] = "0x%04x" % domain template['bus'] = "0x%02x" % int(pci_dev_info['bus'], 16) template['slot'] = "0x%02x" % int(pci_dev_info['slot'], 16) template['key'] = pci_dev_str.split(',')[0] if pci_dev_info['opts'] != '': template['opts'] = split_pci_opts(pci_dev_info['opts']) check_pci_opts(template['opts']) # This is where virtual function assignment takes place func_list = pci_func_list_process(pci_dev_str, template, pci_dev_info['func']) if len(func_list) == 0: return [] # Set the virtual function of the numerically lowest physical function # to zero if it has not been manually set if not filter(lambda x: x[1] == 0, func_list): auto = filter(lambda x: x[2] == AUTO_PHP_FUNC, func_list) manual = filter(lambda x: x[2] == MANUAL_PHP_FUNC, func_list) if not auto: raise PciDeviceParseError('Virtual device does not include ' 'virtual function 0: ' + pci_dev_str) auto.sort(lambda x,y: cmp(x[1], y[1])) auto[0] = (auto[0][0], 0, AUTO_PHP_FUNC) func_list = auto + manual # For pci attachment and detachment is it important that virtual # function 0 is done last. This is because is virtual function 0 that # is used to singnal changes to the guest using ACPI func_list.sort(lambda x,y: cmp(PCI_FUNC(y[1]), PCI_FUNC(x[1]))) # Virtual slot assignment takes place here if specified in the bdf, # else it is done inside qemu-xen, as it knows which slots are free pci = [] for (pfunc, vfunc, auto) in func_list: pci_dev = template.copy() pci_dev['func'] = "0x%x" % pfunc if pci_dev_info['vdevfn'] == '': vdevfn = AUTO_PHP_SLOT | vfunc else: vdevfn = PCI_DEVFN(int(pci_dev_info['vdevfn'], 16), vfunc) pci_dev['vdevfn'] = "0x%02x" % vdevfn pci.append(pci_dev) return pci def parse_pci_name(pci_name_string): dev = parse_pci_name_extended(pci_name_string) if len(dev) != 1: raise PciDeviceParseError(("Failed to parse pci device: %s: " "multiple functions specified prohibited") % pci_name_string) pci = dev[0] if not int(pci['vdevfn'], 16) & AUTO_PHP_SLOT: raise PciDeviceParseError
/*
             LUFA Library
     Copyright (C) Dean Camera, 2017.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
*/

/*
  Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaims all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Main source file for the AudioInput demo. This file contains the main tasks of
 *  the demo and is responsible for the initial application hardware configuration.
 */

#include "AudioInput.h"

/** LUFA Audio Class driver interface configuration and state information. This structure is
 *  passed to all Audio Class driver functions, so that multiple instances of the same class
 *  within a device can be differentiated from one another.
 */
USB_ClassInfo_Audio_Device_t Microphone_Audio_Interface =
	{
		.Config =
			{
				.ControlInterfaceNumber   = INTERFACE_ID_AudioControl,
				.StreamingInterfaceNumber = INTERFACE_ID_AudioStream,
				.DataINEndpoint           =
					{
						.Address          = AUDIO_STREAM_EPADDR,
						.Size             = AUDIO_STREAM_EPSIZE,
						.Banks            = 2,
					},
			},
	};

/** Current audio sampling frequency of the streaming audio endpoint. */
static uint32_t CurrentAudioSampleFrequency = 48000;


/** Main program entry point. This routine contains the overall program flow, including initial
 *  setup of all components and the main program loop.
 */
int main(void)
{
	SetupHardware();

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
	GlobalInterruptEnable();

	for (;;)
	{
		Audio_Device_USBTask(&Microphone_Audio_Interface);
		USB_USBTask();
	}
}

/** Configures the board hardware and chip peripherals for the demo's functionality. */
void SetupHardware(void)
{
#if (ARCH == ARCH_AVR8)
	/* Disable watchdog if enabled by bootloader/fuses */
	MCUSR &= ~(1 << WDRF);
	wdt_disable();

	/* Disable clock division */
	clock_prescale_set(clock_div_1);
#endif

	/* Hardware Initialization */
	LEDs_Init();
	Buttons_Init();
	ADC_Init(ADC_FREE_RUNNING | ADC_PRESCALE_32);
	ADC_SetupChannel(MIC_IN_ADC_CHANNEL);
	USB_Init();

	/* Start the ADC conversion in free running mode */
	ADC_StartReading(ADC_REFERENCE_AVCC | ADC_RIGHT_ADJUSTED | ADC_GET_CHANNEL_MASK(MIC_IN_ADC_CHANNEL));
}

/** ISR to handle the reloading of the data endpoint with the next sample. */
ISR(TIMER0_COMPA_vect, ISR_BLOCK)
{
	uint8_t PrevEndpoint = Endpoint_GetCurrentEndpoint();

	/* Check that the USB bus is ready for the next sample to write */
	if (Audio_Device_IsReadyForNextSample(&Microphone_Audio_Interface))
	{
		int16_t AudioSample;

		#if defined(USE_TEST_TONE)
			static uint8_t SquareWaveSampleCount;
			static int16_t CurrentWaveValue;

			/* In test tone mode, generate a square wave at 1/256 of the sample rate */
			if (SquareWaveSampleCount++ == 0xFF)
			  CurrentWaveValue ^= 0x8000;

			/* Only generate audio if the board button is being pressed */
			AudioSample = (Buttons_GetStatus() & BUTTONS_BUTTON1) ? CurrentWaveValue : 0;
		#else
			/* Audio sample is ADC value scaled to fit the entire range */
			AudioSample = ((SAMPLE_MAX_RANGE / ADC_MAX_RANGE) * ADC_GetResult());

			#if defined(MICROPHONE_BIASED_TO_HALF_RAIL)
			/* Microphone is biased to half rail voltage, subtract the bias from the sample value */
			AudioSample -= (SAMPLE_MAX_RANGE / 2);
			#endif
		#endif

		Audio_Device_WriteSample16(&Microphone_Audio_Interface, AudioSample);
	}

	Endpoint_SelectEndpoint(PrevEndpoint);
}

/** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void)
{
	LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);

	/* Sample reload timer initialization */
	TIMSK0  = (1 << OCIE0A);
	OCR0A   = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1);
	TCCR0A  = (1 << WGM01);  // CTC mode
	TCCR0B  = (1 << CS01);   // Fcpu/8 speed
}

/** Event handler for the library USB Disconnection event. */
void EVENT_USB_Device_Disconnect(void)
{
	/* Stop the sample reload timer */
	TCCR0B = 0;

	LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
}

/** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void)
{
	bool ConfigSuccess = true;

	ConfigSuccess &= Audio_Device_ConfigureEndpoints(&Microphone_Audio_Interface);

	LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
}

/** Event handler for the library USB Control Request reception event. */
void EVENT_USB_Device_ControlRequest(void)
{
	Audio_Device_ProcessControlRequest(&Microphone_Audio_Interface);
}

/** Audio class driver callback for the setting and retrieval of streaming endpoint properties. This callback must be implemented
 *  in the user application to handle property manipulations on streaming audio endpoints.
 *
 *  When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for
 *  the given endpoint index, and should return as fast as possible. When non-NULL, this value may be altered for GET operations
 *  to indicate the size of the retrieved data.
 *
 *  \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value
 *        of the \c DataLength parameter.
 *
 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state.
 *  \param[in]     EndpointProperty    Property of the endpoint to get or set, a value from Audio_ClassRequests_t.
 *  \param[in]     EndpointAddress     Address of the streaming endpoint whose property is being referenced.
 *  \param[in]     EndpointControl     Parameter of the endpoint to get or set, a value from Audio_EndpointControls_t.
 *  \param[in,out] DataLength          For SET operations, the length of the parameter data to set. For GET operations, the maximum
 *                                     length of the retrieved data. When NULL, the function should return whether the given property
 *                                     and parameter is valid for the requested endpoint without reading or modifying the Data buffer.
 *  \param[in,out] Data                Pointer to a location where the parameter data is stored for SET operations, or where
 *                                     the retrieved data is to be stored for GET operations.
 *
 *  \return Boolean \c true if the property get/set was successful, \c false otherwise
 */
bool CALLBACK_Audio_Device_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
                                                  const uint8_t EndpointProperty,
                                                  const uint8_t EndpointAddress,
                                                  const uint8_t EndpointControl,
                                                  uint16_t* const DataLength,
                                                  uint8_t* Data)
{
	/* Check the requested endpoint to see if a supported endpoint is being manipulated */
	if (EndpointAddress == Microphone_Audio_Interface.Config.DataINEndpoint.Address)
	{
		/* Check the requested control to see if a supported control is being manipulated */
		if (EndpointControl == AUDIO_EPCONTROL_SamplingFreq)
		{
			switch (EndpointProperty)
			{
				case AUDIO_REQ_SetCurrent:
					/* Check if we are just testing for a valid property, or actually adjusting it */
					if (DataLength != NULL)
					{
						/* Set the new sampling frequency to the value given by the host */
						CurrentAudioSampleFrequency = (((uint32_t)Data[2] << 16) | ((uint32_t)Data[1] << 8) | (uint32_t)Data[0]);

						/* Adjust sample reload timer to the new frequency */
						OCR0A = ((F_CPU / 8 / CurrentAudioSampleFrequency) - 1);
					}

					return true;
				case AUDIO_REQ_GetCurrent:
					/* Check if we are just testing for a valid property, or actually reading it */
					if (DataLength != NULL)
					{
						*DataLength = 3;

						Data[2] = (CurrentAudioSampleFrequency >> 16);
						Data[1] = (CurrentAudioSampleFrequency >> 8);
						Data[0] = (CurrentAudioSampleFrequency &  0xFF);
					}

					return true;
			}
		}
	}

	return false;
}

/** Audio class driver callback for the setting and retrieval of streaming interface properties. This callback must be implemented
 *  in the user application to handle property manipulations on streaming audio interfaces.
 *
 *  When the DataLength parameter is NULL, this callback should only indicate whether the specified operation is valid for
 *  the given entity and should return as fast as possible. When non-NULL, this value may be altered for GET operations
 *  to indicate the size of the retrieved data.
 *
 *  \note The length of the retrieved data stored into the Data buffer on GET operations should not exceed the initial value
 *        of the \c DataLength parameter.
 *
 *  \param[in,out] AudioInterfaceInfo  Pointer to a structure containing an Audio Class configuration and state.
 *  \param[in]     Property            Property of the interface to get or set, a value from Audio_ClassRequests_t.
 *  \param[in]     EntityAddress       Address of the audio entity whose property is being referenced.
 *  \param[in]     Parameter           Parameter of the entity to get or set, specific to each type of entity (see USB Audio specification).
 *  \param[in,out] DataLength          For SET operations, the length of the parameter data to set. For GET operations, the maximum
 *                                     length of the retrieved data. When NULL, the function should return whether the given property
 *                                     and parameter is valid for the requested endpoint without reading or modifying the Data buffer.
 *  \param[in,out] Data                Pointer to a location where the parameter data is stored for SET operations, or where
 *                                     the retrieved data is to be stored for GET operations.
 *
 *  \return Boolean \c true if the property GET/SET was successful, \c false otherwise
 */
bool CALLBACK_Audio_Device_GetSetInterfaceProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
                                                   const uint8_t Property,
                                                   const uint8_t EntityAddress,
                                                   const uint16_t Parameter,
                                                   uint16_t* const DataLength,
                                                   uint8_t* Data)
{
	/* No audio interface entities in the device descriptor, thus no properties to get or set. */
	return false;
}
R_MASK self.table_offset = self.table_offset & ~MSIX_BIR_MASK self.pba_index = self.pba_offset & MSIX_BIR_MASK self.pba_offset = self.pba_offset & ~MSIX_BIR_MASK break except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)' % (PROC_PCI_PATH, strerr, errno))) except TypeError, err: log.debug("Caught TypeError '%s'" % err) pass def get_info_from_sysfs(self): self.find_capability(0x11) sysfs_mnt = find_sysfs_mnt() if sysfs_mnt == None: return False path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_RESOURCE_PATH try: resource_file = open(path,'r') for i in range(PROC_PCI_NUM_RESOURCES): line = resource_file.readline() sline = line.split() if len(sline)<3: continue start = int(sline[0],16) end = int(sline[1],16) flags = int(sline[2],16) size = end-start+1 if start!=0: if flags&PCI_BAR_IO: self.ioports.append( (start,size) ) else: self.iomem.append( (start,size) ) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_IRQ_PATH try: self.irq = int(open(path,'r').readline()) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH try: self.driver = os.path.basename(os.readlink(path)) except OSError, (errno, strerr): self.driver = "" path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_VENDOR_PATH try: self.vendor = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_DEVICE_PATH try: self.device = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH try: self.subvendor = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH try: self.subdevice = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ self.name+SYSFS_PCI_DEV_CLASS_PATH try: self.classcode = int(open(path,'r').readline(), 16) except IOError, (errno, strerr): raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % (path, strerr, errno))) return True def get_info_from_lspci(self): """ Get information such as vendor name, device name, class name, etc. Since we cannot obtain these data from sysfs, use 'lspci' command. """ global lspci_info global lspci_info_lock lspci_info_lock.acquire() try: if lspci_info is None: _create_lspci_info() device_info = lspci_info.get(self.name) if device_info: try: self.revision = int(device_info.get('Rev', '0'), 16) except ValueError: pass self.vendorname = device_info.get('Vendor', '') self.devicename = device_info.get('Device', '') self.classname = device_info.get('Class', '') self.subvendorname = device_info.get('SVendor', '') self.subdevicename = device_info.get('SDevice', '') return True finally: lspci_info_lock.release() def __str__(self): str = "PCI Device %s\n" % (self.name) for (start,size) in self.ioports: str = str + "IO Port 0x%02x [size=%d]\n"%(start,size) for (start,size) in self.iomem: str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size) str = str + "IRQ %d\n"%(self.irq) str = str + "Vendor ID 0x%04x\n"%(self.vendor) str = str + "Device ID 0x%04x\n"%(self.device) str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor) str = str + "Subsystem Device ID 0x%04x"%(self.subdevice) return str def main(): if len(sys.argv)<5: print "Usage: %s \n" % sys.argv[0] sys.exit(2) dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16), int(sys.argv[3],16), int(sys.argv[4],16)) print str(dev) if __name__=='__main__': main()