深入Linux USB框架:剖析硬件驱动的核心部分

深入Linux USB框架:剖析硬件驱动的核心部分

1. 简介

Linux USB框架是Linux操作系统中负责处理USB设备的一个框架。它提供了一种标准且简单的接口,使得开发人员可以轻松地编写USB设备驱动程序,并与操作系统进行交互。本文将深入探讨Linux USB框架的核心部分,并解析硬件驱动的关键点。

2. USB驱动程序的注册

2.1 USB设备初始化

在开始编写USB驱动程序之前,需要对USB设备进行初始化。这涉及到在系统中注册USB设备。注册USB设备的过程可以通过下面的代码来演示:

struct usb_device_id my_usb_table[] = {

{ USB_DEVICE(0x1234, 0x5678) },

{ } /* Terminating entry */

};

MODULE_DEVICE_TABLE(usb, my_usb_table);

static struct usb_driver my_usb_driver = {

.name = "my_usb_driver",

.probe = my_usb_probe,

.disconnect = my_usb_disconnect,

.id_table = my_usb_table,

};

module_usb_driver(my_usb_driver);

在上述代码中,首先定义了一个usb_device_id结构体数组my_usb_table,用来描述支持的USB设备的Vendor ID和Product ID。

然后,通过MODULE_DEVICE_TABLE(usb, my_usb_table)宏定义,将my_usb_table注册到Linux内核的设备表中。

接下来,定义了一个usb_driver结构体my_usb_driver,其中包含了驱动程序的一些相关信息,如驱动程序名称、驱动程序的初始化函数probe和断开连接函数disconnect

最后,通过module_usb_driver(my_usb_driver)函数将驱动程序注册到Linux内核。

2.2 USB驱动程序的初始化函数

USB驱动程序的初始化函数在驱动程序被加载时被调用。在这个函数中,可以进行一些必要的设置和初始化工作。下面是一个示例的初始化函数:

static int my_usb_probe(struct usb_interface *interface, const struct usb_device_id *id)

{

// 获取相关设备信息

struct usb_device *udev = interface_to_usbdev(interface);

int retval;

// 打印设备信息

dev_info(&interface->dev, "USB device detected\n");

// 设置USB设备操作

interface->driver_data = devm_kzalloc(&interface->dev, sizeof(struct my_usb), GFP_KERNEL);

if (!interface->driver_data) {

dev_err(&interface→dev, "Memory allocation failed\n");

return -ENOMEM;

}

// ...

return 0;

}

在上述代码中,首先通过interface_to_usbdev函数将usb_interface结构体转换为usb_device结构体,以获取相关的设备信息。

然后,打印设备信息,以确认USB设备已被检测到。

接下来,通过devm_kzalloc函数分配内存,并将其保存在usb_interface结构体的driver_data字段中。这里的示例是用来保存使用的自定义结构体my_usb

最后,通过返回0来表示设备的初始化成功。

3. USB传输

3.1 USB传输数据的流程

在USB驱动程序中,为实现数据的传输,需要使用到Linux USB框架提供的一些函数。下面是USB传输数据的一个基本流程:

1. 通过usb_bulk_msg函数实现批量传输数据。

2. 通过usb_control_msg函数实现控制传输数据。

3. 通过usb_interrupt_msg函数实现中断传输数据。

3.2 批量传输数据示例

static int my_usb_send(struct usb_device *udev, void *data, int size)

{

struct usb_host_endpoint *ep;

struct urb *urb;

int retval;

// 获取发送数据的端点

ep = usb_sndbulkpipe(udev, EP_OUT);

// 分配USB请求块

urb = usb_alloc_urb(0, GFP_KERNEL);

if (!urb)

return -ENOMEM;

// 初始化USB请求块

usb_fill_bulk_urb(urb, udev, ep, data, size, my_usb_send_callback, NULL);

// 设置传输的超时时间

urb->timeout = 5000;

// 提交USB请求块

retval = usb_submit_urb(urb, GFP_KERNEL);

if (retval) {

dev_err(&interface->dev, "Failed to submit URB: %d\n", retval);

goto error;

}

// 等待传输完成

retval = usb_wait_for_completion_timeout(&urb->kref, urb->timeout);

if (retval == 0) {

dev_err(&interface->dev, "Transfer timed out\n");

usb_kill_urb(urb);

}

// 检查传输结果

if (urb->status) {

dev_err(&interface->dev, "Transfer failed with status: %d\n", urb->status);

retval = urb->status;

}

// 释放USB请求块

usb_free_urb(urb);

return retval;

error:

usb_free_urb(urb);

return retval;

}

在上述代码中,首先通过usb_sndbulkpipe函数获取发送数据的批量端点。

然后,通过usb_alloc_urb函数分配USB请求块,并使用usb_fill_bulk_urb函数初始化请求块。

接下来,设置传输的超时时间,并提交请求块通过usb_submit_urb函数执行传输操作。

然后,通过usb_wait_for_completion_timeout函数等待传输完成。

最后,通过检查传输结果和释放请求块的方式来结束传输操作。

4. 总结

本文深入探讨了Linux USB框架的核心部分,并剖析了硬件驱动中的关键点。我们了解了USB驱动程序的注册过程,以及USB传输数据的流程和实现方法。了解了这些核心知识后,我们可以更加深入地理解Linux USB框架,并能够编写高效稳定的USB驱动程序。

操作系统标签