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

时间:2014-07-29 10:50:01

标签: linux kernel usb

我正在编写Linux内核模块,使用书籍u-blox NEO-7通过USB读取GPS设备(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"来解决问题。但我想避免这种情况。即通过分配一个新的" struct urb"对于每个通过usb_alloc_urb(...)的读取请求(通常在探测USB设备时分配一次)。

我的代码遵循Greg Kroah-Hartman的USB skeleton driver,他也重用了" struct urb"针对不同的阅读要求。

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

完整的代码可以在pastebin找到。以下是read方法和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);
}

1 个答案:

答案 0 :(得分:1)

现在,我为每个读取请求分配一个新的struct urb。这可以避免在调用应用程序取消活动读取请求后出现问题({1}}。分配的结构在完整的处理程序中被释放。

我优化代码时会回到LKML。目前,可以为每个单个读取请求分配一个新的struct urb。内核模块的完整代码位于pastebin

struct urb