简体   繁体   English

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

[英]Linux kernel module to read out GPS device via USB

I'm writing a Linux kernel module to read out a GPS device (a u-blox NEO-7 ) via USB by using the book Linux Device Drivers . 我正在编写一个Linux内核模块,通过USB使用Linux设备驱动程序读取GPS设备( u-blox NEO-7 )。

I already can probe and read out data from the device successfully. 我已经可以成功探测并读出设备中的数据。 But, there is a problem when reading the device with multiple applications simultaneously (I used "cat /dev/ublox" to read indefinitely). 但是,同时读取具有多个应用程序的设备时出现问题(我使用“cat / dev / ublox”无限期读取)。 When the active/reading applications is cancelled via "Ctrl + C", the next reading attempt from the other application fails (exactly method call usb_submit_urb(...) returns -EINVAL ). 当通过“Ctrl + C”取消活动/读取应用程序时,来自另一个应用程序的下一次读取尝试失败(确切的方法调用usb_submit_urb(...)返回-EINVAL )。

I use following ideas for my implementation: 我对我的实现使用以下想法:

  • The kernel module methods should be re-entrant. 内核模块方法应该是可重入的。 Therefore, I use a mutex to protect critical sections. 因此,我使用互斥锁来保护关键部分。 Eg allowing only one reader simultaneously. 例如,同时只允许一个阅读器。
  • To safe ressources, I reuse the struct urb for different reading requests (see an explanation ) 为了安全的资源,我将struct urb重用于不同的阅读请求(参见解释
  • Device-specific data like USB endpoint address and so on is held in a device-specific struct called ublox_device . 特定于设备的数据(如USB端点地址等)保存在名为ublox_device 的特定设备的结构中
  • After submitting the USB read request, the calling process is sent to sleep until the asynchronous complete handler is called. 提交USB读取请求后,调用进程将进入休眠状态,直到调用异步完成处理程序。

I verified that the ideas are implemented correctly: I have run two instances of "cat /dev/ublox" simultaneously and I got the correct output (only one instance accessed the critical read section at a time). 我验证了这些想法是否正确实现:我同时运行了两个“cat / dev / ublox”实例,并得到了正确的输出(一次只有一个实例访问了关键读取部分)。 And also reusing the "struct urb" is working. 并且重用“struct urb”正在起作用。 Both instances read out data alternatively. 两个实例都交替读出数据。

The problem only occurs if the currently active instance is cancelled via "Ctrl + C". 如果通过“Ctrl + C”取消当前活动的实例,则只会出现此问题。 I can solve the problem by not reusing the "struct urb" but I would like to avoid that. 我可以通过不重用“struct urb”来解决问题,但我想避免这种情况。 Ie by allocating a new "struct urb" for each read request via usb_alloc_urb(...) (usually it is allocated once when probing the USB device). 即通过usb_alloc_urb(...)为每个读取请求分配一个新的“struct urb”(通常在探测USB设备时分配一次)。

My code follows the USB skeleton driver from Greg Kroah-Hartman who also reuse the "struct urb" for different reading requests. 我的代码遵循Greg Kroah-Hartman的USB骨架驱动程序 ,他也为不同的阅读请求重用“struct urb”。

Maybe someone has a clue what's going wrong here. 也许有人知道这里出了什么问题。

The complete code can be found on pastebin . 完整的代码可以在pastebin上找到。 Here is a small excerpt of the read method and the USB request complete handler. 以下是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);
}

Now, I allocate a new struct urb for each read request. 现在,我为每个读取请求分配一个新的struct urb This avoids the problem with the messed up struct urb after an active read request is cancelled by the calling application. 这可以避免在调用应用程序取消活动读取请求后出现struct urb的问题。 The allocated struct is freed in the complete handler. 已分配的结构在完整的处理程序中释放。

I will come back to LKML when I optimize my code. 我优化代码时会回到LKML For now, it is okay to allocate a new struct urb for each single read request. 现在,可以为每个单个读取请求分配一个新的struct urb The complete code of the kernel module is on pastebin . 内核模块的完整代码在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);
    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM