how to translate from udev path to ACPI Device - linux-device-driver

I have a PCI device as follows
DEVPATH=/devices/pci0000:00/0000:00:0c.0/0000:04:00.0
% lspci -s 04:0
04:00.0 Non-VGA unclassified device:
This publishes multiple i2c buses. So am attempting to learn how to translate this to ACPI.
Investigation so far
% cat /sys/bus/pci/devices/0000\:00\:0c.0/firmware_node/path
\_SB_.PCI0.PEX3
So, I create the device within the scope of this device and address as shown by the last part of DEVPATH
Scope (\_SB_.PCI0.PEX3)
{
Device (PD01)
{
Name (_ADR, 0x00040000)
Device (CH00)
{
Name (_ADR, 00)
Name (_HID, "PRP0001")
Name (_STR, Unicode("MUX0"))
Name (_CRS, ResourceTemplate ()
{
I2cSerialBus (0x70, ControllerInitiated, 100000,
AddressingMode7Bit, "\\_SB_.PCI0.PEX3.PD01.CH00", 0x00,
ResourceConsumer,,)
})
Name (_DSD, Package ()
{
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package (2) { "compatible", "nxp,pca9548" },
}
})
}
}
}
I then compile this with iASL and add the table dynamically using the Loading SSDT with configfs.
When I monitor this using the udevadm monitor I see that the ACPI device are created, but the PCA9548 is not loaded.
% cat /sys/bus/acpi/devices/PRP0001\:03/path
\_SB_.PCI0.PEX3.OCOR.CH03
Should the kernel driver used for the FPGA do any special handling to allow ACPI to permit the devices below it be discovered?
The FPGA driver is auto-loaded as part of PCI enumeration.
Is there any error in how I have nested the Device definition?

Related

[gnu-efi]: How to call InitializeGlobalIoDevice funtion when I wanna call CMOS Read/Write?

Below is the code to initializing the IO device, and I wanna to call a function to do CMOS read/write, but I don't know the DevicePath and Protocol? Does anyone know this? thanks a lot;
/*
Routine Description:
Check to see if DevicePath exists for a given Protocol. Return Error if it
exists. Return GlobalIoFuncs set match the DevicePath
Arguments:
DevicePath - to operate on
Protocol - to check the DevicePath against
ErrorStr - ASCII string to display on error
GlobalIoFncs - Returned with DeviceIoProtocol for the DevicePath
Returns:
Pass or Fail based on wether GlobalIoFncs where found
*/
EFI_STATUS
InitializeGlobalIoDevice (
IN EFI_DEVICE_PATH *DevicePath,
IN EFI_GUID *Protocol,
IN CHAR8 *ErrorStr EFI_UNUSED,
OUT EFI_DEVICE_IO_INTERFACE **GlobalIoFncs
)
{
EFI_STATUS Status;
EFI_HANDLE Handle;
//
// Check to see if this device path already has Protocol on it.
// if so we are loading recursivly and should exit with an error
//
Status = uefi_call_wrapper(BS->LocateDevicePath, 3, Protocol, &DevicePath, &Handle);
if (!EFI_ERROR(Status)) {
DEBUG ((D_INIT, "Device Already Loaded for %a device\n", ErrorStr));
return EFI_LOAD_ERROR;
}
Status = uefi_call_wrapper(BS->LocateDevicePath, 3, &DeviceIoProtocol, &DevicePath, &Handle);
if (!EFI_ERROR(Status)) {
Status = uefi_call_wrapper(BS->HandleProtocol, 3, Handle, &DeviceIoProtocol, (VOID*)GlobalIoFncs);
}
ASSERT (!EFI_ERROR(Status));
return Status;
}
Need your help....
In UEFI spec, there is no Protocol or Device Path defined for CMOS.
If you'd like to read/write the CMOS RTC, there are GetTime() and SetTime() APIs defined in Runtime Services. They can be directly called from RT in gnu-efi.
If you want to read/write other CMOS registers, simply access I/O port 0x70/0x71 with inb/outb instruction with inline assembly in C. That's also how EDK2 accesses CMOS.
https://github.com/tianocore/edk2/blob/master/OvmfPkg/Library/PlatformInitLib/Cmos.c
https://github.com/tianocore/edk2/blob/master/MdePkg/Library/BaseIoLibIntrinsic/IoLib.c

How to make tap device use socket API?

I'm using tap device.
The problem is that you just can ->read() or ->write() one packet every system call.
After read the source file tun.c, I found there is struct socket in tun device and function tun_get_socket() can return it.
struct socket *tun_get_socket(struct file *file)
{
struct tun_file *tfile;
if (file->f_op != &tun_fops)
return ERR_PTR(-EINVAL);
tfile = file->private_data;
if (!tfile)
return ERR_PTR(-EBADFD);
return &tfile->socket;
}
EXPORT_SYMBOL_GPL(tun_get_socket);
The socket.ops is set with tun_socket_ops which have ->sendmsg() and ->recvmsg().
static const struct proto_ops tun_socket_ops = {
.sendmsg = tun_sendmsg,
.recvmsg = tun_recvmsg,
.release = tun_release,
};
The questions:
How to create one file descriptor to connect with this socket? That makes me to use ->sendmsg() and ->recvmsg() in userspace. My OS is CentOS7.9 with kernel version 3.10.0-1160.el7.x86_64.
Or is there other ways I can read or write multiple packets at one time from tap device?
Writing new kernel module is acceptable.

Write to HID with Chip Selection with .NET Console App

Hi I am writing a simple console app that needs to write bytes to MCP2210 USB to SPI Master
I found this library over here, seems to do good job with connecting the device and reading the metadata.
I am writing message to the board as below
public static byte[] Talk()
{
var device = DeviceList.Local.GetHidDevices(1240, 222).FirstOrDefault();
if (device == null)
{
Console.WriteLine($"Could not find a device with Vendor Id:1240, Product Id:222 ");
return null;
}
var reportDescriptor = device.GetReportDescriptor();
foreach (var deviceItem in reportDescriptor.DeviceItems)
{
Console.WriteLine("Opening device for 20 seconds...");
if (!device.TryOpen(out var hidStream))
{
Console.WriteLine("Failed to open device.");
continue;
}
Console.WriteLine("Opened device.");
hidStream.ReadTimeout = Timeout.Infinite;
hidStream.Write(new byte[3] {60, 00, 00});
}
Not sure If I am writing it correctly.
While writing I need to do a chip selection as displayed in this other terminal
Any help is greatly appreciated
Here is the MC I am using https://www.microchip.com/wwwproducts/en/MCP2210
I do not see a closing of your stream. This may cause your data to not even being sent (at least not in time).
Consider using blocks with streams.
But with out parameters not possible.

How to performs I/O to block device from block device driver under Linux

I have a task to write a block device driver (/dev/dua - for example) , this block device is must be looks like to OS as a disk device like /dev/sda. So, this driver must process data blocks and write it to other block device.
I looking for a right way to performs I/O operations on the backend device like "/dev/sdb".
I have played with the vfs_read/write routines it's works at glance for disk sector sized transfers. But, probably there is more effective way to performs I/O on backend device ?
TIA.
Follows a piece of code (original has been found here : https://github.com/asimkadav/block-filter) implements a "filtering" feature, so it can be used as a method to performs I/O on a backend block device `
void misc_request_fn(struct request_queue *q, struct bio *bio) {
printk ("we are passing bios.\n");
// here is where we trace requests...
original_request_fn (q, bio);
return;
}
void register_block_device(char *path) {
struct request_queue *blkdev_queue = NULL;
if (path == NULL) {
printk ("Block device empty.\n");
return;
}
printk ("Will open %s.\n", path);
blkdev = lookup_bdev(path);
if (IS_ERR(blkdev)) {
printk ("No such block device.\n");
return;
}
printk ("Found block device %p with bs %d.\n", blkdev, blkdev->bd_block_size);
blkdev_queue = bdev_get_queue(blkdev);
original_request_fn = blkdev_queue->request_fn;
blkdev_queue->request_fn = misc_request_fn;
}
`

RTOS μC/OS-II not running as expected

I'm using ST STM32F101xB and μC/OS-II, I was having external clock (HSE) on old board and it's running fine. We wanted to use internal clock (HSI) on new board, however, the RTOS (Appmaintask()) doesn't run using internal clock, i have changed my code as below, any idea what's wrong with the change:
void BSP_Init (void)
{
RCC_DeInit();
//RCC_HSEConfig(RCC_HSE_ON);
//RCC_WaitForHSEStartUp();
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1); // APB2 clock divide by 1 => 64MHz
RCC_PCLK1Config(RCC_HCLK_Div2); // APB1 clock divide by 2 => 32MHz
FLASH_SetLatency(FLASH_Latency_2);
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_8); // 64MHz
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_8);
RCC_PLLCmd(ENABLE);
RCC_LSEConfig(RCC_LSE_OFF);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
;
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08) {
;
}
//Set the Vector Table base location at 0x08000000
//NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
// Need to finalize and arange priority for each interrupts in future,
// So that 1 interrupt wont blocks another interrupt.
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);
}
void main()
{
INT8U err;
cpuObj = new Cstm32f10x();
BSP_Init();
BSP_IntDisAll(); /* Disable all ints until we are ready to accept them. */
OSInit();
err = OSTaskCreateExt (AppMainTask,
(void *)0,
(OS_STK *)&AppMainTaskStk[APP_MAIN_TASK_STK_SIZE-1],
APP_MAIN_TASK_PRIO,
APP_MAIN_TASK_ID,
(OS_STK *)&AppMainTaskStk[0],
APP_MAIN_TASK_STK_SIZE,
(void *)0,
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);
OSStart(); // Start multitasking (i.e. give control to uC/OS-II)
}
void AppMainTask (void *p_arg)
{
OS_CPU_SysTickInit();
while(TRUE)
{
OSTimeDly(1);
}
}
Thanks.
Setting up of the PLL is normally performed in the CMSIS start-up code provided by ST/ARM. This code executes as part of the runtime environment start-up before main() is called. I recommend that you use this code for chip initialisation since static data initialisation and static object constructors run before main() and will be running before possibly critical initialisation.
The CMSIS with Cortex-M3 core and STM32F1xx specific device support is included in the STM32 Standard Peripheral Library. The file that actually does the work is system_stm32f10x.c. Other functions you are performing in BSP_Init() such as flash latency are also dealt with by the CMSIS start-up code. Even if you customise this code, I strongly recommend that you use this method of early environment initialisation.
Another possibility is to use the STM32CubeMX utility to generate configuration code. This appears to be a replacement for the apparently now unavailable STM32 MicroXplorer utility.