why use cpu_to_le32 for the DMA address but not for length? (in an example code in a book) - dma

I was reading the book Essential Linux Device Driver (by Sreekrishnan Venkateswaran) and in Chapter 10 Listing 10.5. Setting Up DMA Descriptors and Buffers, I see
/* Device-specific data structure for the Ethernet Function */
struct device_data {
struct pci_dev *pdev; /* The PCI Device structure */
struct net_device *ndev; /* The Net Device structure */
void *dma_buffer_rx; /* Kernel virtual address of the receive descriptor */
dma_addr_t dma_bus_rx; /* Bus address of the receive descriptor */
void *dma_buffer_tx; /* Kernel virtual address of the transmit descriptor */
dma_addr_t dma_bus_tx; /* Bus address of the transmit descriptor */
/* ... */
spin_lock_t device_lock; /* Serialize */
} *mydev_data;
/* On-card registers related to DMA */
#define DMA_RX_REGISTER_OFFSET 0x0 /* Offset of the register holding the bus address of the RX descriptor */
#define DMA_TX_REGISTER_OFFSET 0x4 /* Offset of the register holding the bus address of the TX descriptor */
#define CONTROL_REGISTER 0x8 /* Offset of the control register */
/* Control Register Defines */
#define INITIATE_XMIT 0x1
/* Descriptor control word definitions */
#define FREE_FLAG 0x1 /* Free Descriptor */
#define INTERRUPT_FLAG 0x2 /* Assert interrupt after DMA */
/* Invoked from Listing 10.3 */
static void dma_descriptor_setup(struct pci_dev *pdev)
{
/* Allocate receive DMA descriptors and buffers */
mydev_data->dma_buffer_rx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_rx);
/* Fill the two receive descriptors as shown in Figure 10.2 */
/* RX descriptor 1 */
mydev_data->dma_buffer_rx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 24)); /* Buffer address */
mydev_data->dma_buffer_rx[1] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[2] = FREE_FLAG; /* Descriptor is free */
/* RX descriptor 2 */
mydev_data->dma_buffer_rx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_rx + 1560)); /* Buffer address */
mydev_data->dma_buffer_rx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_rx[5] = FREE_FLAG; /* Descriptor is free */
wmb(); /* Write Memory Barrier */
/* Write the address of the receive descriptor to the appropriate register in the card. The I/O base address, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_rx), ioaddr + DMA_RX_REGISTER_OFFSET);
/* Allocate transmit DMA descriptors and buffers */
mydev_data->dma_buffer_tx = pci_alloc_consistent(pdev, 3096, &mydev_data->dma_bus_tx);
/* Fill the two transmit descriptors as shown in Figure 10.2 */
/* TX descriptor 1 */
mydev_data->dma_buffer_tx[0] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 24)); /* Buffer address */ <---- line A
mydev_data->dma_buffer_tx[1] = 1536; /* Buffer length */ <---- line B
/* Valid descriptor. Generate an interrupt after completing the DMA */
mydev_data->dma_buffer_tx[2] = (FREE_FLAG | INTERRUPT_FLAG);
/* TX descriptor 2 */
mydev_data->dma_buffer_tx[3] = cpu_to_le32((unsigned long)(mydev_data->dma_bus_tx + 1560)); /* Buffer address */
mydev_data->dma_buffer_tx[4] = 1536; /* Buffer length */
mydev_data->dma_buffer_tx[5] = (FREE_FLAG | INTERRUPT_FLAG);
wmb(); /* Write Memory Barrier */
/* Write the address of the transmit descriptor to the appropriate register in the card. The I/O base, ioaddr, was populated in Listing 10.3 */
outl(cpu_to_le32((unsigned long)mydev_data->dma_bus_tx), ioaddr + DMA_TX_REGISTER_OFFSET);
}
/* Invoked from Listing 10.3 */
static void dma_descriptor_release(struct pci_dev *pdev)
{
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_tx);
pci_free_consistent(pdev, 3096, mydev_data->dma_bus_rx);
}
In the code, the driver prepares a buffer for the DMA descriptors and DMA buffers using pci_alloc_consistent() and sets them up and passes the buffer address (bus address) to the hardware making sure it's in little endian format using cpu_to_le32(). So I understood the H/W sees the buffer descriptor. But in the descriptor, why did it use cpu_to_le32() for the descriptor address (line A above) and not for the following buffer length (line B above)? Does the H/W see only the buffer address and not the size? Or is it an error in the book? By the way, this is for a fictitious PCI ethernet chip driver.

In practice such approach indeed looks like a mistake. But theoretically it's possible that one field (address) is always little endian no matter what, while another (length) is in native mode. Nowadays, with help of FPGA, I guess one even may try to implement this theoretical case.
So, in the given context, especially taking into consideration your remark that this is for a fictitious PCI ethernet chip, it is a bit hard to say what was author's intention here.

Related

GRUB memory map gives me weird values

I am trying to use grub in order to get the memory map, instead of going through the bios route. The problem is that grub seems to be giving me very weird values for some reason. Can anyone help with this?
Relevant code:
This is how I parse the mmap
void mm_init(mmap_entry_t *mmap_addr, uint32_t length)
{
mmap = mmap_addr;
/* Loop through mmap */
printk("-- Scanning memory map --");
for (size_t i = 0; mmap < (mmap_addr + length); i++) {
/* RAM is available! */
if (mmap->type == 1) {
uint64_t starting_addr = (((uint64_t) mmap->base_addr_high) << 32) | ((uint64_t) mmap->base_addr_low);
uint64_t length = (((uint64_t) mmap->length_high) << 32) | ((uint64_t) mmap->length_low);
printk("Found segment starting from 0x%x, with a length of %i", starting_addr, length);
}
/* Next entry */
mmap = (mmap_entry_t *) ((uint32_t) mmap + mmap->size + sizeof(mmap->size));
}
}
This is my mmap_entry_t struct (not the one in multiboot.h):
struct mmap_entry {
uint32_t size;
uint32_t base_addr_low, base_addr_high;
uint32_t length_low, length_high;
uint8_t type;
} __attribute__((packed));
typedef struct mmap_entry mmap_entry_t;
And this is how I call mm_init()
/* Kernel main function */
void kmain(multiboot_info_t *info)
{
/* Check if grub can give us a memory map */
/* TODO: Detect manually */
if (!(info->flags & (1<<6))) {
panic("couldn't get memory map!");
}
/* Init mm */
mm_init((mmap_entry_t *) info->mmap_addr, info->mmap_length);
for(;;);
}
This is the output I get on qemu:
-- Scanning memory map --
Found segment starting from 0x0, with a length of 0
Found segment starting from 0x100000, with a length of 0
And yes, I am pushing eax and ebx before calling kmain. Any ideas on what is going wrong here?
It turns out that the bit masking stuff was the problem. If we drop that, we can still have 32-bit addresses and the memory map works just fine.

I have a problem reading ADC with DMA on STM32 F767zi. When I look into the buffer, all I see are zeros, and I do not know why?

The size of my buffer is 4096 and I want to fill the buffer with the adc values that are read.
#define ADC_BUF_LEN 4096
uint16_t adc_buf[ADC_BUF_LEN];
I am using this function to start the reading process of the ADC using DMA
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc_buf, ADC_BUF_LEN);
Here are my configurations for the ADC
hadc2.Instance = ADC2;
hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV6;
hadc2.Init.Resolution = ADC_RESOLUTION_12B;
hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc2.Init.ContinuousConvMode = ENABLE;
hadc2.Init.DiscontinuousConvMode = DISABLE;
hadc2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc2.Init.NbrOfConversion = 1;
hadc2.Init.DMAContinuousRequests = ENABLE;
hadc2.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
if (HAL_ADC_Init(&hadc2) != HAL_OK)
{
Error_Handler();
}
This my DMA configuration
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
}
These are my interrupt functions. I set a toggle breakpoint on the first interrupt and when I debug, the LED does not turn on which suggests that the DMA isn't working?
/* USER CODE BEGIN 4 */
//Called when first half of buffer is filled
void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) {
//HAL_ADC_GetValue(&hadc2);
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_SET);
}
//Called when buffer is completely filled
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, GPIO_PIN_RESET);
}
I set the prescaled to be divided by 6 if this information helps.
Please give me some advice!
Thank you in advance.

Interfacing an I2S microphone with BeagleBone Black

I am trying to interface an I2S microphone (https://www.adafruit.com/product/3421) with BeagleBone Black. I followed the article (http://www.ti.com/lit/an/sprac97/sprac97.pdf), and able to update the device tree, and the Linux kernel as suggested in the article.
The I2S component (for microphone) of the device tree is included as a dtsi in the main device tree source. The content of the dtsi is as below
&am33xx_pinmux {
mcasp1_pins: mcasp1_pins {
pinctrl-single,pins = <
/* sink must enable receivers */
0x1a0 0x23
/* P9_42 mcasp1_aclkx - bit clock */
0x1a4 0x23
/* P9_27 mcasp1_fsx - frame sync */
0x1a8 0x23
/* P9_41 mcasp1_axr0 - i2s input */
>;
};
};
&mcasp1 {
#sound-dai-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&mcasp1_pins>;
status = "okay";
op-mode = <0>;
tdm-slots = <2>;
num-serializer = <4>;
serial-dir = < /* 1 TX 2 RX 0 unused */
2 0 0 0
>;
rx-num-evt = <1>;
tx-num-evt = <1>;
};
/ {
pcm5102a: pcm5102a {
#sound-dai-cells = <0>;
compatible = "ti,pcm5102a";
status = "okay";
};
sound1: sound#1 {
compatible = "simple-audio-card";
simple-audio-card,name = "PCM5102a";
simple-audio-card,format = "i2s";
simple-audio-card,bitclock-master = <&sound1_master>;
simple-audio-card,frame-master = <&sound1_master>;
simple-audio-card,bitclock-inversion;
simple-audio-card,cpu {
sound-dai = <&mcasp1>;
};
sound1_master: simple-audio-card,codec {
#sound-dai-cells = <0>;
sound-dai = <&pcm5102a>;
clocks = <&mcasp1_fck>;
clock-names = "mclk";
};
};
};
The final device tree (decompiled from am335x-boneblack.dtb) is attached here. McASP entries (mcasp1_pins), including pins as specified in the TI document above are on line no 1077.
I have also compiled the kernel with a new driver pcm5102 as suggested in the document. Finally, I see the driver listed in the output of the arecord command.
root#arm:/sys/class/gpio# arecord -l
**** List of CAPTURE Hardware Devices ****
card 0: PCM5102a [PCM5102a], device 0: davinci-mcasp.0-pcm5102a-hifi pcm5102a-hifi-0 []
Subdevices: 1/1
Subdevice #0: subdevice #0
However whenever I try to record audio, I am not getting any audio data. The audio file is formed, but the file size is always 44 bytes irrespective of how long I try to record audio for. Clearly no data is there in the file.
Recording using arecord command gives error as below
arecord -d 10 -Dhw:0,0 -f dat audio.wav
Recording WAVE 'audio.wav' : Signed 16 bit Little Endian, Rate 48000 Hz, Stereo
arecord: pcm_read:2032: read error: Input/output error
Moreover, whenever I try to connect the clock (MCASP1_ACLKR (Bit Clock) - P9_42) with my oscilloscope, I don't see any pulses. Looks like there is no proper clock signal on this pin. What can I do to debug, and fix this?
Any ideas?
Parag
The PCM1864 board used in the link you provided generates its own clock and operates in master mode. The microphone you are using, however, requires the bus master to generate both the bit clock and frame sync signals to operate.
The McASP module of the am33xx processor can generate these signals, although some modifications to the driver/device tree might be necessary.
The mcasp signals can be mapped to the following pins on the BeagleBone board (generated by TI's pinmux tool). Note, the device used here is mcasp0, not mcasp1. I assume TI was using a different version of the beagle bone which had mcasp1 connected to the IO header.
pinctrl-single,pins = <
AM33XX_IOPAD(0x9ac, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (A14) mcasp0_ahclkx.mcasp0_ahclkx */
AM33XX_IOPAD(0x99c, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (C12) mcasp0_ahclkr.mcasp0_ahclkr */
AM33XX_IOPAD(0x990, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (A13) mcasp0_aclkx.mcasp0_aclkx */
AM33XX_IOPAD(0x994, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (B13) mcasp0_fsx.mcasp0_fsx */
AM33XX_IOPAD(0x9a0, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (B12) mcasp0_aclkr.mcasp0_aclkr */
AM33XX_IOPAD(0x9a4, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (C13) mcasp0_fsr.mcasp0_fsr */
AM33XX_IOPAD(0x998, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (D12) mcasp0_axr0.mcasp0_axr0 */
AM33XX_IOPAD(0x9a8, PIN_INPUT_PULLDOWN | MUX_MODE0) /* (D13) mcasp0_axr1.mcasp0_axr1 */
>;
According to the datasheet of the processor, the clock signals of the receiver (ahclkr, aclkr, fsr) can be setup to run independently of of in sync with the clock signals of the transmitter and dividers can be specified as necessary. The pins which are used to provide the clock signals will need to be set to PIN_OUTPUT.
It seems to me that the overlay provided by beagle board here, when used in conjunction with the default clock device tree insert here, derives the clocks from the system clock. You might want to experiment with this.

PIC32 USB CDC is slow to write and raises erroneous flag

I am currently attempting to write code for a pic32MZ2048EFH100 which receives and responds to messages from a custom program on a PC through the USB CDC drivers in harmony.
Currently, the pic is able to both send and receive messages. However, whenever it sends a message to the PC, it always raises the buffer 80% full flag (EV_RX80FULL) incorrectly. In addition to this, the PIC32 sends messages relatively slowly. I am porting the firmware over from a TERN board which works correctly. There are times when the PC sends two messages very quickly, the TERN will send out an acknowledgement for one, receive the next, and then acknowledge that one. The PIC, on the other hand, will receive both and then send out two acknowledgements which will cause problems with the program on the PC side.
The largest difference between the two boards is that the drivers are different which is where we think the problem is originating. The PIC uses a driver from Microchip and the .inf is as follows
;---------------------------------------------------------------------------------
;Note: When the driver package is signed, any modifications to this .inf file will
;break the signature, and the driver package will need to be re-signed.
;---------------------------------------------------------------------------------
; Modified Windows USB CDC Abstract Control Model Serial Driver Setup File
; Copyright (C) 2012 Microchip Technology Inc.
[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%MFGNAME%
CatalogFile=%MFGFILENAME%.cat
DriverVer=10/06/2014,5.1.2600.9
[Manufacturer]
%MFGNAME%=DeviceList,NTamd64
;------------------------------------------------------------------------------
; Vendor and Product ID Definitions
;------------------------------------------------------------------------------
; When developing your USB device, the VID and PID used in the PC side
; application program and the firmware on the microcontroller must match.
; The VID and PID can be changed in the USB device descriptor and on the below
; lines in this file. If you modify this .inf file to customize it for your
; device, please remove all existing Microchip (VID 0x04D8) entries from
; the device lists.
;------------------------------------------------------------------------------
[DeviceList]
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_000A
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0205
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0206
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_00DF&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0057&MI_01
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_006E&MI_01
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0208&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0208&MI_02
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_00DD&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0207&MI_00
[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_000A
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0205
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0206
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_00DF&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0057&MI_01
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_006E&MI_01
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0208&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0208&MI_02
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_00DD&MI_00
%DESCRIPTION%=DriverInstall,USB\VID_04D8&PID_0207&MI_00
;------------------------------------------------------------------------------
; Windows 32bit OSes Section
;------------------------------------------------------------------------------
[DriverInstall.nt]
include=mdmcpq.inf
CopyFiles=FakeModemCopyFileSection
AddReg=DriverInstall.nt.AddReg
[DriverInstall.nt.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.NT.Services]
include=mdmcpq.inf
AddService=usbser, 0x00000002, LowerFilter_Service_Inst
;------------------------------------------------------------------------------
; Windows 64bit OSes Section
;------------------------------------------------------------------------------
[DriverInstall.NTamd64]
include=mdmcpq.inf
CopyFiles=FakeModemCopyFileSection
AddReg=DriverInstall.NTamd64.AddReg
[DriverInstall.NTamd64.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,%DRIVERFILENAME%.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.NTamd64.Services]
include=mdmcpq.inf
AddService=usbser, 0x00000002, LowerFilter_Service_Inst
;------------------------------------------------------------------------------
; Common Sections
;------------------------------------------------------------------------------
[DestinationDirs]
DefaultDestDir=12
[SourceDisksNames]
[SourceDisksFiles]
[FakeModemCopyFileSection]
[LowerFilter_Service_Inst]
DisplayName= %SERVICE%
ServiceType= 1
StartType = 3
ErrorControl = 0
ServiceBinary = %12%\usbser.sys
;------------------------------------------------------------------------------
; String Definitions
;------------------------------------------------------------------------------
; These strings can be modified to customize your device
;------------------------------------------------------------------------------
[Strings]
MFGFILENAME="mchpcdc"
DRIVERFILENAME ="usbser"
MFGNAME="Microchip Technology, Inc." ;This name shows up in the device manager properties for the device
DESCRIPTION="USB Serial Port" ;This is the "friendly name" that shows up in the device manager
SERVICE="USB to Serial Driver"
Here is the USB configuration on the PIC:
/**************************************************
* USB Device Function Driver Init Data
**************************************************/
const USB_DEVICE_CDC_INIT cdcInit0 =
{
.queueSizeRead = 1,
.queueSizeWrite = 1,
.queueSizeSerialStateNotification = 1
};
/**************************************************
* USB Device Layer Function Driver Registration
* Table
**************************************************/
const USB_DEVICE_FUNCTION_REGISTRATION_TABLE funcRegistrationTable[1] =
{
/* Function 1 */
{
.configurationValue = 1, /* Configuration value */
.interfaceNumber = 0, /* First interfaceNumber of this function */
.speed = USB_SPEED_HIGH|USB_SPEED_FULL, /* Function Speed */
.numberOfInterfaces = 2, /* Number of interfaces */
.funcDriverIndex = 0, /* Index of CDC Function Driver */
.driver = (void*)USB_DEVICE_CDC_FUNCTION_DRIVER, /* USB CDC function data exposed to device layer */
.funcDriverInit = (void*)&cdcInit0 /* Function driver init data */
},
};
/*******************************************
* USB Device Layer Descriptors
*******************************************/
/*******************************************
* USB Device Descriptor
*******************************************/
const USB_DEVICE_DESCRIPTOR deviceDescriptor =
{
0x12, // Size of this descriptor in bytes
USB_DESCRIPTOR_DEVICE, // DEVICE descriptor type
0x0200, // USB Spec Release Number in BCD format
USB_CDC_CLASS_CODE, // Class Code
USB_CDC_SUBCLASS_CODE, // Subclass code
0x00, // Protocol code
USB_DEVICE_EP0_BUFFER_SIZE, // Max packet size for EP0, see system_config.h
0x04D8, // Vendor ID
0x000A, // Product ID
0x0100, // Device release number in BCD format
0x01, // Manufacturer string index
0x02, // Product string index
0x00, // Device serial number string index
0x01 // Number of possible configurations
};
/*******************************************
* USB Device Qualifier Descriptor for this
* demo.
*******************************************/
const USB_DEVICE_QUALIFIER deviceQualifierDescriptor1 =
{
0x0A, // Size of this descriptor in bytes
USB_DESCRIPTOR_DEVICE_QUALIFIER, // Device Qualifier Type
0x0200, // USB Specification Release number
USB_CDC_CLASS_CODE, // Class Code
USB_CDC_SUBCLASS_CODE, // Subclass code
0x00, // Protocol code
USB_DEVICE_EP0_BUFFER_SIZE, // Maximum packet size for endpoint 0
0x01, // Number of possible configurations
0x00 // Reserved for future use.
};
/*******************************************
* USB High Speed Configuration Descriptor
*******************************************/
const uint8_t highSpeedConfigurationDescriptor[]=
{
/* Configuration Descriptor */
0x09, // Size of this descriptor in bytes
USB_DESCRIPTOR_CONFIGURATION, // Descriptor Type
67,0, //(67 Bytes)Size of the Config descriptor.e
2, // Number of interfaces in this cfg
0x01, // Index value of this configuration
0x00, // Configuration string index
USB_ATTRIBUTE_DEFAULT | USB_ATTRIBUTE_SELF_POWERED, // Attributes
50, // Max power consumption (2X mA)
/* Descriptor for Function 1 - CDC */
/* Interface Descriptor */
0x09, // Size of this descriptor in bytes
USB_DESCRIPTOR_INTERFACE, // Descriptor Type
0, // Interface Number
0x00, // Alternate Setting Number
0x01, // Number of endpoints in this interface
USB_CDC_COMMUNICATIONS_INTERFACE_CLASS_CODE, // Class code
USB_CDC_SUBCLASS_ABSTRACT_CONTROL_MODEL, // Subclass code
USB_CDC_PROTOCOL_AT_V250, // Protocol code
0x00, // Interface string index
/* CDC Class-Specific Descriptors */
sizeof(USB_CDC_HEADER_FUNCTIONAL_DESCRIPTOR), // Size of the descriptor
USB_CDC_DESC_CS_INTERFACE, // CS_INTERFACE
USB_CDC_FUNCTIONAL_HEADER, // Type of functional descriptor
0x20,0x01, // CDC spec version
sizeof(USB_CDC_ACM_FUNCTIONAL_DESCRIPTOR), // Size of the descriptor
USB_CDC_DESC_CS_INTERFACE, // CS_INTERFACE
USB_CDC_FUNCTIONAL_ABSTRACT_CONTROL_MANAGEMENT, // Type of functional descriptor
USB_CDC_ACM_SUPPORT_LINE_CODING_LINE_STATE_AND_NOTIFICATION,// bmCapabilities of ACM
sizeof(USB_CDC_UNION_FUNCTIONAL_DESCRIPTOR_HEADER) + 1, // Size of the descriptor
USB_CDC_DESC_CS_INTERFACE, // CS_INTERFACE
USB_CDC_FUNCTIONAL_UNION, // Type of functional descriptor
0, // com interface number
1,
sizeof(USB_CDC_CALL_MANAGEMENT_DESCRIPTOR), // Size of the descriptor
USB_CDC_DESC_CS_INTERFACE, // CS_INTERFACE
USB_CDC_FUNCTIONAL_CALL_MANAGEMENT, // Type of functional descriptor
0x00, // bmCapabilities of CallManagement
1, // Data interface number
/* Interrupt Endpoint (IN)Descriptor */
0x07, // Size of this descriptor
USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor
1| USB_EP_DIRECTION_IN, // EndpointAddress ( EP1 IN INTERRUPT)
USB_TRANSFER_TYPE_INTERRUPT, // Attributes type of EP (INTERRUPT)
0x10,0x00, // Max packet size of this EP
0x02, // Interval (in ms)
/* Interface Descriptor */
0x09, // Size of this descriptor in bytes
USB_DESCRIPTOR_INTERFACE, // INTERFACE descriptor type
1, // Interface Number
0x00, // Alternate Setting Number
0x02, // Number of endpoints in this interface
USB_CDC_DATA_INTERFACE_CLASS_CODE, // Class code
0x00, // Subclass code
USB_CDC_PROTOCOL_NO_CLASS_SPECIFIC, // Protocol code
0x00, // Interface string index
/* Bulk Endpoint (OUT)Descriptor */
0x07, // Size of this descriptor
USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor
2|USB_EP_DIRECTION_OUT, // EndpointAddress ( EP2 OUT)
USB_TRANSFER_TYPE_BULK, // Attributes type of EP (BULK)
0x00, 0x02, // Max packet size of this EP
0x00, // Interval (in ms)
/* Bulk Endpoint (IN)Descriptor */
0x07, // Size of this descriptor
USB_DESCRIPTOR_ENDPOINT, // Endpoint Descriptor
2|USB_EP_DIRECTION_IN, // EndpointAddress ( EP2 IN )
0x02, // Attributes type of EP (BULK)
0x00, 0x02, // Max packet size of this EP
0x00, // Interval (in ms)
};
/******************************************************
* USB Driver Initialization
******************************************************/
const DRV_USBHS_INIT drvUSBInit =
{
/* Interrupt Source for USB module */
.interruptSource = INT_SOURCE_USB_1,
/* Interrupt Source for USB module */
.interruptSourceUSBDma = INT_SOURCE_USB_1_DMA,
/* System module initialization */
.moduleInit = {SYS_MODULE_POWER_RUN_FULL},
.operationMode = DRV_USBHS_OPMODE_DEVICE,
.operationSpeed = USB_SPEED_HIGH,
/* Stop in idle */
.stopInIdle = false,
/* Suspend in sleep */
.suspendInSleep = false,
/* Identifies peripheral (PLIB-level) ID */
.usbID = 0,
};

Network Activity Monitoring on iPhone

I've been working for 5 days trying to learn and implement Network monitor on the iPhone.
I looked into netstat code from apple, and i lost like 25% of my hair.
I found links for JB Devices but i need it to execute on a non JB device. (Irrespective of whether Apple accepts it on the App store or not).
I found some useful links :
how to get tcp udp opening port list on iPhone (I couldn't parse the data returned in this question :( )
Data Usage on iPhone
sysctlbyname buf return type (I'm not a networking guy..could not understand this one, may be you guys can help :) )
TCP/UPD port list
I can say i got some thing from the first link. Can you guys help me to Parse the data ?
Is there any other method to achieve this??
Ok, you have all that you need over the table.
You can check the question Is there any private api to monitor network traffic on iPhone?
And here you can find the source code of inet. That code have all you need to parse the data returned of how to get tcp udp opening port list on iPhone
size_t len = 0;
if (sysctlbyname("net.inet.tcp.pcblist_n", 0, &len, 0, 0) < 0) {
perror("sysctlbyname");
} else {
char *buf = malloc(len);
sysctlbyname("net.inet.tcp.pcblist_n", buf, &len, 0, 0);
NSData *data = [NSData dataWithBytesNoCopy:buf length:len];
NSLog(#"data = %#", data);
}
Ok, yes the source code of inet is a little complicate. But, you know that netstat print the net status. So, you only need to see when inet execute printf, at this point you will have the data parsed.
If you try to compile the source of inet for iOS, you will find a lot of problems: some header files are not present in ios sdk. Ok, no problem copy the headers.
For the simulator you only need copy the header of netstat.h. And add some struct declaration that are private:
struct xtcpcb_n {
u_int32_t xt_len;
u_int32_t xt_kind; /* XSO_TCPCB */
u_int64_t t_segq;
int t_dupacks; /* consecutive dup acks recd */
int t_timer[TCPT_NTIMERS_EXT]; /* tcp timers */
int t_state; /* state of this connection */
u_int t_flags;
int t_force; /* 1 if forcing out a byte */
tcp_seq snd_una; /* send unacknowledged */
tcp_seq snd_max; /* highest sequence number sent;
* used to recognize retransmits
*/
tcp_seq snd_nxt; /* send next */
tcp_seq snd_up; /* send urgent pointer */
tcp_seq snd_wl1; /* window update seg seq number */
tcp_seq snd_wl2; /* window update seg ack number */
tcp_seq iss; /* initial send sequence number */
tcp_seq irs; /* initial receive sequence number */
tcp_seq rcv_nxt; /* receive next */
tcp_seq rcv_adv; /* advertised window */
u_int32_t rcv_wnd; /* receive window */
tcp_seq rcv_up; /* receive urgent pointer */
u_int32_t snd_wnd; /* send window */
u_int32_t snd_cwnd; /* congestion-controlled window */
u_int32_t snd_ssthresh; /* snd_cwnd size threshold for
* for slow start exponential to
* linear switch
*/
u_int t_maxopd; /* mss plus options */
u_int32_t t_rcvtime; /* time at which a packet was received */
u_int32_t t_starttime; /* time connection was established */
int t_rtttime; /* round trip time */
tcp_seq t_rtseq; /* sequence number being timed */
int t_rxtcur; /* current retransmit value (ticks) */
u_int t_maxseg; /* maximum segment size */
int t_srtt; /* smoothed round-trip time */
int t_rttvar; /* variance in round-trip time */
int t_rxtshift; /* log(2) of rexmt exp. backoff */
u_int t_rttmin; /* minimum rtt allowed */
u_int32_t t_rttupdated; /* number of times rtt sampled */
u_int32_t max_sndwnd; /* largest window peer has offered */
int t_softerror; /* possible error not yet reported */
/* out-of-band data */
char t_oobflags; /* have some */
char t_iobc; /* input character */
/* RFC 1323 variables */
u_char snd_scale; /* window scaling for send window */
u_char rcv_scale; /* window scaling for recv window */
u_char request_r_scale; /* pending window scaling */
u_char requested_s_scale;
u_int32_t ts_recent; /* timestamp echo data */
u_int32_t ts_recent_age; /* when last updated */
tcp_seq last_ack_sent;
/* RFC 1644 variables */
tcp_cc cc_send; /* send connection count */
tcp_cc cc_recv; /* receive connection count */
tcp_seq snd_recover; /* for use in fast recovery */
/* experimental */
u_int32_t snd_cwnd_prev; /* cwnd prior to retransmit */
u_int32_t snd_ssthresh_prev; /* ssthresh prior to retransmit */
u_int32_t t_badrxtwin; /* window for retransmit recovery */
};
struct xinpcb_n {
u_int32_t xi_len; /* length of this structure */
u_int32_t xi_kind; /* XSO_INPCB */
u_int64_t xi_inpp;
u_short inp_fport; /* foreign port */
u_short inp_lport; /* local port */
u_int64_t inp_ppcb; /* pointer to per-protocol pcb */
inp_gen_t inp_gencnt; /* generation count of this instance */
int inp_flags; /* generic IP/datagram flags */
u_int32_t inp_flow;
u_char inp_vflag;
u_char inp_ip_ttl; /* time to live */
u_char inp_ip_p; /* protocol */
union { /* foreign host table entry */
struct in_addr_4in6 inp46_foreign;
struct in6_addr inp6_foreign;
} inp_dependfaddr;
union { /* local host table entry */
struct in_addr_4in6 inp46_local;
struct in6_addr inp6_local;
} inp_dependladdr;
struct {
u_char inp4_ip_tos; /* type of service */
} inp_depend4;
struct {
u_int8_t inp6_hlim;
int inp6_cksum;
u_short inp6_ifindex;
short inp6_hops;
} inp_depend6;
u_int32_t inp_flowhash;
};
#define SO_TC_STATS_MAX 4
struct data_stats {
u_int64_t rxpackets;
u_int64_t rxbytes;
u_int64_t txpackets;
u_int64_t txbytes;
};
struct xgen_n {
u_int32_t xgn_len; /* length of this structure */
u_int32_t xgn_kind; /* number of PCBs at this time */
};
#define XSO_SOCKET 0x001
#define XSO_RCVBUF 0x002
#define XSO_SNDBUF 0x004
#define XSO_STATS 0x008
#define XSO_INPCB 0x010
#define XSO_TCPCB 0x020
struct xsocket_n {
u_int32_t xso_len; /* length of this structure */
u_int32_t xso_kind; /* XSO_SOCKET */
u_int64_t xso_so; /* makes a convenient handle */
short so_type;
u_int32_t so_options;
short so_linger;
short so_state;
u_int64_t so_pcb; /* another convenient handle */
int xso_protocol;
int xso_family;
short so_qlen;
short so_incqlen;
short so_qlimit;
short so_timeo;
u_short so_error;
pid_t so_pgid;
u_int32_t so_oobmark;
uid_t so_uid; /* XXX */
};
struct xsockbuf_n {
u_int32_t xsb_len; /* length of this structure */
u_int32_t xsb_kind; /* XSO_RCVBUF or XSO_SNDBUF */
u_int32_t sb_cc;
u_int32_t sb_hiwat;
u_int32_t sb_mbcnt;
u_int32_t sb_mbmax;
int32_t sb_lowat;
short sb_flags;
short sb_timeo;
};
struct xsockstat_n {
u_int32_t xst_len; /* length of this structure */
u_int32_t xst_kind; /* XSO_STATS */
struct data_stats xst_tc_stats[SO_TC_STATS_MAX];
};
But for the Device you need to copy some other headers of the kernel, I don't know why the headers aren't in the device sdk (maybe if you use them Apple will not approve your app, I don't know, but that doesn't matter).
You can copy the missing headers from the simulator SDK to your project. Or you can change the header path to the simulator SDK. (I copied the headers).
If you copy the headers you will need change some include declaration.
You don't need all the inet.c code. You only need these functions:
protopr
inetprint
inetname
Then inside those functions you will see the printf with the data parsed, you can add that in a dictionary.
Here is my code. You can see a class named: DHInet with two method that return a NSArray with a list of NSDictionary with the information of the connections.
I hope you find it useful, and if anyone wants to give me a hand in improving the code, so be it, I need to clean the code, because it has a lot of ifdef that are not necessary.

Resources