Read/Write from a hdd inside a network device driver (Linux) - linux-device-driver

I am new in Linux programming. I want to customize an existing driver for my needs. It is the RealTek 8169 network driver.
My question is: I can access to a HDD inside the driver? Is this "allowed"? Or could I get some problems with this?
I want to do something like this:
// Which disk?
char diskName[] = "/dev/sda";
std::string diskError = std::string() + diskName + ": ";
// Open device file
std::ifstream disk(diskName, std::ios_base::binary);
if(!disk)
throw(std::runtime_error(diskError + std::strerror(errno)));
// Seek to 12345'th sector
disk.seekg(512 * 12345);
if(!disk)
throw(std::runtime_error(diskError + std::strerror(errno)));
// Read in one sector
std::vector<char> buffer(512);
disk.read(&buffer[0], 512);
if(!disk)
throw(std::runtime_error(diskError + std::strerror(errno)));

Related

How to pass user space data to dmaengine client usage call?

[EDITED]
I have a board on arm64 with fpga (SoC).
The task is simple:
make possible to transfer data from/to "User Space" area (app) to/from "Kernel Space" phys mem (device mem = fpga regs), with and without dma support usage (streaming type). That dma is in the board (ZynqMP / GDMA).
I will have several devices - on fpga and outside, which should use this communication, but now I'm working only with fpga-ddr4 mem area.
Now I see the next logic flow:
some initialization (dma parameters and so on);
ioremap() a fpga device area;
make a buffer (by kzalloc() or another) - this buffer I should give to the US by mmap fops;
make a scatterlist from the buffer (pseudo-code below);
use the scatterlist with dmaengine to transfer data;
// scatterlist init pseudo-code
struct scatterlist sgl[2];
struct scatterlist *sge;
int i, buf_n, err_code;
__u8 *buffer; // allocated earlier
sg_init_table(sgl, ARRAY_SIZE(sgl));
for_each_sg(sgl, sge, ARRAY_SIZE(sgl), i) {
struct page *pg = virt_to_page(buffer + i * PAGE_SIZE);
dma_addr_t dma_handle = dma_map_page(&pdev->dev, pg, 0, PAGE_SIZE, direction /* DMA_TO_DEVICE */);
if ((err_code = dma_mapping_error(&pdev->dev, dma_handle))) {
dev_err(&pdev->dev, "dma page mapping failed! (code: %i)\n", err_code);
break;
}
sg_set_page(sge, pg, PAGE_SIZE, 0);
}
dma_map_sg(&pdev->dev, sgl, ARRAY_SIZE(sgl), direction) // with appropriate check
Now I misunderstanding next - how or where the destination controled? I mean, I had allocated the buffer in RAM, make scatterlist from it and give this list by argument of dmaengine funtions for transferring. But I dont set/use ioremapped device mem area to save this buffer data! Is this dma works only with appropriate RAM memory area and I should copy buffer to the device area? Or, should I use the ioremapped area as my buffer?
Is it right flow? Explain me my mistakes pleaes?

STM32F7 + FatFs = FR_NOT_READY

I am now using CubeMx 4.23.0 and FW package for STM32F7 1.8.0
MCU is STM32F746 on Core746i board.
Everything is generated by CubeMx automatically.
main.c:
SCB_EnableICache();
SCB_EnableDCache();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SDMMC1_SD_Init();
MX_USB_DEVICE_Init();
MX_FATFS_Init();
HAL_Delay(3000);
DebugString("start OK");
uint8_t res = 0;
FATFS SDFatFs;
FIL MyFile; /* File object */
char SD_Path[4];
res = f_mount(&SDFatFs, (TCHAR const*)SD_Path, 0);
sprintf(DebugStr, "f_mount = 0x%02X", res);
DebugString(DebugStr);
res = f_open(&MyFile, "test.txt", FA_READ);
sprintf(DebugStr, "f_open = 0x%02X", res);
DebugString(DebugStr);
sdmmc.c:
void MX_SDMMC1_SD_Init(void)
{
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_1B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd1.Init.ClockDiv = 7;
//HAL_SD_Init(&hsd1);
// ^^^^^ I also tried this here
//HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B)
//^^^^ and this
}
In case of f_mount(&SDFatFs, (TCHAR const*)SD_Path, 0) <- with 1 here (forced mount), output is:
f_mount = 0x03
f_open = 0x01
With 0 (do not mount now) output is:
f_mount = 0x00
f_open = 0x03
0x03 value is FR_NOT_READY, but official info is pretty vague about it
Things I've tried:
Adding HAL_SD_Init(&hsd1) to MX_SDMMC1_SD_Init() since i didnt find where is SD card GPIO init happening.
2 GB noname SD card, 1 GB Transcend card.
Different hsd1.Init.ClockDiv 3 to 255.
Resoldering everything completely.
Switching to 4-bit wide bus using HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B);
Turn on and off pullups.
But card still does not mount. It's formatted in FAT, working on a PC, files i've tried to open are exist, but empty.
How to get it to mount?
Thanks in advance!
there was the problem with exact version of cubemx.
updating stm32cubemx helped.
You can try
`f_mount(0, "path", 0);
` after the f_open call . it may work.
If the function with forced mounting failed with FR_NOT_READY, it means that the filesystem object has been registered successfully but the
volume is currently not ready to work
. The volume mount process will be attempted on subsequent file/directroy function.
If implementation of the disk I/O layer lacks asynchronous media change detection, application program needs to perform f_mount function after each media change to force cleared the filesystem object.
Changing all SDIO pins except SDIO_CK to pull-up according to This Topic works for me
Try commenting MX_USB_DEVICE_Init(), see what happens.

Writing PCI driver for DMA transfer on Qemu

I am writing a PCI device on Qemu and driver(LKM) in the guest OS. While Qemu provides an example PCI device, edu(edu.txt and edu.c) with it's distribution, I am having trouble writing the kernel module to do DMA transfer. A basic driver has been covered here but it does not support DMA.
I am following the implementation of the link and this. I tried to transmit buffer to the PCI device from the IRQ handler. The device can read the data (pci_dma_read) but the I am not getting the correct data that I am supposed to receive. Here is the code segment that is doing DMA transfer:
static int write_to_HyPerf(void *dev, void* addr, uint32_t size)
{
/* ----------------------------------------------------------------------------
* PCI address 'addr':
* addr -> DMA source address
* 0x40000 -> DMA destination address
* 100 -> DMA transfer count
* 1 -> DMA command register
* while (DMA command register & 1)
*--------------------------------------------------------------------------------
*/
iowrite32((u32 *)dma_handle_to_device, mmio + IO_DMA_SRC);
iowrite32(DMA_START, mmio + IO_DMA_DST);
iowrite32((u32 *)size, mmio + IO_DMA_XCNT);
iowrite32(DMA_CMD | DMA_IRQ, mmio + IO_DMA_CMD);
}
I also have setup coherent mapping using dma_alloc_coherent.
vaddr_to_device = dma_alloc_coherent(&(dev->dev), DMA_SIZE, &dma_handle_to_device, GFP_ATOMIC);
The complete code is available here. What am I doing wrong?
Could be that you having problem in your driver.
In this case you can use this:
https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/kernel_modules/qemu_edu.c
and you can use dd command as in this script to write and read from your device:
https://github.com/cirosantilli/linux-kernel-module-cheat/blob/master/rootfs_overlay/lkmc/qemu_edu.sh
Then all you need is to write the wanted dma values to the correct address
like in the edu.c code:
case 0x80:
dma_rw(edu, false, &val, &edu->dma.src, false);
break;
case 0x88:
dma_rw(edu, false, &val, &edu->dma.dst, false);
break;
case 0x90:
dma_rw(edu, false, &val, &edu->dma.cnt, false);
break;
case 0x98:
dma_rw(edu, false, &val, &edu->dma.cmd, false);
break;

How to show the disk name and capacity of external storage in android

I am creating an android application that had to work with the external storage.I want to display the list of external storage devices with its external storage name and its free space and its total space can any one tell me how to display capacity and free space and name of a disk in android.
I did some thing to check external devices in a list view:
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) {
Devices_Temp++;
i += "\n" +
"DeviceName: " + device.getDeviceName() +"\n"+
"VendorID: " + device.getVendorId() +"\n" +
"ProductID: " + device.getProductId() + "\n";
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
StatFs statfs = new StatFs(Environment.getExternalStorageDirectory().getPath());
long bytes_available = (long)statfs .getBlockSizeLong()*(long)statfs.getAvailableBlocksLong();
long total_bytes_count=bytes_available/(1024*1024);
String_Array_Dynamic_Genaration.add("Free space : "+total_bytes_count);
}

Access to internal Xilinx FPGA block RAM

I'm writing a device driver for Xilinx Virtex-6 X8 PCI Express Gen 2 Evaluation/Development Kit SX315T FPGA. My OS is openSUSE 11.3 64 bit.
In the documentation for this device (Virtex-6 FPGA Integrated Block form PCI Express User Guide UG517 (v5.0) April 19, 2010, page 219) says:
The PIO design is a simple target-only application that interfaces with the Endpoint for
PCIe core’s Transaction (TRN) interface and is provided as a starting point for customers to build their own designs. The following features are included:
• Four transaction-specific 2 KB target regions using the internal Xilinx FPGA block
RAMs, providing a total target space of 8192 bytes
• Supports single DWORD payload Read and Write PCI Express transactions to
32-/64-bit address memory spaces and I/O space with support for completion TLPs
• Utilizes the core’s trn_rbar_hit_n[6:0] signals to differentiate between TLP destination
Base Address Registers
• Provides separate implementations optimized for 32-bit, 64-bit, and 128-bit TRN
interfaces
In the device is available BAR0 and BAR2 length 128 bytes.
I'm trying to access internal Xilinx FPGA block RAM, for that I am mapping BAR0 in virtual space kernel.
struct pcie_dev {
struct pci_dev* dev;
struct cdev chr_dev;
atomic_t dev_available;
u32 IOBaseAddress;
u32 IOLastAddress;
void* __iomem bar;
void *virt_addr;
u32 length;
unsigned long sirqNum;
void *private_data; };
struct pcie_dev cur_pcie_dev;
cur_pcie_dev.IOBaseAddress = pci_resource_start(dev, 0);
cur_pcie_dev.IOLastAddress = pci_resource_end(dev, 0);
cur_pcie_dev.length=pci_resource_len(dev,0);
cur_pcie_dev.bar=pci_iomap(dev, 0,cur_pcie_dev.length);
IOBaseAddress is 0xfbbfe000
IOLastAddress is 0xfbbfe07f
length=128;
Using IOCTL I try, write/read data.
case IOCTL_INFO_DEVICE:
{
u32 *rcslave_mem = (u32 *)pCur_dev->bar;
u32 result = 0;
u32 value = 0;
int i;
for (i = 0; i <2048 ; i++) {
printk(KERN_DEBUG "Writing 0x%08x to 0x%p.\n",
(u32)value, (void *)rcslave_mem + i);
iowrite32(value, rcslave_mem + i);
value++;
}
/* read-back loop */
value = 0;
for (i = 0; i < 2048; i++) {
result = ioread32(rcslave_mem + i);
printk(KERN_DEBUG "Wrote 0x%08x to 0x%p, but read back 0x%08x.\n",
(u32)value, (void *)rcslave_mem + i, (u32)result);
value++;
}
But it turns out to write and read only 32 values​​. As I understand it, the recording takes place in BAR0 (4 byte * 32 values ​​= 128 bytes), but not in internal Xilinx memory.I tried to go the other way.
cur_pcie_dev.IOBaseAddress = pci_resource_start(dev, 0);
cur_pcie_dev.IOLastAddress = pci_resource_end(dev, 0);
cur_pcie_dev.length=pci_resource_len(dev,0);
flags = pci_resource_flags(dev,0);
if (flags & IORESOURCE_MEM) {
if (request_mem_region(cur_pcie_dev.IOBaseAddress,cur_pcie_dev.length, DEVICE_NAME)== NULL) {
return -EBUSY;}
cur_pcie_dev.virt_addr=ioremap_nocache(cur_pcie_dev.IOBaseAddress,cur_pcie_dev.length);
if (cur_pcie_dev.virt_addr == NULL) {
printk(KERN_ERR "ERROR: BAR%u remapping FAILED\n",0);
return -ENOMEM;
}
printk(KERN_INFO " Allocated I/O memory range %#lx-%#lx\n", cur_pcie_dev.IOBaseAddress,(cur_pcie_dev.IOBaseAddress+cur_pcie_dev.length-1));
} else {
printk(KERN_ERR "ERROR: Invalid PCI region flags\n");
return -EIO;
}
Then
address = ((unsigned int)pCur_dev->virt_addr+pd.Address);
iowrite32(pd.Value,(unsigned int*) address);
address = ((unsigned int)pCur_dev->virt_addr+pd.Address);
pd.Value = ioread32((unsigned int *)address);
I use a summing virtual address and the address, which specifies the user. But the result is read / write operations is also not true. Tell me what I'm doing wrong.
P.S.Sorry for my bad English
What is the reason you are trying to access internal block RAM of your board? I think a normal behavior of a device driver (which your device here is a PCI Express interface), would suffice if you are using Programmed I/O (PIO) on your FPGA. When you write to your device driver, the data would be transferred to block RAM by downloaded IP core on FPGA side (and also in reverse).
Take a look at Linux Driver in xapp1022 (Memory Endpoint Test) package from Xilinx.
P.S.: I know it's an old question and you may found your answer way sooner :)