Linux内核模块通过USB读取GPS设备

标签 linux kernel usb

我正在编写一个 Linux 内核模块,通过 USB 读出一个 GPS 设备(一个 u-blox NEO-7 ),使用这本书 Linux Device Drivers .

我已经可以成功探测和读取设备中的数据了。但是,同时读取具有多个应用程序的设备时会出现问题(我使用“cat/dev/ublox”无限读取)。当通过“Ctrl + C”取消事件/阅读应用程序时,其他应用程序的下一次阅读尝试失败(确切地说方法调用 usb_submit_urb(...) 返回 -EINVAL).

我在实现中使用了以下想法:

  • 内核模块方法应该是可重入的。因此,我使用互斥锁来保护临界区。例如。只允许一名读者同时阅读。
  • 为了安全资源,我重新使用了 struct urb针对不同的阅读请求(参见explanation)
  • 设备特定的数据(如 USB 端点地址等)保存在名为 ublox_device设备特定的结构中。
  • 提交USB读取请求后,调用进程进入休眠状态,直到调用异步完成处理程序。

我验证了这些想法是否正确实现:我同时运行了“cat/dev/ublox”的两个实例并且我得到了正确的输出(一次只有一个实例访问了关键读取部分)。并且重用“struct urb”也在起作用。两个实例交替读出数据。

仅当通过“Ctrl + C”取消当前事件的实例时才会出现此问题。我可以通过不重用“struct urb”来解决问题,但我想避免这种情况。 IE。通过 usb_alloc_urb(...) 为每个读取请求分配一个新的“struct urb” (通常在探测USB设备时分配一次)。

我的代码遵循 USB skeleton driver来自 Greg Kroah-Hartman,他还针对不同的阅读请求重用了“struct urb”。

也许有人知道这里出了什么问题。

完整代码可以在pastebin上找到.这是读取方法和 USB 请求完成处理程序的一小段摘录。

static ssize_t ublox_read(struct file *file, char *buffer, size_t count, loff_t *pos)
{
        struct ublox_device *ublox_device = file->private_data;
        ...
        return_value = mutex_lock_interruptible(&ublox_device->bulk_in_mutex);
        if (return_value < 0)
                return -EINTR;
        ...
retry:
        usb_fill_bulk_urb(...);

        ublox_device->read_in_progress = 1;

        /* Next call fails if active application is cancelled via "Ctrl + C" */   
        return_value = usb_submit_urb(ublox_device->bulk_in_urb, GFP_KERNEL);
        if (return_value) {
                printk(KERN_ERR "usb_submit_urb(...) failed!\n");
                ublox_device->read_in_progress = 0;
                goto exit;
        }

        /* Go to sleep until read operation has finished */
        return_value = wait_event_interruptible(ublox_device->bulk_in_wait_queue, (!ublox_device->read_in_progress));
        if (return_value < 0)
                goto exit;
        ...
exit:
        mutex_unlock(&ublox_device->bulk_in_mutex);
        return return_value;
}

static void ublox_read_bulk_callback(struct urb *urb)
{
        struct ublox_device *ublox_device = urb->context;
        int status = urb->status;

        /* Evaluate status... */
        ...
        ublox_device->transferred_bytes = urb->actual_length;
        ublox_device->read_in_progress = 0;

        wake_up_interruptible(&ublox_device->bulk_in_wait_queue);
}

最佳答案

现在,我为每个读取请求分配一个新的 struct urb。这避免了在调用应用程序取消事件读取请求后出现困惑的 struct urb 问题。分配的结构在完整的处理程序中被释放。

我会回来LKML当我优化我的代码时。现在,可以为每个读取请求分配一个新的 struct urb。内核模块的完整代码在pastebin上.

static ssize_t ublox_read(struct file *file, char *buffer, size_t count, loff_t *pos)
{
    struct ublox_device *ublox_device = file->private_data;
    ...
retry:
    ublox_device->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); 
    ...
    usb_fill_bulk_urb(...);
    ...
    return_value = usb_submit_urb(ublox_device->bulk_in_urb, GFP_KERNEL);
    ...
}

static void ublox_read_bulk_callback(struct urb *urb)
{
    struct ublox_device *ublox_device = urb->context;
    ...
    usb_free_urb(ublox_device->bulk_in_urb);
    ...
}

关于Linux内核模块通过USB读取GPS设备,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25019058/

相关文章:

linux - 如何判断进程是否结束?

windows - 基于操作系统的C++条件编译

c++ - g++ 生成依赖文件缺少用户定义的 header

java - 如何通过 USB 进行通信(手机到 PC)?

c - 解释 USB 操纵杆轴

keyboard - USB接口(interface)条码扫描器

Linux bash 脚本 : share variable among terminal windows

c - 解释一下下面的程序是如何工作的?

linux - Linux 上物理内存 0x8000 (32Kb) 到 0x10000 (1Mb) 是什么

linux - "soft/hard nofile"在 Linux 上意味着什么