rk3399 创建一个字符设备,利用dma-buf机制从网卡读取数据例程
时间: 2023-08-22 13:33:31 浏览: 153
好的,以下是一个简单的例程,用于在 rk3399 上创建一个字符设备,并利用 dma-buf 机制从网卡读取数据:
```c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#define DEV_NAME "mydev"
#define BUF_SIZE 4096
static struct miscdevice my_misc_device;
static char *rx_buf;
static dma_addr_t rx_buf_dma;
static int my_open(struct inode *inode, struct file *file)
{
return 0;
}
static int my_release(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
ssize_t ret = 0;
if (count > BUF_SIZE)
count = BUF_SIZE;
if (copy_to_user(buf, rx_buf, count))
ret = -EFAULT;
else
ret = count;
return ret;
}
static struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
};
static int my_probe(struct platform_device *pdev)
{
struct net_device *dev = dev_get_by_name(&init_net, "eth0");
struct sk_buff *skb;
struct scatterlist sg;
int i, len;
if (!dev) {
pr_err("Failed to get eth0 device\n");
return -ENODEV;
}
skb = netdev_alloc_skb(dev, BUF_SIZE, GFP_KERNEL);
if (!skb) {
pr_err("Failed to allocate skb\n");
return -ENOMEM;
}
skb_reserve(skb, NET_SKB_PAD);
skb_put(skb, BUF_SIZE);
sg_init_one(&sg, skb->data, skb->len);
if (dma_map_sg(&pdev->dev, &sg, 1, DMA_FROM_DEVICE) != 1) {
pr_err("Failed to map SG to DMA buffer\n");
return -ENOMEM;
}
rx_buf = dma_alloc_coherent(&pdev->dev, BUF_SIZE, &rx_buf_dma, GFP_KERNEL);
if (!rx_buf) {
pr_err("Failed to allocate DMA buffer\n");
return -ENOMEM;
}
len = skb->len;
for (i = 0; i < len; i += skb_tailroom(skb)) {
skb_reset_tail_pointer(skb);
skb_set_tail_pointer(skb, skb->len);
sg_init_one(&sg, skb->data, skb_tailroom(skb));
dma_sync_sg_for_cpu(&pdev->dev, &sg, 1, DMA_FROM_DEVICE);
memcpy(rx_buf + i, skb->data, skb_tailroom(skb));
dma_sync_sg_for_device(&pdev->dev, &sg, 1, DMA_FROM_DEVICE);
}
netdev_rx(skb);
misc_register(&my_misc_device);
return 0;
}
static int my_remove(struct platform_device *pdev)
{
misc_deregister(&my_misc_device);
dma_free_coherent(&pdev->dev, BUF_SIZE, rx_buf, rx_buf_dma);
return 0;
}
static struct platform_driver my_driver = {
.driver = {
.name = "my_driver",
},
.probe = my_probe,
.remove = my_remove,
};
static int __init my_init(void)
{
my_misc_device.minor = MISC_DYNAMIC_MINOR;
my_misc_device.name = DEV_NAME;
my_misc_device.fops = &my_fops;
return platform_driver_register(&my_driver);
}
static void __exit my_exit(void)
{
platform_driver_unregister(&my_driver);
}
module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");
```
以上代码仅供参考,实际使用时需要根据具体需求进行修改和优化。
阅读全文